Skip to content

Commit 449580d

Browse files
author
atollk
committed
Added filter_glob and exclude_glob to fs.walk.Walker and related functions.
These extend the class by an option to include/exclude resources by their entire path, not just its last component. Unit tests will be added in a future commit.
1 parent deefe74 commit 449580d

File tree

2 files changed

+46
-7
lines changed

2 files changed

+46
-7
lines changed

fs/walk.py

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ def __init__(
6262
filter_dirs=None, # type: Optional[List[Text]]
6363
exclude_dirs=None, # type: Optional[List[Text]]
6464
max_depth=None, # type: Optional[int]
65+
filter_glob=None, # type: Optional[List[Text]]
66+
exclude_glob=None, # type: Optional[List[Text]]
6567
):
6668
# type: (...) -> None
6769
"""Create a new `Walker` instance.
@@ -85,11 +87,22 @@ def __init__(
8587
any of these patterns will be removed from the walk.
8688
filter_dirs (list, optional): A list of patterns that will be used
8789
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.
8993
exclude_dirs (list, optional): A list of patterns that will be
9094
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.
9297
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 patah
101+
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 only be returned if their global patah
105+
matches one of the patterns.
93106
94107
"""
95108
if search not in ("breadth", "depth"):
@@ -109,6 +122,8 @@ def __init__(
109122
self.exclude = exclude
110123
self.filter_dirs = filter_dirs
111124
self.exclude_dirs = exclude_dirs
125+
self.filter_glob = filter_glob
126+
self.exclude_glob = exclude_glob
112127
self.max_depth = max_depth
113128
super(Walker, self).__init__()
114129

@@ -180,6 +195,8 @@ def __repr__(self):
180195
filter_dirs=(self.filter_dirs, None),
181196
exclude_dirs=(self.exclude_dirs, None),
182197
max_depth=(self.max_depth, None),
198+
filter_glob=(self.filter_glob, None),
199+
exclude_glob=(self.exclude_glob, None),
183200
)
184201

185202
def _iter_walk(
@@ -200,8 +217,12 @@ def _check_open_dir(self, fs, path, info):
200217
"""Check if a directory should be considered in the walk."""
201218
if self.exclude_dirs is not None and fs.match(self.exclude_dirs, info.name):
202219
return False
220+
if self.exclude_glob is not None and fs.match(self.exclude_glob, path):
221+
return False
203222
if self.filter_dirs is not None and not fs.match(self.filter_dirs, info.name):
204223
return False
224+
if self.filter_glob is not None and not fs.match(self.filter_glob, path):
225+
return False
205226
return self.check_open_dir(fs, path, info)
206227

207228
def check_open_dir(self, fs, path, info):
@@ -247,6 +268,17 @@ def check_scan_dir(self, fs, path, info):
247268
"""
248269
return True
249270

271+
def _check_file(self, fs, info):
272+
# type: (FS, Info) -> bool
273+
"""Check if a filename should be included."""
274+
# Weird check required for backwards compatibility, when _check_file did not exist.
275+
if Walker._check_file == type(self)._check_file:
276+
if self.exclude is not None and fs.match(self.exclude, info.name):
277+
return False
278+
if self.filter is not None and not fs.match(self.filter, info.name):
279+
return False
280+
return self.check_file(fs, info)
281+
250282
def check_file(self, fs, info):
251283
# type: (FS, Info) -> bool
252284
"""Check if a filename should be included.
@@ -261,9 +293,7 @@ def check_file(self, fs, info):
261293
bool: `True` if the file should be included.
262294
263295
"""
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)
296+
return True
267297

268298
def _scan(
269299
self,
@@ -418,7 +448,7 @@ def _walk_breadth(
418448
_calculate_depth = self._calculate_depth
419449
_check_open_dir = self._check_open_dir
420450
_check_scan_dir = self._check_scan_dir
421-
_check_file = self.check_file
451+
_check_file = self._check_file
422452

423453
depth = _calculate_depth(path)
424454

@@ -451,7 +481,7 @@ def _walk_depth(
451481
_calculate_depth = self._calculate_depth
452482
_check_open_dir = self._check_open_dir
453483
_check_scan_dir = self._check_scan_dir
454-
_check_file = self.check_file
484+
_check_file = self._check_file
455485
depth = _calculate_depth(path)
456486

457487
stack = [

tests/test_walk.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,15 @@ class CustomizedMemoryFS(MemoryFS):
283283
self.assertEqual(sub_walker.walker_class, CustomWalker)
284284
six.assertCountEqual(self, ["/c", "/d"], sub_walker.files())
285285

286+
def test_check_file_overwrite(self):
287+
class CustomWalker(walk.Walker):
288+
def check_file(self, fs, info):
289+
return False
290+
291+
walker = CustomWalker()
292+
files = list(walker.files(self.fs))
293+
self.assertEqual(files, [])
294+
286295

287296
class TestInfo(TestBoundWalkerBase):
288297
def test_walk_info(self):

0 commit comments

Comments
 (0)