gh-101566: Sync with zipp 3.14. (GH-102018)

This commit is contained in:
Jason R. Coombs 2023-02-20 16:01:58 -05:00 committed by GitHub
parent 84181c1404
commit 36854bbb24
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 215 additions and 56 deletions

View file

@ -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)