Skip to content

Commit 4b2176e

Browse files
committed
1 parent 11c0937 commit 4b2176e

File tree

3 files changed

+54
-56
lines changed

3 files changed

+54
-56
lines changed

Doc/library/zipfile.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -527,7 +527,7 @@ ZipFile Objects
527527
a path is provided.
528528

529529
This does not physically remove the local file entry from the archive.
530-
Call :meth:`ZipFile.repack` afterwards to reclaim space.
530+
Call :meth:`repack` afterwards to reclaim space.
531531

532532
The archive must be opened with mode ``'w'``, ``'x'`` or ``'a'``.
533533

Lib/test/test_zipfile/test_core.py

Lines changed: 44 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1362,8 +1362,11 @@ class ZstdWriterTests(AbstractWriterTests, unittest.TestCase):
13621362
compression = zipfile.ZIP_ZSTANDARD
13631363

13641364

1365-
def ComparableZipInfo(zinfo):
1366-
return (zinfo.filename, zinfo.header_offset, zinfo.compress_size, zinfo.CRC)
1365+
class ComparableZipInfo:
1366+
keys = [i for i in zipfile.ZipInfo.__slots__ if not i.startswith('_')]
1367+
1368+
def __new__(cls, zinfo):
1369+
return {i: getattr(zinfo, i) for i in cls.keys}
13671370

13681371
_struct_pack = struct.pack
13691372

@@ -1379,6 +1382,8 @@ def struct_pack_no_dd_sig(fmt, *values):
13791382

13801383
class RepackHelperMixin:
13811384
"""Common helpers for remove and repack."""
1385+
maxDiff = 8192
1386+
13821387
@classmethod
13831388
def _prepare_test_files(cls):
13841389
return [
@@ -1389,14 +1394,11 @@ def _prepare_test_files(cls):
13891394

13901395
@classmethod
13911396
def _prepare_zip_from_test_files(cls, zfname, test_files, force_zip64=False):
1392-
zinfos = []
13931397
with zipfile.ZipFile(zfname, 'w', cls.compression) as zh:
13941398
for file, data in test_files:
13951399
with zh.open(file, 'w', force_zip64=force_zip64) as fh:
13961400
fh.write(data)
1397-
zinfo = zh.getinfo(file)
1398-
zinfos.append(ComparableZipInfo(zinfo))
1399-
return zinfos
1401+
return list(zh.infolist())
14001402

14011403
class AbstractRemoveTests(RepackHelperMixin):
14021404
@classmethod
@@ -1416,7 +1418,7 @@ def test_remove_by_name(self):
14161418
# check infolist
14171419
self.assertEqual(
14181420
[ComparableZipInfo(zi) for zi in zh.infolist()],
1419-
[zi for j, zi in enumerate(zinfos) if j != i],
1421+
[ComparableZipInfo(zi) for j, zi in enumerate(zinfos) if j != i],
14201422
)
14211423

14221424
# check NameToInfo cache
@@ -1437,7 +1439,7 @@ def test_remove_by_zinfo(self):
14371439
# check infolist
14381440
self.assertEqual(
14391441
[ComparableZipInfo(zi) for zi in zh.infolist()],
1440-
[zi for j, zi in enumerate(zinfos) if j != i],
1442+
[ComparableZipInfo(zi) for j, zi in enumerate(zinfos) if j != i],
14411443
)
14421444

14431445
# check NameToInfo cache
@@ -1478,13 +1480,13 @@ def test_remove_by_name_duplicated(self):
14781480
# check infolist
14791481
self.assertEqual(
14801482
[ComparableZipInfo(zi) for zi in zh.infolist()],
1481-
[zinfos[0], zinfos[2]],
1483+
[ComparableZipInfo(zi) for zi in [zinfos[0], zinfos[2]]],
14821484
)
14831485

14841486
# check NameToInfo cache
14851487
self.assertEqual(
14861488
ComparableZipInfo(zh.getinfo('file.txt')),
1487-
zinfos[0],
1489+
ComparableZipInfo(zinfos[0]),
14881490
)
14891491

14901492
# make sure the zip file is still valid
@@ -1499,7 +1501,7 @@ def test_remove_by_name_duplicated(self):
14991501
# check infolist
15001502
self.assertEqual(
15011503
[ComparableZipInfo(zi) for zi in zh.infolist()],
1502-
[zinfos[2]],
1504+
[ComparableZipInfo(zi) for zi in [zinfos[2]]],
15031505
)
15041506

15051507
# check NameToInfo cache
@@ -1528,13 +1530,13 @@ def test_remove_by_zinfo_duplicated(self):
15281530
# check infolist
15291531
self.assertEqual(
15301532
[ComparableZipInfo(zi) for zi in zh.infolist()],
1531-
[zinfos[1], zinfos[2]],
1533+
[ComparableZipInfo(zi) for zi in [zinfos[1], zinfos[2]]],
15321534
)
15331535

15341536
# check NameToInfo cache
15351537
self.assertEqual(
15361538
ComparableZipInfo(zh.getinfo('file.txt')),
1537-
zinfos[1],
1539+
ComparableZipInfo(zinfos[1]),
15381540
)
15391541

15401542
# make sure the zip file is still valid
@@ -1548,13 +1550,13 @@ def test_remove_by_zinfo_duplicated(self):
15481550
# check infolist
15491551
self.assertEqual(
15501552
[ComparableZipInfo(zi) for zi in zh.infolist()],
1551-
[zinfos[0], zinfos[2]],
1553+
[ComparableZipInfo(zi) for zi in [zinfos[0], zinfos[2]]],
15521554
)
15531555

15541556
# check NameToInfo cache
15551557
self.assertEqual(
15561558
ComparableZipInfo(zh.getinfo('file.txt')),
1557-
zinfos[0],
1559+
ComparableZipInfo(zinfos[0]),
15581560
)
15591561

15601562
# make sure the zip file is still valid
@@ -1570,7 +1572,7 @@ def test_remove_by_zinfo_duplicated(self):
15701572
# check infolist
15711573
self.assertEqual(
15721574
[ComparableZipInfo(zi) for zi in zh.infolist()],
1573-
[zinfos[2]],
1575+
[ComparableZipInfo(zi) for zi in [zinfos[2]]],
15741576
)
15751577

15761578
# check NameToInfo cache
@@ -1591,7 +1593,7 @@ def test_remove_zip64(self):
15911593
# check infolist
15921594
self.assertEqual(
15931595
[ComparableZipInfo(zi) for zi in zh.infolist()],
1594-
[zi for j, zi in enumerate(zinfos) if j != i],
1596+
[ComparableZipInfo(zi) for j, zi in enumerate(zinfos) if j != i],
15951597
)
15961598

15971599
# check NameToInfo cache
@@ -1626,14 +1628,14 @@ def test_remove_mode_w(self):
16261628
with zipfile.ZipFile(TESTFN, 'w') as zh:
16271629
for file, data in self.test_files:
16281630
zh.writestr(file, data)
1629-
zinfos = [ComparableZipInfo(zi) for zi in zh.infolist()]
1631+
zinfos = list(zh.infolist())
16301632

16311633
zh.remove(self.test_files[0][0])
16321634

16331635
# check infolist
16341636
self.assertEqual(
16351637
[ComparableZipInfo(zi) for zi in zh.infolist()],
1636-
[zinfos[1], zinfos[2]],
1638+
[ComparableZipInfo(zi) for zi in [zinfos[1], zinfos[2]]],
16371639
)
16381640

16391641
# check NameToInfo cache
@@ -1648,14 +1650,14 @@ def test_remove_mode_x(self):
16481650
with zipfile.ZipFile(TESTFN, 'x') as zh:
16491651
for file, data in self.test_files:
16501652
zh.writestr(file, data)
1651-
zinfos = [ComparableZipInfo(zi) for zi in zh.infolist()]
1653+
zinfos = list(zh.infolist())
16521654

16531655
zh.remove(self.test_files[0][0])
16541656

16551657
# check infolist
16561658
self.assertEqual(
16571659
[ComparableZipInfo(zi) for zi in zh.infolist()],
1658-
[zinfos[1], zinfos[2]],
1660+
[ComparableZipInfo(zi) for zi in [zinfos[1], zinfos[2]]],
16591661
)
16601662

16611663
# check NameToInfo cache
@@ -1714,7 +1716,7 @@ def test_repack_basic(self):
17141716
# check infolist
17151717
self.assertEqual(
17161718
[ComparableZipInfo(zi) for zi in zh.infolist()],
1717-
expected_zinfos,
1719+
[ComparableZipInfo(zi) for zi in expected_zinfos],
17181720
)
17191721

17201722
# check file size
@@ -1766,7 +1768,7 @@ def test_repack_bytes_before_first_file(self):
17661768
# check infolist
17671769
self.assertEqual(
17681770
[ComparableZipInfo(zi) for zi in zh.infolist()],
1769-
expected_zinfos,
1771+
[ComparableZipInfo(zi) for zi in expected_zinfos],
17701772
)
17711773

17721774
# check file size
@@ -1800,7 +1802,7 @@ def test_repack_magic_before_first_file(self):
18001802
# check infolist
18011803
self.assertEqual(
18021804
[ComparableZipInfo(zi) for zi in zh.infolist()],
1803-
expected_zinfos,
1805+
[ComparableZipInfo(zi) for zi in expected_zinfos],
18041806
)
18051807

18061808
# check file size
@@ -1846,7 +1848,7 @@ def test_repack_file_entry_before_first_file(self):
18461848
# check infolist
18471849
self.assertEqual(
18481850
[ComparableZipInfo(zi) for zi in zh.infolist()],
1849-
expected_zinfos,
1851+
[ComparableZipInfo(zi) for zi in expected_zinfos],
18501852
)
18511853

18521854
# check file size
@@ -1856,6 +1858,7 @@ def test_repack_file_entry_before_first_file(self):
18561858
with zipfile.ZipFile(TESTFN) as zh:
18571859
self.assertIsNone(zh.testzip())
18581860

1861+
@mock.patch.object(time, 'time', new=lambda: 315504000) # fix time for ZipFile.writestr()
18591862
def test_repack_bytes_before_removed_files(self):
18601863
"""Should preserve if there are bytes before stale local file entries."""
18611864
for ii in ([1], [1, 2], [2]):
@@ -1870,7 +1873,7 @@ def test_repack_bytes_before_removed_files(self):
18701873
zh.writestr(file, data)
18711874
for i in ii:
18721875
zh.remove(self.test_files[i][0])
1873-
expected_zinfos = [ComparableZipInfo(zi) for zi in zh.infolist()]
1876+
expected_zinfos = list(zh.infolist())
18741877
expected_size = os.path.getsize(TESTFN)
18751878

18761879
# do the removal and check the result
@@ -1889,7 +1892,7 @@ def test_repack_bytes_before_removed_files(self):
18891892
# check infolist
18901893
self.assertEqual(
18911894
[ComparableZipInfo(zi) for zi in zh.infolist()],
1892-
expected_zinfos,
1895+
[ComparableZipInfo(zi) for zi in expected_zinfos],
18931896
)
18941897

18951898
# check file size
@@ -1899,6 +1902,7 @@ def test_repack_bytes_before_removed_files(self):
18991902
with zipfile.ZipFile(TESTFN) as zh:
19001903
self.assertIsNone(zh.testzip())
19011904

1905+
@mock.patch.object(time, 'time', new=lambda: 315504000) # fix time for ZipFile.writestr()
19021906
def test_repack_bytes_after_removed_files(self):
19031907
"""Should keep extra bytes if there are bytes after stale local file entries."""
19041908
for ii in ([1], [1, 2], [2]):
@@ -1912,7 +1916,7 @@ def test_repack_bytes_after_removed_files(self):
19121916
if i == ii[-1]:
19131917
fh.write(b' dummy bytes ')
19141918
zh.start_dir = fh.tell()
1915-
expected_zinfos = [ComparableZipInfo(zi) for zi in zh.infolist()]
1919+
expected_zinfos = list(zh.infolist())
19161920
expected_size = os.path.getsize(TESTFN)
19171921

19181922
# do the removal and check the result
@@ -1931,7 +1935,7 @@ def test_repack_bytes_after_removed_files(self):
19311935
# check infolist
19321936
self.assertEqual(
19331937
[ComparableZipInfo(zi) for zi in zh.infolist()],
1934-
expected_zinfos,
1938+
[ComparableZipInfo(zi) for zi in expected_zinfos],
19351939
)
19361940

19371941
# check file size
@@ -1941,6 +1945,7 @@ def test_repack_bytes_after_removed_files(self):
19411945
with zipfile.ZipFile(TESTFN) as zh:
19421946
self.assertIsNone(zh.testzip())
19431947

1948+
@mock.patch.object(time, 'time', new=lambda: 315504000) # fix time for ZipFile.writestr()
19441949
def test_repack_bytes_between_removed_files(self):
19451950
"""Should strip only local file entries before random bytes."""
19461951
# calculate the expected results
@@ -1951,7 +1956,7 @@ def test_repack_bytes_between_removed_files(self):
19511956
zh.start_dir = fh.tell()
19521957
zh.writestr(*self.test_files[2])
19531958
zh.remove(self.test_files[2][0])
1954-
expected_zinfos = [ComparableZipInfo(zi) for zi in zh.infolist()]
1959+
expected_zinfos = list(zh.infolist())
19551960
expected_size = os.path.getsize(TESTFN)
19561961

19571962
# do the removal and check the result
@@ -1970,7 +1975,7 @@ def test_repack_bytes_between_removed_files(self):
19701975
# check infolist
19711976
self.assertEqual(
19721977
[ComparableZipInfo(zi) for zi in zh.infolist()],
1973-
expected_zinfos,
1978+
[ComparableZipInfo(zi) for zi in expected_zinfos],
19741979
)
19751980

19761981
# check file size
@@ -1992,7 +1997,7 @@ def test_repack_prepended_bytes(self):
19921997
fh.write(b'dummy ')
19931998
fh.write(fz.read())
19941999
with zipfile.ZipFile(TESTFN) as zh:
1995-
expected_zinfos = [ComparableZipInfo(zi) for zi in zh.infolist()]
2000+
expected_zinfos = list(zh.infolist())
19962001
expected_size = os.path.getsize(TESTFN)
19972002

19982003
# do the removal and check the result
@@ -2010,7 +2015,7 @@ def test_repack_prepended_bytes(self):
20102015
# check infolist
20112016
self.assertEqual(
20122017
[ComparableZipInfo(zi) for zi in zh.infolist()],
2013-
expected_zinfos,
2018+
[ComparableZipInfo(zi) for zi in expected_zinfos],
20142019
)
20152020

20162021
# check file size
@@ -2055,7 +2060,7 @@ def test_repack_removed_basic(self):
20552060
# check infolist
20562061
self.assertEqual(
20572062
[ComparableZipInfo(zi) for zi in zh.infolist()],
2058-
expected_zinfos,
2063+
[ComparableZipInfo(zi) for zi in expected_zinfos],
20592064
)
20602065

20612066
# check file size
@@ -2098,20 +2103,20 @@ def test_repack_removed_partial(self):
20982103
with zipfile.ZipFile(TESTFN) as zh:
20992104
self.assertIsNone(zh.testzip())
21002105

2106+
@mock.patch.object(time, 'time', new=lambda: 315504000) # fix time for ZipFile.writestr()
21012107
def test_repack_removed_bytes_between_files(self):
21022108
"""Should not remove bytes between local file entries."""
21032109
for ii in ([0], [1], [2]):
21042110
with self.subTest(removed=ii):
21052111
# calculate the expected results
2106-
expected_zinfos = []
21072112
with open(TESTFN, 'wb') as fh:
21082113
with zipfile.ZipFile(fh, 'w', self.compression) as zh:
21092114
for j, (file, data) in enumerate(self.test_files):
21102115
if j not in ii:
21112116
zh.writestr(file, data)
2112-
expected_zinfos.append(ComparableZipInfo(zh.getinfo(file)))
21132117
fh.write(b' dummy bytes ')
21142118
zh.start_dir = fh.tell()
2119+
expected_zinfos = list(zh.infolist())
21152120
expected_size = os.path.getsize(TESTFN)
21162121

21172122
# do the removal and check the result
@@ -2128,7 +2133,7 @@ def test_repack_removed_bytes_between_files(self):
21282133
# check infolist
21292134
self.assertEqual(
21302135
[ComparableZipInfo(zi) for zi in zh.infolist()],
2131-
expected_zinfos,
2136+
[ComparableZipInfo(zi) for zi in expected_zinfos],
21322137
)
21332138

21342139
# check file size
@@ -2184,7 +2189,7 @@ def test_repack_removed_prepended_bytes(self):
21842189
fh.write(b'dummy ')
21852190
fh.write(fz.read())
21862191
with zipfile.ZipFile(TESTFN) as zh:
2187-
expected_zinfos = [ComparableZipInfo(zi) for zi in zh.infolist()]
2192+
expected_zinfos = list(zh.infolist())
21882193
expected_size = os.path.getsize(TESTFN)
21892194

21902195
# do the removal and check the result
@@ -2201,7 +2206,7 @@ def test_repack_removed_prepended_bytes(self):
22012206
# check infolist
22022207
self.assertEqual(
22032208
[ComparableZipInfo(zi) for zi in zh.infolist()],
2204-
expected_zinfos,
2209+
[ComparableZipInfo(zi) for zi in expected_zinfos],
22052210
)
22062211

22072212
# check file size

0 commit comments

Comments
 (0)