Skip to content

Commit a35fd38

Browse files
authored
gh-102209: Sync with zipp 3.15 moving complexity tests into dedicated module (#102232)
Sync with jaraco/zipp@757a4e1a.
1 parent 207e1c5 commit a35fd38

File tree

7 files changed

+87
-51
lines changed

7 files changed

+87
-51
lines changed

Lib/test/test_zipfile/_context.py

-30
This file was deleted.

Lib/test/test_zipfile/_func_timeout_compat.py

-8
This file was deleted.

Lib/test/test_zipfile/_itertools.py

+38
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import itertools
2+
from collections import deque
3+
from itertools import islice
24

35

46
# from jaraco.itertools 6.3.0
@@ -39,3 +41,39 @@ def always_iterable(obj, base_type=(str, bytes)):
3941
return iter(obj)
4042
except TypeError:
4143
return iter((obj,))
44+
45+
46+
# from more_itertools v9.0.0
47+
def consume(iterator, n=None):
48+
"""Advance *iterable* by *n* steps. If *n* is ``None``, consume it
49+
entirely.
50+
Efficiently exhausts an iterator without returning values. Defaults to
51+
consuming the whole iterator, but an optional second argument may be
52+
provided to limit consumption.
53+
>>> i = (x for x in range(10))
54+
>>> next(i)
55+
0
56+
>>> consume(i, 3)
57+
>>> next(i)
58+
4
59+
>>> consume(i)
60+
>>> next(i)
61+
Traceback (most recent call last):
62+
File "<stdin>", line 1, in <module>
63+
StopIteration
64+
If the iterator has fewer items remaining than the provided limit, the
65+
whole iterator will be consumed.
66+
>>> i = (x for x in range(3))
67+
>>> consume(i, 5)
68+
>>> next(i)
69+
Traceback (most recent call last):
70+
File "<stdin>", line 1, in <module>
71+
StopIteration
72+
"""
73+
# Use functions that consume iterators at C speed.
74+
if n is None:
75+
# feed the entire iterator into a zero-length deque
76+
deque(iterator, maxlen=0)
77+
else:
78+
# advance to the empty slice starting at position n
79+
next(islice(iterator, n, n), None)

Lib/test/test_zipfile/_support.py

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import importlib
2+
import unittest
3+
4+
5+
def import_or_skip(name):
6+
try:
7+
return importlib.import_module(name)
8+
except ImportError: # pragma: no cover
9+
raise unittest.SkipTest(f'Unable to import {name}')
+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import unittest
2+
import string
3+
import zipfile
4+
5+
from ._functools import compose
6+
from ._itertools import consume
7+
8+
from ._support import import_or_skip
9+
10+
11+
big_o = import_or_skip('big_o')
12+
13+
14+
class TestComplexity(unittest.TestCase):
15+
def test_implied_dirs_performance(self):
16+
best, others = big_o.big_o(
17+
compose(consume, zipfile.CompleteDirs._implied_dirs),
18+
lambda size: [
19+
'/'.join(string.ascii_lowercase + str(n)) for n in range(size)
20+
],
21+
max_n=1000,
22+
min_n=1,
23+
)
24+
assert best <= big_o.complexities.Linear

Lib/test/test_zipfile/test_path.py

+10-12
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import contextlib
44
import pathlib
55
import pickle
6-
import string
76
import sys
87
import unittest
98
import zipfile
@@ -12,7 +11,6 @@
1211
from ._itertools import Counter
1312

1413
from ._test_params import parameterize, Invoked
15-
from ._func_timeout_compat import set_timeout
1614

1715
from test.support.os_helper import temp_dir
1816

@@ -22,9 +20,6 @@ class itertools:
2220
Counter = Counter
2321

2422

25-
consume = tuple
26-
27-
2823
def add_dirs(zf):
2924
"""
3025
Given a writable zip file zf, inject directory entries for
@@ -330,12 +325,6 @@ def test_joinpath_constant_time(self):
330325
# Check the file iterated all items
331326
assert entries.count == self.HUGE_ZIPFILE_NUM_ENTRIES
332327

333-
# timeout disabled due to #102209
334-
# @set_timeout(3)
335-
def test_implied_dirs_performance(self):
336-
data = ['/'.join(string.ascii_lowercase + str(n)) for n in range(10000)]
337-
zipfile.CompleteDirs._implied_dirs(data)
338-
339328
@pass_alpharep
340329
def test_read_does_not_close(self, alpharep):
341330
alpharep = self.zipfile_ondisk(alpharep)
@@ -513,7 +502,7 @@ def test_pickle(self, alpharep, path_type, subpath):
513502
saved_1 = pickle.dumps(zipfile.Path(zipfile_ondisk, at=subpath))
514503
restored_1 = pickle.loads(saved_1)
515504
first, *rest = restored_1.iterdir()
516-
assert first.read_text().startswith('content of ')
505+
assert first.read_text(encoding='utf-8').startswith('content of ')
517506

518507
@pass_alpharep
519508
def test_extract_orig_with_implied_dirs(self, alpharep):
@@ -525,3 +514,12 @@ def test_extract_orig_with_implied_dirs(self, alpharep):
525514
# wrap the zipfile for its side effect
526515
zipfile.Path(zf)
527516
zf.extractall(source_path.parent)
517+
518+
@pass_alpharep
519+
def test_getinfo_missing(self, alpharep):
520+
"""
521+
Validate behavior of getinfo on original zipfile after wrapping.
522+
"""
523+
zipfile.Path(alpharep)
524+
with self.assertRaises(KeyError):
525+
alpharep.getinfo('does-not-exist')

Lib/zipfile/_path.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,11 @@ class CompleteDirs(InitializedState, zipfile.ZipFile):
8686
"""
8787
A ZipFile subclass that ensures that implied directories
8888
are always included in the namelist.
89+
90+
>>> list(CompleteDirs._implied_dirs(['foo/bar.txt', 'foo/bar/baz.txt']))
91+
['foo/', 'foo/bar/']
92+
>>> list(CompleteDirs._implied_dirs(['foo/bar.txt', 'foo/bar/baz.txt', 'foo/bar/']))
93+
['foo/']
8994
"""
9095

9196
@staticmethod
@@ -215,7 +220,7 @@ class Path:
215220
216221
Read text:
217222
218-
>>> c.read_text()
223+
>>> c.read_text(encoding='utf-8')
219224
'content of c'
220225
221226
existence:

0 commit comments

Comments
 (0)