Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Teach zipp.Path some additional pathlib.Path methods. #85

Merged
merged 11 commits into from
Nov 25, 2022
38 changes: 38 additions & 0 deletions tests/test_zipp.py
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,44 @@ def test_root_unnamed(self, alpharep):
assert sub.name == "b"
assert sub.parent

@pass_alpharep
def test_match_and_glob(self, alpharep):
root = zipp.Path(alpharep)
assert not root.match("*.txt")

assert list(root.glob("b/c.*")) == [zipp.Path(alpharep, "b/c.txt")]

files = root.glob("**/*.txt")
assert all(each.match("*.txt") for each in files)

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

@pass_alpharep
def test_eq_hash(self, alpharep):
root = zipp.Path(alpharep)
assert root == zipp.Path(alpharep)

assert root != (root / "a.txt")
assert (root / "a.txt") == (root / "a.txt")

root = zipp.Path(alpharep)
assert root in {root}

@pass_alpharep
def test_is_symlink(self, alpharep):
"""
See python/cpython#82102 for symlink support beyond this object.
"""

root = zipp.Path(alpharep)
assert not root.is_symlink()

@pass_alpharep
def test_relative_to(self, alpharep):
root = zipp.Path(alpharep)
relative = root.joinpath("b", "c.txt").relative_to(root / "b")
assert relative == pathlib.Path("c.txt")

@pass_alpharep
def test_inheritance(self, alpharep):
cls = type('PathChild', (zipp.Path,), {})
Expand Down
50 changes: 50 additions & 0 deletions zipp/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import io
import os
import posixpath
import zipfile
import itertools
Expand Down Expand Up @@ -243,6 +244,14 @@ def __init__(self, root, at=""):
self.root = FastLookup.make(root)
self.at = at

def __eq__(self, other):
if self.__class__ is not other.__class__:
return NotImplemented
jaraco marked this conversation as resolved.
Show resolved Hide resolved
return (self.root, self.at) == (other.root, other.at)

def __hash__(self):
return hash((self.root, self.at))

def open(self, mode='r', *args, pwd=None, **kwargs):
"""
Open this entry as text or binary following the semantics
Expand Down Expand Up @@ -313,6 +322,47 @@ def iterdir(self):
subs = map(self._next, self.root.namelist())
return filter(self._is_child, subs)

def match(self, path_pattern):
return pathlib.Path(self.at).match(path_pattern)
jaraco marked this conversation as resolved.
Show resolved Hide resolved

def is_symlink(self):
return False # See #82102
jaraco marked this conversation as resolved.
Show resolved Hide resolved

@contextlib.contextmanager
def _scandir(self): # Needed for glob
yield self.iterdir()

def _make_child_relpath(self, relpath): # Needed for glob
return self / relpath

def glob(self, pattern):
if not pattern:
jaraco marked this conversation as resolved.
Show resolved Hide resolved
raise ValueError("Unacceptable pattern: {!r}".format(pattern))
path = pathlib.Path(self.at)
drv, root, pattern_parts = path._flavour.parse_parts((pattern,))
if drv or root:
raise NotImplementedError("Non-relative patterns are unsupported")
jaraco marked this conversation as resolved.
Show resolved Hide resolved
if pattern[-1] in (path._flavour.sep, path._flavour.altsep):
pattern_parts.append('')
selector = pathlib._make_selector(tuple(pattern_parts), path._flavour)
for p in selector.select_from(self):
jaraco marked this conversation as resolved.
Show resolved Hide resolved
yield p
jaraco marked this conversation as resolved.
Show resolved Hide resolved

def rglob(self, pattern):
path = pathlib.Path(self.at)
drv, root, pattern_parts = path._flavour.parse_parts((pattern,))
if drv or root:
raise NotImplementedError("Non-relative patterns are unsupported")
if pattern and pattern[-1] in (path._flavour.sep, path._flavour.altsep):
pattern_parts.append('')
selector = pathlib._make_selector(("**",) + tuple(pattern_parts), path._flavour)
for p in selector.select_from(self):
yield p
jaraco marked this conversation as resolved.
Show resolved Hide resolved

def relative_to(self, *other, **kwargs):
other = (pathlib.Path(each.at) for each in other)
jaraco marked this conversation as resolved.
Show resolved Hide resolved
return pathlib.Path(self.at).relative_to(*other, **kwargs)
jaraco marked this conversation as resolved.
Show resolved Hide resolved

def __str__(self):
return posixpath.join(self.root.filename, self.at)

Expand Down