mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-08-22 06:13:25 -07:00
Update zipp==3.20.2
This commit is contained in:
parent
09049a06a1
commit
795f6ea469
4 changed files with 68 additions and 70 deletions
|
@ -1,3 +1,12 @@
|
||||||
|
"""
|
||||||
|
A Path-like interface for zipfiles.
|
||||||
|
|
||||||
|
This codebase is shared between zipfile.Path in the stdlib
|
||||||
|
and zipp in PyPI. See
|
||||||
|
https://github.com/python/importlib_metadata/wiki/Development-Methodology
|
||||||
|
for more detail.
|
||||||
|
"""
|
||||||
|
|
||||||
import io
|
import io
|
||||||
import posixpath
|
import posixpath
|
||||||
import zipfile
|
import zipfile
|
||||||
|
@ -37,7 +46,7 @@ def _parents(path):
|
||||||
def _ancestry(path):
|
def _ancestry(path):
|
||||||
"""
|
"""
|
||||||
Given a path with elements separated by
|
Given a path with elements separated by
|
||||||
posixpath.sep, generate all elements of that path
|
posixpath.sep, generate all elements of that path.
|
||||||
|
|
||||||
>>> list(_ancestry('b/d'))
|
>>> list(_ancestry('b/d'))
|
||||||
['b/d', 'b']
|
['b/d', 'b']
|
||||||
|
@ -49,9 +58,14 @@ def _ancestry(path):
|
||||||
['b']
|
['b']
|
||||||
>>> list(_ancestry(''))
|
>>> list(_ancestry(''))
|
||||||
[]
|
[]
|
||||||
|
|
||||||
|
Multiple separators are treated like a single.
|
||||||
|
|
||||||
|
>>> list(_ancestry('//b//d///f//'))
|
||||||
|
['//b//d///f', '//b//d', '//b']
|
||||||
"""
|
"""
|
||||||
path = path.rstrip(posixpath.sep)
|
path = path.rstrip(posixpath.sep)
|
||||||
while path and path != posixpath.sep:
|
while path.rstrip(posixpath.sep):
|
||||||
yield path
|
yield path
|
||||||
path, tail = posixpath.split(path)
|
path, tail = posixpath.split(path)
|
||||||
|
|
||||||
|
@ -86,69 +100,7 @@ class InitializedState:
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class SanitizedNames:
|
class CompleteDirs(InitializedState, zipfile.ZipFile):
|
||||||
"""
|
|
||||||
ZipFile mix-in to ensure names are sanitized.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def namelist(self):
|
|
||||||
return list(map(self._sanitize, super().namelist()))
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _sanitize(name):
|
|
||||||
r"""
|
|
||||||
Ensure a relative path with posix separators and no dot names.
|
|
||||||
|
|
||||||
Modeled after
|
|
||||||
https://github.com/python/cpython/blob/bcc1be39cb1d04ad9fc0bd1b9193d3972835a57c/Lib/zipfile/__init__.py#L1799-L1813
|
|
||||||
but provides consistent cross-platform behavior.
|
|
||||||
|
|
||||||
>>> san = SanitizedNames._sanitize
|
|
||||||
>>> san('/foo/bar')
|
|
||||||
'foo/bar'
|
|
||||||
>>> san('//foo.txt')
|
|
||||||
'foo.txt'
|
|
||||||
>>> san('foo/.././bar.txt')
|
|
||||||
'foo/bar.txt'
|
|
||||||
>>> san('foo../.bar.txt')
|
|
||||||
'foo../.bar.txt'
|
|
||||||
>>> san('\\foo\\bar.txt')
|
|
||||||
'foo/bar.txt'
|
|
||||||
>>> san('D:\\foo.txt')
|
|
||||||
'D/foo.txt'
|
|
||||||
>>> san('\\\\server\\share\\file.txt')
|
|
||||||
'server/share/file.txt'
|
|
||||||
>>> san('\\\\?\\GLOBALROOT\\Volume3')
|
|
||||||
'?/GLOBALROOT/Volume3'
|
|
||||||
>>> san('\\\\.\\PhysicalDrive1\\root')
|
|
||||||
'PhysicalDrive1/root'
|
|
||||||
|
|
||||||
Retain any trailing slash.
|
|
||||||
>>> san('abc/')
|
|
||||||
'abc/'
|
|
||||||
|
|
||||||
Raises a ValueError if the result is empty.
|
|
||||||
>>> san('../..')
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
ValueError: Empty filename
|
|
||||||
"""
|
|
||||||
|
|
||||||
def allowed(part):
|
|
||||||
return part and part not in {'..', '.'}
|
|
||||||
|
|
||||||
# Remove the drive letter.
|
|
||||||
# Don't use ntpath.splitdrive, because that also strips UNC paths
|
|
||||||
bare = re.sub('^([A-Z]):', r'\1', name, flags=re.IGNORECASE)
|
|
||||||
clean = bare.replace('\\', '/')
|
|
||||||
parts = clean.split('/')
|
|
||||||
joined = '/'.join(filter(allowed, parts))
|
|
||||||
if not joined:
|
|
||||||
raise ValueError("Empty filename")
|
|
||||||
return joined + '/' * name.endswith('/')
|
|
||||||
|
|
||||||
|
|
||||||
class CompleteDirs(InitializedState, SanitizedNames, zipfile.ZipFile):
|
|
||||||
"""
|
"""
|
||||||
A ZipFile subclass that ensures that implied directories
|
A ZipFile subclass that ensures that implied directories
|
||||||
are always included in the namelist.
|
are always included in the namelist.
|
||||||
|
@ -329,7 +281,7 @@ class Path:
|
||||||
>>> str(path.parent)
|
>>> str(path.parent)
|
||||||
'mem'
|
'mem'
|
||||||
|
|
||||||
If the zipfile has no filename, such attributes are not
|
If the zipfile has no filename, such attributes are not
|
||||||
valid and accessing them will raise an Exception.
|
valid and accessing them will raise an Exception.
|
||||||
|
|
||||||
>>> zf.filename = None
|
>>> zf.filename = None
|
||||||
|
@ -470,8 +422,7 @@ class Path:
|
||||||
prefix = re.escape(self.at)
|
prefix = re.escape(self.at)
|
||||||
tr = Translator(seps='/')
|
tr = Translator(seps='/')
|
||||||
matches = re.compile(prefix + tr.translate(pattern)).fullmatch
|
matches = re.compile(prefix + tr.translate(pattern)).fullmatch
|
||||||
names = (data.filename for data in self.root.filelist)
|
return map(self._next, filter(matches, self.root.namelist()))
|
||||||
return map(self._next, filter(matches, names))
|
|
||||||
|
|
||||||
def rglob(self, pattern):
|
def rglob(self, pattern):
|
||||||
return self.glob(f'**/{pattern}')
|
return self.glob(f'**/{pattern}')
|
||||||
|
|
37
lib/zipp/compat/overlay.py
Normal file
37
lib/zipp/compat/overlay.py
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
"""
|
||||||
|
Expose zipp.Path as .zipfile.Path.
|
||||||
|
|
||||||
|
Includes everything else in ``zipfile`` to match future usage. Just
|
||||||
|
use:
|
||||||
|
|
||||||
|
>>> from zipp.compat.overlay import zipfile
|
||||||
|
|
||||||
|
in place of ``import zipfile``.
|
||||||
|
|
||||||
|
Relative imports are supported too.
|
||||||
|
|
||||||
|
>>> from zipp.compat.overlay.zipfile import ZipInfo
|
||||||
|
|
||||||
|
The ``zipfile`` object added to ``sys.modules`` needs to be
|
||||||
|
hashable (#126).
|
||||||
|
|
||||||
|
>>> _ = hash(sys.modules['zipp.compat.overlay.zipfile'])
|
||||||
|
"""
|
||||||
|
|
||||||
|
import importlib
|
||||||
|
import sys
|
||||||
|
import types
|
||||||
|
|
||||||
|
import zipp
|
||||||
|
|
||||||
|
|
||||||
|
class HashableNamespace(types.SimpleNamespace):
|
||||||
|
def __hash__(self):
|
||||||
|
return hash(tuple(vars(self)))
|
||||||
|
|
||||||
|
|
||||||
|
zipfile = HashableNamespace(**vars(importlib.import_module('zipfile')))
|
||||||
|
zipfile.Path = zipp.Path
|
||||||
|
zipfile._path = zipp
|
||||||
|
|
||||||
|
sys.modules[__name__ + '.zipfile'] = zipfile # type: ignore[assignment]
|
|
@ -7,5 +7,7 @@ def _text_encoding(encoding, stacklevel=2, /): # pragma: no cover
|
||||||
|
|
||||||
|
|
||||||
text_encoding = (
|
text_encoding = (
|
||||||
io.text_encoding if sys.version_info > (3, 10) else _text_encoding # type: ignore
|
io.text_encoding # type: ignore[unused-ignore, attr-defined]
|
||||||
|
if sys.version_info > (3, 10)
|
||||||
|
else _text_encoding
|
||||||
)
|
)
|
||||||
|
|
|
@ -28,7 +28,7 @@ class Translator:
|
||||||
"""
|
"""
|
||||||
Given a glob pattern, produce a regex that matches it.
|
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):
|
def extend(self, pattern):
|
||||||
r"""
|
r"""
|
||||||
|
@ -41,6 +41,14 @@ class Translator:
|
||||||
"""
|
"""
|
||||||
return rf'(?s:{pattern})\Z'
|
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):
|
def translate_core(self, pattern):
|
||||||
r"""
|
r"""
|
||||||
Given a glob pattern, produce a regex that matches it.
|
Given a glob pattern, produce a regex that matches it.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue