]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-135276: Refresh `zipfile.Path` from zipp 3.23 (#135277)
authorJason R. Coombs <jaraco@jaraco.com>
Sun, 8 Jun 2025 19:20:20 +0000 (15:20 -0400)
committerGitHub <noreply@github.com>
Sun, 8 Jun 2025 19:20:20 +0000 (19:20 +0000)
Apply changes from zipp 3.23

Lib/test/test_zipfile/_path/_test_params.py
Lib/test/test_zipfile/_path/test_complexity.py
Lib/test/test_zipfile/_path/test_path.py
Lib/test/test_zipfile/_path/write-alpharep.py
Lib/zipfile/_path/__init__.py
Lib/zipfile/_path/_functools.py [new file with mode: 0644]
Lib/zipfile/_path/glob.py
Misc/NEWS.d/next/Library/2025-06-08-14-50-34.gh-issue-135276.ZLUhV1.rst [new file with mode: 0644]

index bc95b4ebf4a168c1798af262cf8e750c56ed4144..00a9eaf2f99c1aef7e008477582761d5d5dcf277 100644 (file)
@@ -1,5 +1,5 @@
-import types
 import functools
+import types
 
 from ._itertools import always_iterable
 
index b505dd7c3764623ee566ed5a4ce9910647d960ee..7c108fc6ab8191db8e48f8d1587d5a6aa5dfcd4f 100644 (file)
@@ -8,10 +8,8 @@ import zipfile
 
 from ._functools import compose
 from ._itertools import consume
-
 from ._support import import_or_skip
 
-
 big_o = import_or_skip('big_o')
 pytest = import_or_skip('pytest')
 
index 0afabc0c6683c4c8216080a59f4b6d33bdb08d69..696134023a56b917b0f63304b045fed68f2a2bb3 100644 (file)
@@ -1,6 +1,6 @@
+import contextlib
 import io
 import itertools
-import contextlib
 import pathlib
 import pickle
 import stat
@@ -9,12 +9,11 @@ import unittest
 import zipfile
 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 ._itertools import Counter
-
-from ._test_params import parameterize, Invoked
+from ._test_params import Invoked, parameterize
 
 
 class jaraco:
@@ -193,10 +192,10 @@ class TestPath(unittest.TestCase):
         """EncodingWarning must blame the read_text and open calls."""
         assert sys.flags.warn_default_encoding
         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()
         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()
         assert __file__ == wc.filename
 
@@ -364,6 +363,17 @@ class TestPath(unittest.TestCase):
         root = zipfile.Path(alpharep)
         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
     def test_suffix(self, alpharep):
         """
index 48c09b537179fd2489fc236239c81d43b11135e7..7418391abadde5e7a9af8d0de59de0a70bd56249 100644 (file)
@@ -1,4 +1,3 @@
 from . import test_path
 
-
 __name__ == '__main__' and test_path.build_alpharep_fixture().extractall('alpharep')
index 5ae16ec970dda421053623c617d27436f4170388..faae4c84cae5ed290896e2d1df660ceb1844c0f5 100644 (file)
@@ -7,19 +7,19 @@ 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 ._functools import save_method_args
 from .glob import Translator
 
-
 __all__ = ['Path']
 
 
@@ -86,13 +86,12 @@ 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
@@ -181,22 +180,27 @@ 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):
     # compute stack level so that the caller of the caller sees any warning.
     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
 
 
@@ -351,7 +355,7 @@ class Path:
         return io.TextIOWrapper(stream, encoding, *args, **kwargs)
 
     def _base(self):
-        return pathlib.PurePosixPath(self.at or self.root.filename)
+        return pathlib.PurePosixPath(self.at) if self.at else self.filename
 
     @property
     def name(self):
diff --git a/Lib/zipfile/_path/_functools.py b/Lib/zipfile/_path/_functools.py
new file mode 100644 (file)
index 0000000..7390be2
--- /dev/null
@@ -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
index d7fe45a494717ac92d97cc89ef8bf04a8dc4df3b..bd2839304b7db2a628c7d3785f1d0a0d316424f8 100644 (file)
@@ -1,7 +1,6 @@
 import os
 import re
 
-
 _default_seps = os.sep + str(os.altsep) * bool(os.altsep)
 
 
diff --git a/Misc/NEWS.d/next/Library/2025-06-08-14-50-34.gh-issue-135276.ZLUhV1.rst b/Misc/NEWS.d/next/Library/2025-06-08-14-50-34.gh-issue-135276.ZLUhV1.rst
new file mode 100644 (file)
index 0000000..a8fbd48
--- /dev/null
@@ -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.