@@ -62,6 +62,8 @@ def __init__(
62
62
filter_dirs = None , # type: Optional[List[Text]]
63
63
exclude_dirs = None , # type: Optional[List[Text]]
64
64
max_depth = None , # type: Optional[int]
65
+ filter_glob = None , # type: Optional[List[Text]]
66
+ exclude_glob = None , # type: Optional[List[Text]]
65
67
):
66
68
# type: (...) -> None
67
69
"""Create a new `Walker` instance.
@@ -85,11 +87,22 @@ def __init__(
85
87
any of these patterns will be removed from the walk.
86
88
filter_dirs (list, optional): A list of patterns that will be used
87
89
to match directories paths. The walk will only open directories
88
- that match at least one of these patterns.
90
+ that match at least one of these patterns. Directories will
91
+ only be returned if the final component matches one of the
92
+ patterns.
89
93
exclude_dirs (list, optional): A list of patterns that will be
90
94
used to filter out directories from the walk. e.g.
91
- ``['*.svn', '*.git']``.
95
+ ``['*.svn', '*.git']``. Directories matching any of these
96
+ patterns will be removed from the walk.
92
97
max_depth (int, optional): Maximum directory depth to walk.
98
+ filter_glob (list, optional): If supplied, this parameter
99
+ should be a list of path patterns e.g. ``["foo/**/*.py"]``.
100
+ Resources will only be returned if their global path or
101
+ an extension of it matches one of the patterns.
102
+ exclude_glob (list, optional): If supplied, this parameter
103
+ should be a list of path patterns e.g. ``["foo/**/*.py"]``.
104
+ Resources will not be returned if their global path or
105
+ an extension of it matches one of the patterns.
93
106
94
107
"""
95
108
if search not in ("breadth" , "depth" ):
@@ -109,6 +122,8 @@ def __init__(
109
122
self .exclude = exclude
110
123
self .filter_dirs = filter_dirs
111
124
self .exclude_dirs = exclude_dirs
125
+ self .filter_glob = filter_glob
126
+ self .exclude_glob = exclude_glob
112
127
self .max_depth = max_depth
113
128
super (Walker , self ).__init__ ()
114
129
@@ -180,6 +195,8 @@ def __repr__(self):
180
195
filter_dirs = (self .filter_dirs , None ),
181
196
exclude_dirs = (self .exclude_dirs , None ),
182
197
max_depth = (self .max_depth , None ),
198
+ filter_glob = (self .filter_glob , None ),
199
+ exclude_glob = (self .exclude_glob , None ),
183
200
)
184
201
185
202
def _iter_walk (
@@ -198,9 +215,18 @@ def _iter_walk(
198
215
def _check_open_dir (self , fs , path , info ):
199
216
# type: (FS, Text, Info) -> bool
200
217
"""Check if a directory should be considered in the walk."""
218
+ full_path = ("" if path == "/" else path ) + "/" + info .name
201
219
if self .exclude_dirs is not None and fs .match (self .exclude_dirs , info .name ):
202
220
return False
203
- if self .filter_dirs is not None and not fs .match (self .filter_dirs , info .name ):
221
+ if self .exclude_glob is not None and fs .match (self .exclude_glob , full_path ):
222
+ return False
223
+ if self .filter_dirs is not None and not fs .match (
224
+ self .filter_dirs , info .name , accept_prefix = True
225
+ ):
226
+ return False
227
+ if self .filter_glob is not None and not fs .match (
228
+ self .filter_glob , full_path , accept_prefix = True
229
+ ):
204
230
return False
205
231
return self .check_open_dir (fs , path , info )
206
232
@@ -247,6 +273,26 @@ def check_scan_dir(self, fs, path, info):
247
273
"""
248
274
return True
249
275
276
+ def _check_file (self , fs , dir_path , info ):
277
+ # type: (FS, Text, Info) -> bool
278
+ """Check if a filename should be included."""
279
+ # Weird check required for backwards compatibility,
280
+ # when _check_file did not exist.
281
+ if Walker ._check_file == type (self )._check_file :
282
+ if self .exclude is not None and fs .match (self .exclude , info .name ):
283
+ return False
284
+ if self .exclude_glob is not None and fs .match (
285
+ self .exclude_glob , dir_path + "/" + info .name
286
+ ):
287
+ return False
288
+ if self .filter is not None and not fs .match (self .filter , info .name ):
289
+ return False
290
+ if self .filter_glob is not None and not fs .match (
291
+ self .filter_glob , dir_path + "/" + info .name , accept_prefix = True
292
+ ):
293
+ return False
294
+ return self .check_file (fs , info )
295
+
250
296
def check_file (self , fs , info ):
251
297
# type: (FS, Info) -> bool
252
298
"""Check if a filename should be included.
@@ -261,9 +307,7 @@ def check_file(self, fs, info):
261
307
bool: `True` if the file should be included.
262
308
263
309
"""
264
- if self .exclude is not None and fs .match (self .exclude , info .name ):
265
- return False
266
- return fs .match (self .filter , info .name )
310
+ return True
267
311
268
312
def _scan (
269
313
self ,
@@ -420,7 +464,7 @@ def _walk_breadth(
420
464
_calculate_depth = self ._calculate_depth
421
465
_check_open_dir = self ._check_open_dir
422
466
_check_scan_dir = self ._check_scan_dir
423
- _check_file = self .check_file
467
+ _check_file = self ._check_file
424
468
425
469
depth = _calculate_depth (path )
426
470
@@ -434,7 +478,7 @@ def _walk_breadth(
434
478
if _check_scan_dir (fs , dir_path , info , _depth ):
435
479
push (_combine (dir_path , info .name ))
436
480
else :
437
- if _check_file (fs , info ):
481
+ if _check_file (fs , dir_path , info ):
438
482
yield dir_path , info # Found a file
439
483
yield dir_path , None # End of directory
440
484
@@ -453,7 +497,7 @@ def _walk_depth(
453
497
_calculate_depth = self ._calculate_depth
454
498
_check_open_dir = self ._check_open_dir
455
499
_check_scan_dir = self ._check_scan_dir
456
- _check_file = self .check_file
500
+ _check_file = self ._check_file
457
501
depth = _calculate_depth (path )
458
502
459
503
stack = [
@@ -485,7 +529,7 @@ def _walk_depth(
485
529
else :
486
530
yield dir_path , info
487
531
else :
488
- if _check_file (fs , info ):
532
+ if _check_file (fs , dir_path , info ):
489
533
yield dir_path , info
490
534
491
535
0 commit comments