summaryrefslogtreecommitdiffstats
path: root/Lib/zipfile
diff options
context:
space:
mode:
authorJason R. Coombs <jaraco@jaraco.com>2023-02-20 21:01:58 (GMT)
committerGitHub <noreply@github.com>2023-02-20 21:01:58 (GMT)
commit36854bbb240e417c0df6f0014924fcc899388186 (patch)
treec0b3e543bac2a8507e09a4324acafae0d36ba7f4 /Lib/zipfile
parent84181c14040ed2befe7f1a55b4f560c80fa61154 (diff)
downloadcpython-36854bbb240e417c0df6f0014924fcc899388186.zip
cpython-36854bbb240e417c0df6f0014924fcc899388186.tar.gz
cpython-36854bbb240e417c0df6f0014924fcc899388186.tar.bz2
gh-101566: Sync with zipp 3.14. (GH-102018)
Diffstat (limited to 'Lib/zipfile')
-rw-r--r--Lib/zipfile/_path.py63
1 files changed, 60 insertions, 3 deletions
diff --git a/Lib/zipfile/_path.py b/Lib/zipfile/_path.py
index 7c7a6a0..c2c804e 100644
--- a/Lib/zipfile/_path.py
+++ b/Lib/zipfile/_path.py
@@ -4,6 +4,8 @@ import zipfile
import itertools
import contextlib
import pathlib
+import re
+import fnmatch
__all__ = ['Path']
@@ -93,7 +95,7 @@ class CompleteDirs(InitializedState, zipfile.ZipFile):
return _dedupe(_difference(as_dirs, names))
def namelist(self):
- names = super(CompleteDirs, self).namelist()
+ names = super().namelist()
return names + list(self._implied_dirs(names))
def _name_set(self):
@@ -109,6 +111,17 @@ class CompleteDirs(InitializedState, zipfile.ZipFile):
dir_match = name not in names and dirname in names
return dirname if dir_match else name
+ def getinfo(self, name):
+ """
+ Supplement getinfo for implied dirs.
+ """
+ try:
+ return super().getinfo(name)
+ except KeyError:
+ if not name.endswith('/') or name not in self._name_set():
+ raise
+ return zipfile.ZipInfo(filename=name)
+
@classmethod
def make(cls, source):
"""
@@ -138,13 +151,13 @@ class FastLookup(CompleteDirs):
def namelist(self):
with contextlib.suppress(AttributeError):
return self.__names
- self.__names = super(FastLookup, self).namelist()
+ self.__names = super().namelist()
return self.__names
def _name_set(self):
with contextlib.suppress(AttributeError):
return self.__lookup
- self.__lookup = super(FastLookup, self)._name_set()
+ self.__lookup = super()._name_set()
return self.__lookup
@@ -246,6 +259,18 @@ class Path:
self.root = FastLookup.make(root)
self.at = at
+ def __eq__(self, other):
+ """
+ >>> Path(zipfile.ZipFile(io.BytesIO(), 'w')) == 'foo'
+ False
+ """
+ if self.__class__ is not other.__class__:
+ return NotImplemented
+ 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
@@ -316,6 +341,38 @@ class Path:
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)
+
+ def is_symlink(self):
+ """
+ Return whether this path is a symlink. Always false (python/cpython#82102).
+ """
+ return False
+
+ def _descendants(self):
+ for child in self.iterdir():
+ yield child
+ if child.is_dir():
+ yield from child._descendants()
+
+ def glob(self, pattern):
+ if not pattern:
+ raise ValueError(f"Unacceptable pattern: {pattern!r}")
+
+ matches = re.compile(fnmatch.translate(pattern)).fullmatch
+ return (
+ child
+ for child in self._descendants()
+ if matches(str(child.relative_to(self)))
+ )
+
+ def rglob(self, pattern):
+ return self.glob(f'**/{pattern}')
+
+ def relative_to(self, other, *extra):
+ return posixpath.relpath(str(self), str(other.joinpath(*extra)))
+
def __str__(self):
return posixpath.join(self.root.filename, self.at)