summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_zipfile
diff options
context:
space:
mode:
authorJason R. Coombs <jaraco@jaraco.com>2023-02-20 21:01:58 (GMT)
committerGitHub <noreply@github.com>2023-02-20 21:01:58 (GMT)
commit36854bbb240e417c0df6f0014924fcc899388186 (patch)
treec0b3e543bac2a8507e09a4324acafae0d36ba7f4 /Lib/test/test_zipfile
parent84181c14040ed2befe7f1a55b4f560c80fa61154 (diff)
downloadcpython-36854bbb240e417c0df6f0014924fcc899388186.zip
cpython-36854bbb240e417c0df6f0014924fcc899388186.tar.gz
cpython-36854bbb240e417c0df6f0014924fcc899388186.tar.bz2
gh-101566: Sync with zipp 3.14. (GH-102018)
Diffstat (limited to 'Lib/test/test_zipfile')
-rw-r--r--Lib/test/test_zipfile/_context.py30
-rw-r--r--Lib/test/test_zipfile/_func_timeout_compat.py8
-rw-r--r--Lib/test/test_zipfile/_itertools.py29
-rw-r--r--Lib/test/test_zipfile/test_path.py137
4 files changed, 151 insertions, 53 deletions
diff --git a/Lib/test/test_zipfile/_context.py b/Lib/test/test_zipfile/_context.py
new file mode 100644
index 0000000..348798a
--- /dev/null
+++ b/Lib/test/test_zipfile/_context.py
@@ -0,0 +1,30 @@
+import contextlib
+import time
+
+
+class DeadlineExceeded(Exception):
+ pass
+
+
+class TimedContext(contextlib.ContextDecorator):
+ """
+ A context that will raise DeadlineExceeded if the
+ max duration is reached during the execution.
+
+ >>> TimedContext(1)(time.sleep)(.1)
+ >>> TimedContext(0)(time.sleep)(.1)
+ Traceback (most recent call last):
+ ...
+ tests._context.DeadlineExceeded: (..., 0)
+ """
+
+ def __init__(self, max_duration: int):
+ self.max_duration = max_duration
+
+ def __enter__(self):
+ self.start = time.monotonic()
+
+ def __exit__(self, *err):
+ duration = time.monotonic() - self.start
+ if duration > self.max_duration:
+ raise DeadlineExceeded(duration, self.max_duration)
diff --git a/Lib/test/test_zipfile/_func_timeout_compat.py b/Lib/test/test_zipfile/_func_timeout_compat.py
new file mode 100644
index 0000000..b1f2b26
--- /dev/null
+++ b/Lib/test/test_zipfile/_func_timeout_compat.py
@@ -0,0 +1,8 @@
+try:
+ from func_timeout import func_set_timeout as set_timeout
+except ImportError: # pragma: no cover
+ # provide a fallback that doesn't actually time out
+ from ._context import TimedContext as set_timeout
+
+
+__all__ = ['set_timeout']
diff --git a/Lib/test/test_zipfile/_itertools.py b/Lib/test/test_zipfile/_itertools.py
index 559f3f1..74f01fe 100644
--- a/Lib/test/test_zipfile/_itertools.py
+++ b/Lib/test/test_zipfile/_itertools.py
@@ -1,3 +1,32 @@
+import itertools
+
+
+# from jaraco.itertools 6.3.0
+class Counter:
+ """
+ Wrap an iterable in an object that stores the count of items
+ that pass through it.
+
+ >>> items = Counter(range(20))
+ >>> items.count
+ 0
+ >>> values = list(items)
+ >>> items.count
+ 20
+ """
+
+ def __init__(self, i):
+ self.count = 0
+ self.iter = zip(itertools.count(1), i)
+
+ def __iter__(self):
+ return self
+
+ def __next__(self):
+ self.count, result = next(self.iter)
+ return result
+
+
# from more_itertools v8.13.0
def always_iterable(obj, base_type=(str, bytes)):
if obj is None:
diff --git a/Lib/test/test_zipfile/test_path.py b/Lib/test/test_zipfile/test_path.py
index 3086fd2..92fda69 100644
--- a/Lib/test/test_zipfile/test_path.py
+++ b/Lib/test/test_zipfile/test_path.py
@@ -4,36 +4,25 @@ import contextlib
import pathlib
import pickle
import string
-from test.support.script_helper import assert_python_ok
+import sys
import unittest
import zipfile
-from ._test_params import parameterize, Invoked
from ._functools import compose
+from ._itertools import Counter
+from ._test_params import parameterize, Invoked
+from ._func_timeout_compat import set_timeout
from test.support.os_helper import temp_dir
-# Poor man's technique to consume a (smallish) iterable.
-consume = tuple
-
-
-# from jaraco.itertools 5.0
class jaraco:
class itertools:
- class Counter:
- def __init__(self, i):
- self.count = 0
- self._orig_iter = iter(i)
+ Counter = Counter
- def __iter__(self):
- return self
- def __next__(self):
- result = next(self._orig_iter)
- self.count += 1
- return result
+consume = tuple
def add_dirs(zf):
@@ -161,10 +150,10 @@ class TestPath(unittest.TestCase):
u16 = path.joinpath("16.txt")
with u16.open('r', "utf-16") as strm:
data = strm.read()
- self.assertEqual(data, "This was utf-16")
+ assert data == "This was utf-16"
with u16.open(encoding="utf-16") as strm:
data = strm.read()
- self.assertEqual(data, "This was utf-16")
+ assert data == "This was utf-16"
def test_open_encoding_errors(self):
in_memory_file = io.BytesIO()
@@ -177,9 +166,9 @@ class TestPath(unittest.TestCase):
# encoding= as a positional argument for gh-101144.
data = u16.read_text("utf-8", errors="ignore")
- self.assertEqual(data, "invalid utf-8: .")
+ assert data == "invalid utf-8: ."
with u16.open("r", "utf-8", errors="surrogateescape") as f:
- self.assertEqual(f.read(), "invalid utf-8: \udcff\udcff.")
+ assert f.read() == "invalid utf-8: \udcff\udcff."
# encoding= both positional and keyword is an error; gh-101144.
with self.assertRaisesRegex(TypeError, "encoding"):
@@ -191,24 +180,21 @@ class TestPath(unittest.TestCase):
with self.assertRaises(UnicodeDecodeError):
f.read()
- def test_encoding_warnings(self):
+ @unittest.skipIf(
+ not getattr(sys.flags, 'warn_default_encoding', 0),
+ "Requires warn_default_encoding",
+ )
+ @pass_alpharep
+ def test_encoding_warnings(self, alpharep):
"""EncodingWarning must blame the read_text and open calls."""
- code = '''\
-import io, zipfile
-with zipfile.ZipFile(io.BytesIO(), "w") as zf:
- zf.filename = '<test_encoding_warnings in memory zip file>'
- zf.writestr("path/file.txt", b"Spanish Inquisition")
- root = zipfile.Path(zf)
- (path,) = root.iterdir()
- file_path = path.joinpath("file.txt")
- unused = file_path.read_text() # should warn
- file_path.open("r").close() # should warn
-'''
- proc = assert_python_ok('-X', 'warn_default_encoding', '-c', code)
- warnings = proc.err.splitlines()
- self.assertEqual(len(warnings), 2, proc.err)
- self.assertRegex(warnings[0], rb"^<string>:8: EncodingWarning:")
- self.assertRegex(warnings[1], rb"^<string>:9: EncodingWarning:")
+ assert sys.flags.warn_default_encoding
+ root = zipfile.Path(alpharep)
+ with self.assertWarns(EncodingWarning) as wc:
+ root.joinpath("a.txt").read_text()
+ assert __file__ == wc.filename
+ with self.assertWarns(EncodingWarning) as wc:
+ root.joinpath("a.txt").open("r").close()
+ assert __file__ == wc.filename
def test_open_write(self):
"""
@@ -250,7 +236,8 @@ with zipfile.ZipFile(io.BytesIO(), "w") as zf:
root = zipfile.Path(alpharep)
a, b, g = root.iterdir()
assert a.read_text(encoding="utf-8") == "content of a"
- a.read_text("utf-8") # No positional arg TypeError per gh-101144.
+ # Also check positional encoding arg (gh-101144).
+ assert a.read_text("utf-8") == "content of a"
assert a.read_bytes() == b"content of a"
@pass_alpharep
@@ -276,19 +263,6 @@ with zipfile.ZipFile(io.BytesIO(), "w") as zf:
assert e.read_text(encoding="utf-8") == "content of e"
@pass_alpharep
- def test_traverse_simplediv(self, alpharep):
- """
- Disable the __future__.division when testing traversal.
- """
- code = compile(
- source="zipfile.Path(alpharep) / 'a'",
- filename="(test)",
- mode="eval",
- dont_inherit=True,
- )
- eval(code)
-
- @pass_alpharep
def test_pathlike_construction(self, alpharep):
"""
zipfile.Path should be constructable from a path-like object
@@ -356,7 +330,7 @@ with zipfile.ZipFile(io.BytesIO(), "w") as zf:
# Check the file iterated all items
assert entries.count == self.HUGE_ZIPFILE_NUM_ENTRIES
- # @func_timeout.func_set_timeout(3)
+ @set_timeout(3)
def test_implied_dirs_performance(self):
data = ['/'.join(string.ascii_lowercase + str(n)) for n in range(10000)]
zipfile.CompleteDirs._implied_dirs(data)
@@ -473,6 +447,52 @@ with zipfile.ZipFile(io.BytesIO(), "w") as zf:
assert sub.parent
@pass_alpharep
+ def test_match_and_glob(self, alpharep):
+ root = zipfile.Path(alpharep)
+ assert not root.match("*.txt")
+
+ assert list(root.glob("b/c.*")) == [zipfile.Path(alpharep, "b/c.txt")]
+
+ files = root.glob("**/*.txt")
+ assert all(each.match("*.txt") for each in files)
+
+ assert list(root.glob("**/*.txt")) == list(root.rglob("*.txt"))
+
+ def test_glob_empty(self):
+ root = zipfile.Path(zipfile.ZipFile(io.BytesIO(), 'w'))
+ with self.assertRaises(ValueError):
+ root.glob('')
+
+ @pass_alpharep
+ def test_eq_hash(self, alpharep):
+ root = zipfile.Path(alpharep)
+ assert root == zipfile.Path(alpharep)
+
+ assert root != (root / "a.txt")
+ assert (root / "a.txt") == (root / "a.txt")
+
+ root = zipfile.Path(alpharep)
+ assert root in {root}
+
+ @pass_alpharep
+ def test_is_symlink(self, alpharep):
+ """
+ See python/cpython#82102 for symlink support beyond this object.
+ """
+
+ root = zipfile.Path(alpharep)
+ assert not root.is_symlink()
+
+ @pass_alpharep
+ def test_relative_to(self, alpharep):
+ root = zipfile.Path(alpharep)
+ relative = root.joinpath("b", "c.txt").relative_to(root / "b")
+ assert str(relative) == "c.txt"
+
+ relative = root.joinpath("b", "d", "e.txt").relative_to(root / "b")
+ assert str(relative) == "d/e.txt"
+
+ @pass_alpharep
def test_inheritance(self, alpharep):
cls = type('PathChild', (zipfile.Path,), {})
file = cls(alpharep).joinpath('some dir').parent
@@ -493,3 +513,14 @@ with zipfile.ZipFile(io.BytesIO(), "w") as zf:
restored_1 = pickle.loads(saved_1)
first, *rest = restored_1.iterdir()
assert first.read_text().startswith('content of ')
+
+ @pass_alpharep
+ def test_extract_orig_with_implied_dirs(self, alpharep):
+ """
+ A zip file wrapped in a Path should extract even with implied dirs.
+ """
+ source_path = self.zipfile_ondisk(alpharep)
+ zf = zipfile.ZipFile(source_path)
+ # wrap the zipfile for its side effect
+ zipfile.Path(zf)
+ zf.extractall(source_path.parent)