mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-08-20 21:33:18 -07:00
Bump importlib-resources from 6.4.0 to 6.4.5 (#2394)
* Bump importlib-resources from 6.4.0 to 6.4.5 Bumps [importlib-resources](https://github.com/python/importlib_resources) from 6.4.0 to 6.4.5. - [Release notes](https://github.com/python/importlib_resources/releases) - [Changelog](https://github.com/python/importlib_resources/blob/main/NEWS.rst) - [Commits](https://github.com/python/importlib_resources/compare/v6.4.0...v6.4.5) --- updated-dependencies: - dependency-name: importlib-resources dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> * Update importlib-resources==6.4.5 --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> [skip ci]
This commit is contained in:
parent
f3a2c02e96
commit
01589cb8b0
41 changed files with 484 additions and 316 deletions
|
@ -1,16 +1,27 @@
|
|||
"""
|
||||
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 functools
|
||||
import io
|
||||
import posixpath
|
||||
import zipfile
|
||||
import itertools
|
||||
import contextlib
|
||||
import pathlib
|
||||
import posixpath
|
||||
import re
|
||||
import stat
|
||||
import sys
|
||||
import zipfile
|
||||
|
||||
from .compat.py310 import text_encoding
|
||||
from .glob import Translator
|
||||
|
||||
from ._functools import save_method_args
|
||||
|
||||
|
||||
__all__ = ['Path']
|
||||
|
||||
|
@ -37,7 +48,7 @@ def _parents(path):
|
|||
def _ancestry(path):
|
||||
"""
|
||||
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'))
|
||||
['b/d', 'b']
|
||||
|
@ -49,9 +60,14 @@ def _ancestry(path):
|
|||
['b']
|
||||
>>> 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)
|
||||
while path and path != posixpath.sep:
|
||||
while path.rstrip(posixpath.sep):
|
||||
yield path
|
||||
path, tail = posixpath.split(path)
|
||||
|
||||
|
@ -73,82 +89,19 @@ class InitializedState:
|
|||
Mix-in to save the initialization state for pickling.
|
||||
"""
|
||||
|
||||
@save_method_args
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.__args = args
|
||||
self.__kwargs = kwargs
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def __getstate__(self):
|
||||
return self.__args, self.__kwargs
|
||||
return self._saved___init__.args, self._saved___init__.kwargs
|
||||
|
||||
def __setstate__(self, state):
|
||||
args, kwargs = state
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
||||
class SanitizedNames:
|
||||
"""
|
||||
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):
|
||||
class CompleteDirs(InitializedState, zipfile.ZipFile):
|
||||
"""
|
||||
A ZipFile subclass that ensures that implied directories
|
||||
are always included in the namelist.
|
||||
|
@ -230,16 +183,18 @@ class FastLookup(CompleteDirs):
|
|||
"""
|
||||
|
||||
def namelist(self):
|
||||
with contextlib.suppress(AttributeError):
|
||||
return self.__names
|
||||
self.__names = super().namelist()
|
||||
return self.__names
|
||||
return self._namelist
|
||||
|
||||
@functools.cached_property
|
||||
def _namelist(self):
|
||||
return super().namelist()
|
||||
|
||||
def _name_set(self):
|
||||
with contextlib.suppress(AttributeError):
|
||||
return self.__lookup
|
||||
self.__lookup = super()._name_set()
|
||||
return self.__lookup
|
||||
return self._name_set_prop
|
||||
|
||||
@functools.cached_property
|
||||
def _name_set_prop(self):
|
||||
return super()._name_set()
|
||||
|
||||
|
||||
def _extract_text_encoding(encoding=None, *args, **kwargs):
|
||||
|
@ -329,7 +284,7 @@ class Path:
|
|||
>>> str(path.parent)
|
||||
'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.
|
||||
|
||||
>>> zf.filename = None
|
||||
|
@ -388,7 +343,7 @@ class Path:
|
|||
if self.is_dir():
|
||||
raise IsADirectoryError(self)
|
||||
zip_mode = mode[0]
|
||||
if not self.exists() and zip_mode == 'r':
|
||||
if zip_mode == 'r' and not self.exists():
|
||||
raise FileNotFoundError(self)
|
||||
stream = self.root.open(self.at, zip_mode, pwd=pwd)
|
||||
if 'b' in mode:
|
||||
|
@ -470,8 +425,7 @@ class Path:
|
|||
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}')
|
||||
|
|
20
lib/zipp/_functools.py
Normal file
20
lib/zipp/_functools.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
import collections
|
||||
import functools
|
||||
|
||||
|
||||
# from jaraco.functools 4.0.2
|
||||
def save_method_args(method):
|
||||
"""
|
||||
Wrap a method such that when it is called, the args and kwargs are
|
||||
saved on the method.
|
||||
"""
|
||||
args_and_kwargs = collections.namedtuple('args_and_kwargs', 'args kwargs')
|
||||
|
||||
@functools.wraps(method)
|
||||
def wrapper(self, /, *args, **kwargs):
|
||||
attr_name = '_saved_' + method.__name__
|
||||
attr = args_and_kwargs(args, kwargs)
|
||||
setattr(self, attr_name, attr)
|
||||
return method(self, *args, **kwargs)
|
||||
|
||||
return wrapper
|
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]
|
|
@ -1,5 +1,5 @@
|
|||
import sys
|
||||
import io
|
||||
import sys
|
||||
|
||||
|
||||
def _text_encoding(encoding, stacklevel=2, /): # pragma: no cover
|
||||
|
@ -7,5 +7,7 @@ def _text_encoding(encoding, stacklevel=2, /): # pragma: no cover
|
|||
|
||||
|
||||
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
|
||||
)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import os
|
||||
import re
|
||||
|
||||
|
||||
_default_seps = os.sep + str(os.altsep) * bool(os.altsep)
|
||||
|
||||
|
||||
|
@ -28,7 +27,7 @@ class Translator:
|
|||
"""
|
||||
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"""
|
||||
|
@ -41,6 +40,14 @@ class Translator:
|
|||
"""
|
||||
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.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue