Skip to content

Commit

Permalink
pythongh-122903: Honor directories in zipfile.Path.glob. (python#122908)
Browse files Browse the repository at this point in the history
  • Loading branch information
jaraco authored Aug 12, 2024
1 parent 9cd0326 commit 6aa35f3
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 9 deletions.
29 changes: 24 additions & 5 deletions Lib/test/test_zipfile/_path/test_path.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ def zipfile_ondisk(self, alpharep):
def test_iterdir_and_types(self, alpharep):
root = zipfile.Path(alpharep)
assert root.is_dir()
a, k, b, g, j = root.iterdir()
a, n, b, g, j = root.iterdir()
assert a.is_file()
assert b.is_dir()
assert g.is_dir()
Expand All @@ -121,7 +121,7 @@ def test_is_file_missing(self, alpharep):
@pass_alpharep
def test_iterdir_on_file(self, alpharep):
root = zipfile.Path(alpharep)
a, k, b, g, j = root.iterdir()
a, n, b, g, j = root.iterdir()
with self.assertRaises(ValueError):
a.iterdir()

Expand All @@ -136,7 +136,7 @@ def test_subdir_is_dir(self, alpharep):
@pass_alpharep
def test_open(self, alpharep):
root = zipfile.Path(alpharep)
a, k, b, g, j = root.iterdir()
a, n, b, g, j = root.iterdir()
with a.open(encoding="utf-8") as strm:
data = strm.read()
self.assertEqual(data, "content of a")
Expand Down Expand Up @@ -240,7 +240,7 @@ def test_open_missing_directory(self, alpharep):
@pass_alpharep
def test_read(self, alpharep):
root = zipfile.Path(alpharep)
a, k, b, g, j = root.iterdir()
a, n, b, g, j = root.iterdir()
assert a.read_text(encoding="utf-8") == "content of a"
# Also check positional encoding arg (gh-101144).
assert a.read_text("utf-8") == "content of a"
Expand Down Expand Up @@ -306,7 +306,7 @@ def test_mutability(self, alpharep):
reflect that change.
"""
root = zipfile.Path(alpharep)
a, k, b, g, j = root.iterdir()
a, n, b, g, j = root.iterdir()
alpharep.writestr('foo.txt', 'foo')
alpharep.writestr('bar/baz.txt', 'baz')
assert any(child.name == 'foo.txt' for child in root.iterdir())
Expand Down Expand Up @@ -475,6 +475,18 @@ def test_glob_recursive(self, alpharep):

assert list(root.glob("**/*.txt")) == list(root.rglob("*.txt"))

@pass_alpharep
def test_glob_dirs(self, alpharep):
root = zipfile.Path(alpharep)
assert list(root.glob('b')) == [zipfile.Path(alpharep, "b/")]
assert list(root.glob('b*')) == [zipfile.Path(alpharep, "b/")]

@pass_alpharep
def test_glob_subdir(self, alpharep):
root = zipfile.Path(alpharep)
assert list(root.glob('g/h')) == [zipfile.Path(alpharep, "g/h/")]
assert list(root.glob('g*/h*')) == [zipfile.Path(alpharep, "g/h/")]

@pass_alpharep
def test_glob_subdirs(self, alpharep):
root = zipfile.Path(alpharep)
Expand Down Expand Up @@ -594,3 +606,10 @@ def test_malformed_paths(self):
'two-slash.txt',
'parent.txt',
]

@pass_alpharep
def test_interface(self, alpharep):
from importlib.resources.abc import Traversable

zf = zipfile.Path(alpharep)
assert isinstance(zf, Traversable)
8 changes: 5 additions & 3 deletions Lib/zipfile/_path/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,10 @@ def _extract_text_encoding(encoding=None, *args, **kwargs):

class Path:
"""
A pathlib-compatible interface for zip files.
A :class:`importlib.resources.abc.Traversable` interface for zip files.
Implements many of the features users enjoy from
:class:`pathlib.Path`.
Consider a zip file with this structure::
Expand Down Expand Up @@ -466,8 +469,7 @@ def glob(self, pattern):
prefix = re.escape(self.at)
tr = Translator(seps='/')
matches = re.compile(prefix + tr.translate(pattern)).fullmatch
names = (data.filename for data in self.root.filelist)
return map(self._next, filter(matches, names))
return map(self._next, filter(matches, self.root.namelist()))

def rglob(self, pattern):
return self.glob(f'**/{pattern}')
Expand Down
10 changes: 9 additions & 1 deletion Lib/zipfile/_path/glob.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def translate(self, pattern):
"""
Given a glob pattern, produce a regex that matches it.
"""
return self.extend(self.translate_core(pattern))
return self.extend(self.match_dirs(self.translate_core(pattern)))

def extend(self, pattern):
r"""
Expand All @@ -41,6 +41,14 @@ def extend(self, pattern):
"""
return rf'(?s:{pattern})\Z'

def match_dirs(self, pattern):
"""
Ensure that zipfile.Path directory names are matched.
zipfile.Path directory names always end in a slash.
"""
return rf'{pattern}[/]?'

def translate_core(self, pattern):
r"""
Given a glob pattern, produce a regex that matches it.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
``zipfile.Path.glob`` now correctly matches directories instead of
silently omitting them.

0 comments on commit 6aa35f3

Please sign in to comment.