gh-135276: Refresh zipfile.Path from zipp 3.23 (#135277)

Apply changes from zipp 3.23
This commit is contained in:
Jason R. Coombs 2025-06-08 15:20:20 -04:00 committed by GitHub
parent aac22ea212
commit 8d6eb0c262
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 64 additions and 28 deletions

View file

@ -1,5 +1,5 @@
import types
import functools import functools
import types
from ._itertools import always_iterable from ._itertools import always_iterable

View file

@ -8,10 +8,8 @@ import zipfile
from ._functools import compose from ._functools import compose
from ._itertools import consume from ._itertools import consume
from ._support import import_or_skip from ._support import import_or_skip
big_o = import_or_skip('big_o') big_o = import_or_skip('big_o')
pytest = import_or_skip('pytest') pytest = import_or_skip('pytest')

View file

@ -1,6 +1,6 @@
import contextlib
import io import io
import itertools import itertools
import contextlib
import pathlib import pathlib
import pickle import pickle
import stat import stat
@ -9,12 +9,11 @@ import unittest
import zipfile import zipfile
import zipfile._path import zipfile._path
from test.support.os_helper import temp_dir, FakePath from test.support.os_helper import FakePath, temp_dir
from ._functools import compose from ._functools import compose
from ._itertools import Counter from ._itertools import Counter
from ._test_params import Invoked, parameterize
from ._test_params import parameterize, Invoked
class jaraco: class jaraco:
@ -193,10 +192,10 @@ class TestPath(unittest.TestCase):
"""EncodingWarning must blame the read_text and open calls.""" """EncodingWarning must blame the read_text and open calls."""
assert sys.flags.warn_default_encoding assert sys.flags.warn_default_encoding
root = zipfile.Path(alpharep) root = zipfile.Path(alpharep)
with self.assertWarns(EncodingWarning) as wc: with self.assertWarns(EncodingWarning) as wc: # noqa: F821 (astral-sh/ruff#13296)
root.joinpath("a.txt").read_text() root.joinpath("a.txt").read_text()
assert __file__ == wc.filename assert __file__ == wc.filename
with self.assertWarns(EncodingWarning) as wc: with self.assertWarns(EncodingWarning) as wc: # noqa: F821 (astral-sh/ruff#13296)
root.joinpath("a.txt").open("r").close() root.joinpath("a.txt").open("r").close()
assert __file__ == wc.filename assert __file__ == wc.filename
@ -364,6 +363,17 @@ class TestPath(unittest.TestCase):
root = zipfile.Path(alpharep) root = zipfile.Path(alpharep)
assert root.name == 'alpharep.zip' == root.filename.name assert root.name == 'alpharep.zip' == root.filename.name
@pass_alpharep
def test_root_on_disk(self, alpharep):
"""
The name/stem of the root should match the zipfile on disk.
This condition must hold across platforms.
"""
root = zipfile.Path(self.zipfile_ondisk(alpharep))
assert root.name == 'alpharep.zip' == root.filename.name
assert root.stem == 'alpharep' == root.filename.stem
@pass_alpharep @pass_alpharep
def test_suffix(self, alpharep): def test_suffix(self, alpharep):
""" """

View file

@ -1,4 +1,3 @@
from . import test_path from . import test_path
__name__ == '__main__' and test_path.build_alpharep_fixture().extractall('alpharep') __name__ == '__main__' and test_path.build_alpharep_fixture().extractall('alpharep')

View file

@ -7,19 +7,19 @@ https://github.com/python/importlib_metadata/wiki/Development-Methodology
for more detail. for more detail.
""" """
import functools
import io import io
import posixpath
import zipfile
import itertools import itertools
import contextlib
import pathlib import pathlib
import posixpath
import re import re
import stat import stat
import sys import sys
import zipfile
from ._functools import save_method_args
from .glob import Translator from .glob import Translator
__all__ = ['Path'] __all__ = ['Path']
@ -86,13 +86,12 @@ class InitializedState:
Mix-in to save the initialization state for pickling. Mix-in to save the initialization state for pickling.
""" """
@save_method_args
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.__args = args
self.__kwargs = kwargs
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
def __getstate__(self): def __getstate__(self):
return self.__args, self.__kwargs return self._saved___init__.args, self._saved___init__.kwargs
def __setstate__(self, state): def __setstate__(self, state):
args, kwargs = state args, kwargs = state
@ -181,22 +180,27 @@ class FastLookup(CompleteDirs):
""" """
def namelist(self): def namelist(self):
with contextlib.suppress(AttributeError): return self._namelist
return self.__names
self.__names = super().namelist() @functools.cached_property
return self.__names def _namelist(self):
return super().namelist()
def _name_set(self): def _name_set(self):
with contextlib.suppress(AttributeError): return self._name_set_prop
return self.__lookup
self.__lookup = super()._name_set() @functools.cached_property
return self.__lookup def _name_set_prop(self):
return super()._name_set()
def _extract_text_encoding(encoding=None, *args, **kwargs): def _extract_text_encoding(encoding=None, *args, **kwargs):
# compute stack level so that the caller of the caller sees any warning. # compute stack level so that the caller of the caller sees any warning.
is_pypy = sys.implementation.name == 'pypy' is_pypy = sys.implementation.name == 'pypy'
stack_level = 3 + is_pypy # PyPy no longer special cased after 7.3.19 (or maybe 7.3.18)
# See jaraco/zipp#143
is_old_pypi = is_pypy and sys.pypy_version_info < (7, 3, 19)
stack_level = 3 + is_old_pypi
return io.text_encoding(encoding, stack_level), args, kwargs return io.text_encoding(encoding, stack_level), args, kwargs
@ -351,7 +355,7 @@ class Path:
return io.TextIOWrapper(stream, encoding, *args, **kwargs) return io.TextIOWrapper(stream, encoding, *args, **kwargs)
def _base(self): def _base(self):
return pathlib.PurePosixPath(self.at or self.root.filename) return pathlib.PurePosixPath(self.at) if self.at else self.filename
@property @property
def name(self): def name(self):

View 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') # noqa: PYI024
@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

View file

@ -1,7 +1,6 @@
import os import os
import re import re
_default_seps = os.sep + str(os.altsep) * bool(os.altsep) _default_seps = os.sep + str(os.altsep) * bool(os.altsep)

View file

@ -0,0 +1,6 @@
Synchronized zipfile.Path with zipp 3.23, including improved performance of
:meth:`zipfile.Path.open` for non-reading modes, rely on
:func:`functools.cached_property` to cache values on the instance. Rely on
``save_method_args`` to save the initialization method arguments. Fixed
``.name``, ``.stem`` and other basename-based properties on Windows when
working with a zipfile on disk.