zipremove 0.4.1__tar.gz → 0.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {zipremove-0.4.1/src/zipremove.egg-info → zipremove-0.5.0}/PKG-INFO +2 -2
- {zipremove-0.4.1 → zipremove-0.5.0}/README.md +1 -1
- {zipremove-0.4.1 → zipremove-0.5.0}/setup.cfg +1 -1
- {zipremove-0.4.1 → zipremove-0.5.0}/src/zipremove/__init__.py +12 -19
- {zipremove-0.4.1 → zipremove-0.5.0/src/zipremove.egg-info}/PKG-INFO +2 -2
- {zipremove-0.4.1 → zipremove-0.5.0}/tests/test_zipfile.py +143 -60
- {zipremove-0.4.1 → zipremove-0.5.0}/LICENSE.txt +0 -0
- {zipremove-0.4.1 → zipremove-0.5.0}/pyproject.toml +0 -0
- {zipremove-0.4.1 → zipremove-0.5.0}/setup.py +0 -0
- {zipremove-0.4.1 → zipremove-0.5.0}/src/zipremove.egg-info/SOURCES.txt +0 -0
- {zipremove-0.4.1 → zipremove-0.5.0}/src/zipremove.egg-info/dependency_links.txt +0 -0
- {zipremove-0.4.1 → zipremove-0.5.0}/src/zipremove.egg-info/requires.txt +0 -0
- {zipremove-0.4.1 → zipremove-0.5.0}/src/zipremove.egg-info/top_level.txt +0 -0
- {zipremove-0.4.1 → zipremove-0.5.0}/tests/test_zipfile64.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: zipremove
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Extend `zipfile` with `remove`-related functionalities
|
|
5
5
|
Home-page: https://github.com/danny0838/zipremove
|
|
6
6
|
Author: Danny Lin
|
|
@@ -52,7 +52,7 @@ This package extends `zipfile` with `remove`-related functionalities.
|
|
|
52
52
|
a path is provided.
|
|
53
53
|
|
|
54
54
|
This does not physically remove the local file entry from the archive.
|
|
55
|
-
Call `
|
|
55
|
+
Call `repack` afterwards to reclaim space.
|
|
56
56
|
|
|
57
57
|
The archive must be opened with mode ``'w'``, ``'x'`` or ``'a'``.
|
|
58
58
|
|
|
@@ -18,7 +18,7 @@ This package extends `zipfile` with `remove`-related functionalities.
|
|
|
18
18
|
a path is provided.
|
|
19
19
|
|
|
20
20
|
This does not physically remove the local file entry from the archive.
|
|
21
|
-
Call `
|
|
21
|
+
Call `repack` afterwards to reclaim space.
|
|
22
22
|
|
|
23
23
|
The archive must be opened with mode ``'w'``, ``'x'`` or ``'a'``.
|
|
24
24
|
|
|
@@ -82,7 +82,7 @@ class _ZipRepacker:
|
|
|
82
82
|
|
|
83
83
|
def copy(self, zfile, zinfo, filename):
|
|
84
84
|
# make a copy of zinfo
|
|
85
|
-
zinfo2 = copy.
|
|
85
|
+
zinfo2 = copy.copy(zinfo)
|
|
86
86
|
|
|
87
87
|
# apply sanitized new filename as in `ZipInfo.__init__`
|
|
88
88
|
zinfo2.orig_filename = filename
|
|
@@ -90,7 +90,7 @@ class _ZipRepacker:
|
|
|
90
90
|
|
|
91
91
|
zinfo2.header_offset = zfile.start_dir
|
|
92
92
|
|
|
93
|
-
# polyfill:
|
|
93
|
+
# polyfill: clear zinfo2._end_offset if exists
|
|
94
94
|
# (Python >= 3.8 with fix #109858)
|
|
95
95
|
if hasattr(zinfo2, '_end_offset'):
|
|
96
96
|
zinfo2._end_offset = None
|
|
@@ -113,10 +113,9 @@ class _ZipRepacker:
|
|
|
113
113
|
"""
|
|
114
114
|
Repack the ZIP file, stripping unreferenced local file entries.
|
|
115
115
|
|
|
116
|
-
Assumes that local file entries
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
Behavior:
|
|
116
|
+
Assumes that local file entries (and the central directory, which is
|
|
117
|
+
mostly treated as the "last entry") are stored consecutively, with no
|
|
118
|
+
gaps or overlaps:
|
|
120
119
|
|
|
121
120
|
1. If any referenced entry overlaps with another, a `BadZipFile` error
|
|
122
121
|
is raised since safe repacking cannot be guaranteed.
|
|
@@ -129,8 +128,8 @@ class _ZipRepacker:
|
|
|
129
128
|
be a sequence of consecutive entries with no extra preceding bytes;
|
|
130
129
|
extra following bytes are preserved.
|
|
131
130
|
|
|
132
|
-
|
|
133
|
-
|
|
131
|
+
This is to prevent an unexpected data removal (false positive), though
|
|
132
|
+
a false negative may happen in certain rare cases.
|
|
134
133
|
|
|
135
134
|
Examples:
|
|
136
135
|
|
|
@@ -180,8 +179,8 @@ class _ZipRepacker:
|
|
|
180
179
|
- Modifies the ZIP file in place.
|
|
181
180
|
- Updates zfile.start_dir to account for removed data.
|
|
182
181
|
- Sets zfile._didModify to True.
|
|
183
|
-
- Updates header_offset and _end_offset of referenced
|
|
184
|
-
instances.
|
|
182
|
+
- Updates header_offset and clears _end_offset of referenced
|
|
183
|
+
ZipInfo instances.
|
|
185
184
|
|
|
186
185
|
Parameters:
|
|
187
186
|
zfile: A ZipFile object representing the archive to repack.
|
|
@@ -283,17 +282,11 @@ class _ZipRepacker:
|
|
|
283
282
|
zfile.start_dir -= entry_offset
|
|
284
283
|
zfile._didModify = True
|
|
285
284
|
|
|
286
|
-
# polyfill:
|
|
285
|
+
# polyfill: clear ZipInfo._end_offset if exists
|
|
287
286
|
# (Python >= 3.8 with fix #109858)
|
|
288
287
|
if hasattr(ZipInfo, '_end_offset'):
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
if zinfo in removed_zinfos:
|
|
292
|
-
zinfo._end_offset = None
|
|
293
|
-
else:
|
|
294
|
-
if zinfo._end_offset is not None:
|
|
295
|
-
zinfo._end_offset = end_offset
|
|
296
|
-
end_offset = zinfo.header_offset
|
|
288
|
+
for zinfo in filelist:
|
|
289
|
+
zinfo._end_offset = None
|
|
297
290
|
|
|
298
291
|
def _calc_initial_entry_offset(self, fp, data_offset):
|
|
299
292
|
checked_offsets = {}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: zipremove
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Extend `zipfile` with `remove`-related functionalities
|
|
5
5
|
Home-page: https://github.com/danny0838/zipremove
|
|
6
6
|
Author: Danny Lin
|
|
@@ -52,7 +52,7 @@ This package extends `zipfile` with `remove`-related functionalities.
|
|
|
52
52
|
a path is provided.
|
|
53
53
|
|
|
54
54
|
This does not physically remove the local file entry from the archive.
|
|
55
|
-
Call `
|
|
55
|
+
Call `repack` afterwards to reclaim space.
|
|
56
56
|
|
|
57
57
|
The archive must be opened with mode ``'w'``, ``'x'`` or ``'a'``.
|
|
58
58
|
|
|
@@ -4,6 +4,7 @@ import itertools
|
|
|
4
4
|
import os
|
|
5
5
|
import struct
|
|
6
6
|
import sys
|
|
7
|
+
import time
|
|
7
8
|
import unittest
|
|
8
9
|
import unittest.mock as mock
|
|
9
10
|
import warnings
|
|
@@ -42,8 +43,11 @@ def requires_zip64fix(reason='requires Python >= 3.11.4 for zip64 fix (#103861)'
|
|
|
42
43
|
return unittest.skipUnless(sys.version_info >= (3, 11, 4), reason)
|
|
43
44
|
|
|
44
45
|
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
class ComparableZipInfo:
|
|
47
|
+
keys = [i for i in zipfile.ZipInfo.__slots__ if not i.startswith('_')]
|
|
48
|
+
|
|
49
|
+
def __new__(cls, zinfo):
|
|
50
|
+
return {i: getattr(zinfo, i) for i in cls.keys}
|
|
47
51
|
|
|
48
52
|
_struct_pack = struct.pack
|
|
49
53
|
|
|
@@ -59,6 +63,8 @@ def struct_pack_no_dd_sig(fmt, *values):
|
|
|
59
63
|
|
|
60
64
|
class RepackHelperMixin:
|
|
61
65
|
"""Common helpers for remove and repack."""
|
|
66
|
+
maxDiff = 8192
|
|
67
|
+
|
|
62
68
|
@classmethod
|
|
63
69
|
def _prepare_test_files(cls):
|
|
64
70
|
return [
|
|
@@ -69,37 +75,48 @@ class RepackHelperMixin:
|
|
|
69
75
|
|
|
70
76
|
@classmethod
|
|
71
77
|
def _prepare_zip_from_test_files(cls, zfname, test_files, force_zip64=False):
|
|
72
|
-
zinfos = []
|
|
73
78
|
with zipfile.ZipFile(zfname, 'w', cls.compression) as zh:
|
|
74
79
|
for file, data in test_files:
|
|
75
80
|
with zh.open(file, 'w', force_zip64=force_zip64) as fh:
|
|
76
81
|
fh.write(data)
|
|
77
|
-
|
|
78
|
-
zinfos.append(ComparableZipInfo(zinfo))
|
|
79
|
-
return zinfos
|
|
82
|
+
return list(zh.infolist())
|
|
80
83
|
|
|
81
84
|
class AbstractCopyTests(RepackHelperMixin):
|
|
82
85
|
@classmethod
|
|
83
86
|
def setUpClass(cls):
|
|
84
87
|
cls.test_files = cls._prepare_test_files()
|
|
85
88
|
|
|
89
|
+
def tearDown(self):
|
|
90
|
+
unlink(TESTFN)
|
|
91
|
+
|
|
86
92
|
def test_copy_by_name(self):
|
|
87
93
|
for i in range(3):
|
|
88
94
|
with self.subTest(i=i, filename=self.test_files[i][0]):
|
|
89
95
|
zinfos = self._prepare_zip_from_test_files(TESTFN, self.test_files)
|
|
90
96
|
with zipfile.ZipFile(TESTFN, 'a', self.compression) as zh:
|
|
91
|
-
zi_new =
|
|
97
|
+
zi_new = {
|
|
98
|
+
**ComparableZipInfo(zinfos[i]),
|
|
99
|
+
'filename': 'file.txt',
|
|
100
|
+
'orig_filename': 'file.txt',
|
|
101
|
+
'header_offset': zh.start_dir,
|
|
102
|
+
}
|
|
92
103
|
zh.copy(self.test_files[i][0], 'file.txt')
|
|
93
104
|
|
|
94
105
|
# check infolist
|
|
95
106
|
self.assertEqual(
|
|
96
107
|
[ComparableZipInfo(zi) for zi in zh.infolist()],
|
|
97
|
-
[*(zi for
|
|
108
|
+
[*(ComparableZipInfo(zi) for zi in zinfos), zi_new],
|
|
98
109
|
)
|
|
99
110
|
|
|
100
111
|
# check NameToInfo cache
|
|
101
112
|
self.assertEqual(ComparableZipInfo(zh.getinfo('file.txt')), zi_new)
|
|
102
113
|
|
|
114
|
+
# check content
|
|
115
|
+
self.assertEqual(
|
|
116
|
+
zh.read(zi_new['filename']),
|
|
117
|
+
zh.read(zinfos[i].filename),
|
|
118
|
+
)
|
|
119
|
+
|
|
103
120
|
# make sure the zip file is still valid
|
|
104
121
|
with zipfile.ZipFile(TESTFN) as zh:
|
|
105
122
|
self.assertIsNone(zh.testzip())
|
|
@@ -109,18 +126,29 @@ class AbstractCopyTests(RepackHelperMixin):
|
|
|
109
126
|
with self.subTest(i=i, filename=self.test_files[i][0]):
|
|
110
127
|
zinfos = self._prepare_zip_from_test_files(TESTFN, self.test_files)
|
|
111
128
|
with zipfile.ZipFile(TESTFN, 'a', self.compression) as zh:
|
|
112
|
-
zi_new =
|
|
129
|
+
zi_new = {
|
|
130
|
+
**ComparableZipInfo(zinfos[i]),
|
|
131
|
+
'filename': 'file.txt',
|
|
132
|
+
'orig_filename': 'file.txt',
|
|
133
|
+
'header_offset': zh.start_dir,
|
|
134
|
+
}
|
|
113
135
|
zh.copy(zh.infolist()[i], 'file.txt')
|
|
114
136
|
|
|
115
137
|
# check infolist
|
|
116
138
|
self.assertEqual(
|
|
117
139
|
[ComparableZipInfo(zi) for zi in zh.infolist()],
|
|
118
|
-
[*(zi for
|
|
140
|
+
[*(ComparableZipInfo(zi) for zi in zinfos), zi_new],
|
|
119
141
|
)
|
|
120
142
|
|
|
121
143
|
# check NameToInfo cache
|
|
122
144
|
self.assertEqual(ComparableZipInfo(zh.getinfo('file.txt')), zi_new)
|
|
123
145
|
|
|
146
|
+
# check content
|
|
147
|
+
self.assertEqual(
|
|
148
|
+
zh.read(zi_new['filename']),
|
|
149
|
+
zh.read(zinfos[i].filename),
|
|
150
|
+
)
|
|
151
|
+
|
|
124
152
|
# make sure the zip file is still valid
|
|
125
153
|
with zipfile.ZipFile(TESTFN) as zh:
|
|
126
154
|
self.assertIsNone(zh.testzip())
|
|
@@ -130,18 +158,29 @@ class AbstractCopyTests(RepackHelperMixin):
|
|
|
130
158
|
with self.subTest(i=i, filename=self.test_files[i][0]):
|
|
131
159
|
zinfos = self._prepare_zip_from_test_files(TESTFN, self.test_files, force_zip64=True)
|
|
132
160
|
with zipfile.ZipFile(TESTFN, 'a', self.compression) as zh:
|
|
133
|
-
zi_new =
|
|
161
|
+
zi_new = {
|
|
162
|
+
**ComparableZipInfo(zinfos[i]),
|
|
163
|
+
'filename': 'file.txt',
|
|
164
|
+
'orig_filename': 'file.txt',
|
|
165
|
+
'header_offset': zh.start_dir,
|
|
166
|
+
}
|
|
134
167
|
zh.copy(self.test_files[i][0], 'file.txt')
|
|
135
168
|
|
|
136
169
|
# check infolist
|
|
137
170
|
self.assertEqual(
|
|
138
171
|
[ComparableZipInfo(zi) for zi in zh.infolist()],
|
|
139
|
-
[*(zi for
|
|
172
|
+
[*(ComparableZipInfo(zi) for zi in zinfos), zi_new],
|
|
140
173
|
)
|
|
141
174
|
|
|
142
175
|
# check NameToInfo cache
|
|
143
176
|
self.assertEqual(ComparableZipInfo(zh.getinfo('file.txt')), zi_new)
|
|
144
177
|
|
|
178
|
+
# check content
|
|
179
|
+
self.assertEqual(
|
|
180
|
+
zh.read(zi_new['filename']),
|
|
181
|
+
zh.read(zinfos[i].filename),
|
|
182
|
+
)
|
|
183
|
+
|
|
145
184
|
# make sure the zip file is still valid
|
|
146
185
|
with zipfile.ZipFile(TESTFN) as zh:
|
|
147
186
|
self.assertIsNone(zh.testzip())
|
|
@@ -152,18 +191,29 @@ class AbstractCopyTests(RepackHelperMixin):
|
|
|
152
191
|
with open(TESTFN, 'wb') as fh:
|
|
153
192
|
zinfos = self._prepare_zip_from_test_files(Unseekable(fh), self.test_files)
|
|
154
193
|
with zipfile.ZipFile(TESTFN, 'a', self.compression) as zh:
|
|
155
|
-
zi_new =
|
|
194
|
+
zi_new = {
|
|
195
|
+
**ComparableZipInfo(zinfos[i]),
|
|
196
|
+
'filename': 'file.txt',
|
|
197
|
+
'orig_filename': 'file.txt',
|
|
198
|
+
'header_offset': zh.start_dir,
|
|
199
|
+
}
|
|
156
200
|
zh.copy(self.test_files[i][0], 'file.txt')
|
|
157
201
|
|
|
158
202
|
# check infolist
|
|
159
203
|
self.assertEqual(
|
|
160
204
|
[ComparableZipInfo(zi) for zi in zh.infolist()],
|
|
161
|
-
[*(zi for
|
|
205
|
+
[*(ComparableZipInfo(zi) for zi in zinfos), zi_new],
|
|
162
206
|
)
|
|
163
207
|
|
|
164
208
|
# check NameToInfo cache
|
|
165
209
|
self.assertEqual(ComparableZipInfo(zh.getinfo('file.txt')), zi_new)
|
|
166
210
|
|
|
211
|
+
# check content
|
|
212
|
+
self.assertEqual(
|
|
213
|
+
zh.read(zi_new['filename']),
|
|
214
|
+
zh.read(zinfos[i].filename),
|
|
215
|
+
)
|
|
216
|
+
|
|
167
217
|
# make sure the zip file is still valid
|
|
168
218
|
with zipfile.ZipFile(TESTFN) as zh:
|
|
169
219
|
self.assertIsNone(zh.testzip())
|
|
@@ -173,18 +223,29 @@ class AbstractCopyTests(RepackHelperMixin):
|
|
|
173
223
|
with self.subTest(i=i, filename=self.test_files[i][0]):
|
|
174
224
|
zinfos = self._prepare_zip_from_test_files(TESTFN, self.test_files)
|
|
175
225
|
with zipfile.ZipFile(TESTFN, 'a', self.compression) as zh:
|
|
176
|
-
zi_new =
|
|
226
|
+
zi_new = {
|
|
227
|
+
**ComparableZipInfo(zinfos[i]),
|
|
228
|
+
'filename': 'file2.txt',
|
|
229
|
+
'orig_filename': 'file2.txt',
|
|
230
|
+
'header_offset': zh.start_dir,
|
|
231
|
+
}
|
|
177
232
|
zh.copy(self.test_files[i][0], 'file2.txt')
|
|
178
233
|
|
|
179
234
|
# check infolist
|
|
180
235
|
self.assertEqual(
|
|
181
236
|
[ComparableZipInfo(zi) for zi in zh.infolist()],
|
|
182
|
-
[*(zi for
|
|
237
|
+
[*(ComparableZipInfo(zi) for zi in zinfos), zi_new],
|
|
183
238
|
)
|
|
184
239
|
|
|
185
240
|
# check NameToInfo cache
|
|
186
241
|
self.assertEqual(ComparableZipInfo(zh.getinfo('file2.txt')), zi_new)
|
|
187
242
|
|
|
243
|
+
# check content
|
|
244
|
+
self.assertEqual(
|
|
245
|
+
zh.read(zi_new['filename']),
|
|
246
|
+
zh.read(zinfos[i].filename),
|
|
247
|
+
)
|
|
248
|
+
|
|
188
249
|
# make sure the zip file is still valid
|
|
189
250
|
with zipfile.ZipFile(TESTFN) as zh:
|
|
190
251
|
self.assertIsNone(zh.testzip())
|
|
@@ -222,44 +283,63 @@ class AbstractCopyTests(RepackHelperMixin):
|
|
|
222
283
|
with zipfile.ZipFile(TESTFN, 'w') as zh:
|
|
223
284
|
for file, data in self.test_files:
|
|
224
285
|
zh.writestr(file, data)
|
|
225
|
-
zinfos =
|
|
226
|
-
|
|
227
|
-
zi_new =
|
|
286
|
+
zinfos = list(zh.infolist())
|
|
287
|
+
|
|
288
|
+
zi_new = {
|
|
289
|
+
**ComparableZipInfo(zinfos[0]),
|
|
290
|
+
'filename': 'file.txt',
|
|
291
|
+
'orig_filename': 'file.txt',
|
|
292
|
+
'header_offset': zh.start_dir,
|
|
293
|
+
}
|
|
228
294
|
zh.copy(zh.infolist()[0], 'file.txt')
|
|
229
295
|
|
|
230
296
|
# check infolist
|
|
231
297
|
self.assertEqual(
|
|
232
298
|
[ComparableZipInfo(zi) for zi in zh.infolist()],
|
|
233
|
-
[*(zi for
|
|
299
|
+
[*(ComparableZipInfo(zi) for zi in zinfos), zi_new],
|
|
234
300
|
)
|
|
235
301
|
|
|
236
302
|
# check NameToInfo cache
|
|
237
303
|
self.assertEqual(ComparableZipInfo(zh.getinfo('file.txt')), zi_new)
|
|
238
|
-
|
|
304
|
+
|
|
305
|
+
# check content
|
|
306
|
+
self.assertEqual(
|
|
307
|
+
zh.read(zi_new['filename']),
|
|
308
|
+
zh.read(zinfos[0].filename),
|
|
309
|
+
)
|
|
239
310
|
|
|
240
311
|
# make sure the zip file is still valid
|
|
241
312
|
with zipfile.ZipFile(TESTFN) as zh:
|
|
242
313
|
self.assertIsNone(zh.testzip())
|
|
243
314
|
|
|
244
315
|
def test_copy_mode_x(self):
|
|
245
|
-
unlink(TESTFN)
|
|
246
316
|
with zipfile.ZipFile(TESTFN, 'x') as zh:
|
|
247
317
|
for file, data in self.test_files:
|
|
248
318
|
zh.writestr(file, data)
|
|
249
|
-
zinfos =
|
|
250
|
-
|
|
251
|
-
zi_new =
|
|
319
|
+
zinfos = list(zh.infolist())
|
|
320
|
+
|
|
321
|
+
zi_new = {
|
|
322
|
+
**ComparableZipInfo(zinfos[0]),
|
|
323
|
+
'filename': 'file.txt',
|
|
324
|
+
'orig_filename': 'file.txt',
|
|
325
|
+
'header_offset': zh.start_dir,
|
|
326
|
+
}
|
|
252
327
|
zh.copy(zh.infolist()[0], 'file.txt')
|
|
253
328
|
|
|
254
329
|
# check infolist
|
|
255
330
|
self.assertEqual(
|
|
256
331
|
[ComparableZipInfo(zi) for zi in zh.infolist()],
|
|
257
|
-
[*(zi for
|
|
332
|
+
[*(ComparableZipInfo(zi) for zi in zinfos), zi_new],
|
|
258
333
|
)
|
|
259
334
|
|
|
260
335
|
# check NameToInfo cache
|
|
261
336
|
self.assertEqual(ComparableZipInfo(zh.getinfo('file.txt')), zi_new)
|
|
262
|
-
|
|
337
|
+
|
|
338
|
+
# check content
|
|
339
|
+
self.assertEqual(
|
|
340
|
+
zh.read(zi_new['filename']),
|
|
341
|
+
zh.read(zinfos[0].filename),
|
|
342
|
+
)
|
|
263
343
|
|
|
264
344
|
# make sure the zip file is still valid
|
|
265
345
|
with zipfile.ZipFile(TESTFN) as zh:
|
|
@@ -302,7 +382,7 @@ class AbstractRemoveTests(RepackHelperMixin):
|
|
|
302
382
|
# check infolist
|
|
303
383
|
self.assertEqual(
|
|
304
384
|
[ComparableZipInfo(zi) for zi in zh.infolist()],
|
|
305
|
-
[zi for j, zi in enumerate(zinfos) if j != i],
|
|
385
|
+
[ComparableZipInfo(zi) for j, zi in enumerate(zinfos) if j != i],
|
|
306
386
|
)
|
|
307
387
|
|
|
308
388
|
# check NameToInfo cache
|
|
@@ -323,7 +403,7 @@ class AbstractRemoveTests(RepackHelperMixin):
|
|
|
323
403
|
# check infolist
|
|
324
404
|
self.assertEqual(
|
|
325
405
|
[ComparableZipInfo(zi) for zi in zh.infolist()],
|
|
326
|
-
[zi for j, zi in enumerate(zinfos) if j != i],
|
|
406
|
+
[ComparableZipInfo(zi) for j, zi in enumerate(zinfos) if j != i],
|
|
327
407
|
)
|
|
328
408
|
|
|
329
409
|
# check NameToInfo cache
|
|
@@ -364,13 +444,13 @@ class AbstractRemoveTests(RepackHelperMixin):
|
|
|
364
444
|
# check infolist
|
|
365
445
|
self.assertEqual(
|
|
366
446
|
[ComparableZipInfo(zi) for zi in zh.infolist()],
|
|
367
|
-
[zinfos[0], zinfos[2]],
|
|
447
|
+
[ComparableZipInfo(zi) for zi in [zinfos[0], zinfos[2]]],
|
|
368
448
|
)
|
|
369
449
|
|
|
370
450
|
# check NameToInfo cache
|
|
371
451
|
self.assertEqual(
|
|
372
452
|
ComparableZipInfo(zh.getinfo('file.txt')),
|
|
373
|
-
zinfos[0],
|
|
453
|
+
ComparableZipInfo(zinfos[0]),
|
|
374
454
|
)
|
|
375
455
|
|
|
376
456
|
# make sure the zip file is still valid
|
|
@@ -385,7 +465,7 @@ class AbstractRemoveTests(RepackHelperMixin):
|
|
|
385
465
|
# check infolist
|
|
386
466
|
self.assertEqual(
|
|
387
467
|
[ComparableZipInfo(zi) for zi in zh.infolist()],
|
|
388
|
-
[zinfos[2]],
|
|
468
|
+
[ComparableZipInfo(zi) for zi in [zinfos[2]]],
|
|
389
469
|
)
|
|
390
470
|
|
|
391
471
|
# check NameToInfo cache
|
|
@@ -414,13 +494,13 @@ class AbstractRemoveTests(RepackHelperMixin):
|
|
|
414
494
|
# check infolist
|
|
415
495
|
self.assertEqual(
|
|
416
496
|
[ComparableZipInfo(zi) for zi in zh.infolist()],
|
|
417
|
-
[zinfos[1], zinfos[2]],
|
|
497
|
+
[ComparableZipInfo(zi) for zi in [zinfos[1], zinfos[2]]],
|
|
418
498
|
)
|
|
419
499
|
|
|
420
500
|
# check NameToInfo cache
|
|
421
501
|
self.assertEqual(
|
|
422
502
|
ComparableZipInfo(zh.getinfo('file.txt')),
|
|
423
|
-
zinfos[1],
|
|
503
|
+
ComparableZipInfo(zinfos[1]),
|
|
424
504
|
)
|
|
425
505
|
|
|
426
506
|
# make sure the zip file is still valid
|
|
@@ -434,13 +514,13 @@ class AbstractRemoveTests(RepackHelperMixin):
|
|
|
434
514
|
# check infolist
|
|
435
515
|
self.assertEqual(
|
|
436
516
|
[ComparableZipInfo(zi) for zi in zh.infolist()],
|
|
437
|
-
[zinfos[0], zinfos[2]],
|
|
517
|
+
[ComparableZipInfo(zi) for zi in [zinfos[0], zinfos[2]]],
|
|
438
518
|
)
|
|
439
519
|
|
|
440
520
|
# check NameToInfo cache
|
|
441
521
|
self.assertEqual(
|
|
442
522
|
ComparableZipInfo(zh.getinfo('file.txt')),
|
|
443
|
-
zinfos[0],
|
|
523
|
+
ComparableZipInfo(zinfos[0]),
|
|
444
524
|
)
|
|
445
525
|
|
|
446
526
|
# make sure the zip file is still valid
|
|
@@ -456,7 +536,7 @@ class AbstractRemoveTests(RepackHelperMixin):
|
|
|
456
536
|
# check infolist
|
|
457
537
|
self.assertEqual(
|
|
458
538
|
[ComparableZipInfo(zi) for zi in zh.infolist()],
|
|
459
|
-
[zinfos[2]],
|
|
539
|
+
[ComparableZipInfo(zi) for zi in [zinfos[2]]],
|
|
460
540
|
)
|
|
461
541
|
|
|
462
542
|
# check NameToInfo cache
|
|
@@ -478,7 +558,7 @@ class AbstractRemoveTests(RepackHelperMixin):
|
|
|
478
558
|
# check infolist
|
|
479
559
|
self.assertEqual(
|
|
480
560
|
[ComparableZipInfo(zi) for zi in zh.infolist()],
|
|
481
|
-
[zi for j, zi in enumerate(zinfos) if j != i],
|
|
561
|
+
[ComparableZipInfo(zi) for j, zi in enumerate(zinfos) if j != i],
|
|
482
562
|
)
|
|
483
563
|
|
|
484
564
|
# check NameToInfo cache
|
|
@@ -513,14 +593,14 @@ class AbstractRemoveTests(RepackHelperMixin):
|
|
|
513
593
|
with zipfile.ZipFile(TESTFN, 'w') as zh:
|
|
514
594
|
for file, data in self.test_files:
|
|
515
595
|
zh.writestr(file, data)
|
|
516
|
-
zinfos =
|
|
596
|
+
zinfos = list(zh.infolist())
|
|
517
597
|
|
|
518
598
|
zh.remove(self.test_files[0][0])
|
|
519
599
|
|
|
520
600
|
# check infolist
|
|
521
601
|
self.assertEqual(
|
|
522
602
|
[ComparableZipInfo(zi) for zi in zh.infolist()],
|
|
523
|
-
[zinfos[1], zinfos[2]],
|
|
603
|
+
[ComparableZipInfo(zi) for zi in [zinfos[1], zinfos[2]]],
|
|
524
604
|
)
|
|
525
605
|
|
|
526
606
|
# check NameToInfo cache
|
|
@@ -535,14 +615,14 @@ class AbstractRemoveTests(RepackHelperMixin):
|
|
|
535
615
|
with zipfile.ZipFile(TESTFN, 'x') as zh:
|
|
536
616
|
for file, data in self.test_files:
|
|
537
617
|
zh.writestr(file, data)
|
|
538
|
-
zinfos =
|
|
618
|
+
zinfos = list(zh.infolist())
|
|
539
619
|
|
|
540
620
|
zh.remove(self.test_files[0][0])
|
|
541
621
|
|
|
542
622
|
# check infolist
|
|
543
623
|
self.assertEqual(
|
|
544
624
|
[ComparableZipInfo(zi) for zi in zh.infolist()],
|
|
545
|
-
[zinfos[1], zinfos[2]],
|
|
625
|
+
[ComparableZipInfo(zi) for zi in [zinfos[1], zinfos[2]]],
|
|
546
626
|
)
|
|
547
627
|
|
|
548
628
|
# check NameToInfo cache
|
|
@@ -601,7 +681,7 @@ class AbstractRepackTests(RepackHelperMixin):
|
|
|
601
681
|
# check infolist
|
|
602
682
|
self.assertEqual(
|
|
603
683
|
[ComparableZipInfo(zi) for zi in zh.infolist()],
|
|
604
|
-
expected_zinfos,
|
|
684
|
+
[ComparableZipInfo(zi) for zi in expected_zinfos],
|
|
605
685
|
)
|
|
606
686
|
|
|
607
687
|
# check file size
|
|
@@ -653,7 +733,7 @@ class AbstractRepackTests(RepackHelperMixin):
|
|
|
653
733
|
# check infolist
|
|
654
734
|
self.assertEqual(
|
|
655
735
|
[ComparableZipInfo(zi) for zi in zh.infolist()],
|
|
656
|
-
expected_zinfos,
|
|
736
|
+
[ComparableZipInfo(zi) for zi in expected_zinfos],
|
|
657
737
|
)
|
|
658
738
|
|
|
659
739
|
# check file size
|
|
@@ -687,7 +767,7 @@ class AbstractRepackTests(RepackHelperMixin):
|
|
|
687
767
|
# check infolist
|
|
688
768
|
self.assertEqual(
|
|
689
769
|
[ComparableZipInfo(zi) for zi in zh.infolist()],
|
|
690
|
-
expected_zinfos,
|
|
770
|
+
[ComparableZipInfo(zi) for zi in expected_zinfos],
|
|
691
771
|
)
|
|
692
772
|
|
|
693
773
|
# check file size
|
|
@@ -733,7 +813,7 @@ class AbstractRepackTests(RepackHelperMixin):
|
|
|
733
813
|
# check infolist
|
|
734
814
|
self.assertEqual(
|
|
735
815
|
[ComparableZipInfo(zi) for zi in zh.infolist()],
|
|
736
|
-
expected_zinfos,
|
|
816
|
+
[ComparableZipInfo(zi) for zi in expected_zinfos],
|
|
737
817
|
)
|
|
738
818
|
|
|
739
819
|
# check file size
|
|
@@ -743,6 +823,7 @@ class AbstractRepackTests(RepackHelperMixin):
|
|
|
743
823
|
with zipfile.ZipFile(TESTFN) as zh:
|
|
744
824
|
self.assertIsNone(zh.testzip())
|
|
745
825
|
|
|
826
|
+
@mock.patch.object(time, 'time', new=lambda: 315504000) # fix time for ZipFile.writestr()
|
|
746
827
|
def test_repack_bytes_before_removed_files(self):
|
|
747
828
|
"""Should preserve if there are bytes before stale local file entries."""
|
|
748
829
|
for ii in ([1], [1, 2], [2]):
|
|
@@ -757,7 +838,7 @@ class AbstractRepackTests(RepackHelperMixin):
|
|
|
757
838
|
zh.writestr(file, data)
|
|
758
839
|
for i in ii:
|
|
759
840
|
zh.remove(self.test_files[i][0])
|
|
760
|
-
expected_zinfos =
|
|
841
|
+
expected_zinfos = list(zh.infolist())
|
|
761
842
|
expected_size = os.path.getsize(TESTFN)
|
|
762
843
|
|
|
763
844
|
# do the removal and check the result
|
|
@@ -776,7 +857,7 @@ class AbstractRepackTests(RepackHelperMixin):
|
|
|
776
857
|
# check infolist
|
|
777
858
|
self.assertEqual(
|
|
778
859
|
[ComparableZipInfo(zi) for zi in zh.infolist()],
|
|
779
|
-
expected_zinfos,
|
|
860
|
+
[ComparableZipInfo(zi) for zi in expected_zinfos],
|
|
780
861
|
)
|
|
781
862
|
|
|
782
863
|
# check file size
|
|
@@ -786,6 +867,7 @@ class AbstractRepackTests(RepackHelperMixin):
|
|
|
786
867
|
with zipfile.ZipFile(TESTFN) as zh:
|
|
787
868
|
self.assertIsNone(zh.testzip())
|
|
788
869
|
|
|
870
|
+
@mock.patch.object(time, 'time', new=lambda: 315504000) # fix time for ZipFile.writestr()
|
|
789
871
|
def test_repack_bytes_after_removed_files(self):
|
|
790
872
|
"""Should keep extra bytes if there are bytes after stale local file entries."""
|
|
791
873
|
for ii in ([1], [1, 2], [2]):
|
|
@@ -799,7 +881,7 @@ class AbstractRepackTests(RepackHelperMixin):
|
|
|
799
881
|
if i == ii[-1]:
|
|
800
882
|
fh.write(b' dummy bytes ')
|
|
801
883
|
zh.start_dir = fh.tell()
|
|
802
|
-
expected_zinfos =
|
|
884
|
+
expected_zinfos = list(zh.infolist())
|
|
803
885
|
expected_size = os.path.getsize(TESTFN)
|
|
804
886
|
|
|
805
887
|
# do the removal and check the result
|
|
@@ -818,7 +900,7 @@ class AbstractRepackTests(RepackHelperMixin):
|
|
|
818
900
|
# check infolist
|
|
819
901
|
self.assertEqual(
|
|
820
902
|
[ComparableZipInfo(zi) for zi in zh.infolist()],
|
|
821
|
-
expected_zinfos,
|
|
903
|
+
[ComparableZipInfo(zi) for zi in expected_zinfos],
|
|
822
904
|
)
|
|
823
905
|
|
|
824
906
|
# check file size
|
|
@@ -828,6 +910,7 @@ class AbstractRepackTests(RepackHelperMixin):
|
|
|
828
910
|
with zipfile.ZipFile(TESTFN) as zh:
|
|
829
911
|
self.assertIsNone(zh.testzip())
|
|
830
912
|
|
|
913
|
+
@mock.patch.object(time, 'time', new=lambda: 315504000) # fix time for ZipFile.writestr()
|
|
831
914
|
def test_repack_bytes_between_removed_files(self):
|
|
832
915
|
"""Should strip only local file entries before random bytes."""
|
|
833
916
|
# calculate the expected results
|
|
@@ -838,7 +921,7 @@ class AbstractRepackTests(RepackHelperMixin):
|
|
|
838
921
|
zh.start_dir = fh.tell()
|
|
839
922
|
zh.writestr(*self.test_files[2])
|
|
840
923
|
zh.remove(self.test_files[2][0])
|
|
841
|
-
expected_zinfos =
|
|
924
|
+
expected_zinfos = list(zh.infolist())
|
|
842
925
|
expected_size = os.path.getsize(TESTFN)
|
|
843
926
|
|
|
844
927
|
# do the removal and check the result
|
|
@@ -857,7 +940,7 @@ class AbstractRepackTests(RepackHelperMixin):
|
|
|
857
940
|
# check infolist
|
|
858
941
|
self.assertEqual(
|
|
859
942
|
[ComparableZipInfo(zi) for zi in zh.infolist()],
|
|
860
|
-
expected_zinfos,
|
|
943
|
+
[ComparableZipInfo(zi) for zi in expected_zinfos],
|
|
861
944
|
)
|
|
862
945
|
|
|
863
946
|
# check file size
|
|
@@ -879,7 +962,7 @@ class AbstractRepackTests(RepackHelperMixin):
|
|
|
879
962
|
fh.write(b'dummy ')
|
|
880
963
|
fh.write(fz.read())
|
|
881
964
|
with zipfile.ZipFile(TESTFN) as zh:
|
|
882
|
-
expected_zinfos =
|
|
965
|
+
expected_zinfos = list(zh.infolist())
|
|
883
966
|
expected_size = os.path.getsize(TESTFN)
|
|
884
967
|
|
|
885
968
|
# do the removal and check the result
|
|
@@ -897,7 +980,7 @@ class AbstractRepackTests(RepackHelperMixin):
|
|
|
897
980
|
# check infolist
|
|
898
981
|
self.assertEqual(
|
|
899
982
|
[ComparableZipInfo(zi) for zi in zh.infolist()],
|
|
900
|
-
expected_zinfos,
|
|
983
|
+
[ComparableZipInfo(zi) for zi in expected_zinfos],
|
|
901
984
|
)
|
|
902
985
|
|
|
903
986
|
# check file size
|
|
@@ -942,7 +1025,7 @@ class AbstractRepackTests(RepackHelperMixin):
|
|
|
942
1025
|
# check infolist
|
|
943
1026
|
self.assertEqual(
|
|
944
1027
|
[ComparableZipInfo(zi) for zi in zh.infolist()],
|
|
945
|
-
expected_zinfos,
|
|
1028
|
+
[ComparableZipInfo(zi) for zi in expected_zinfos],
|
|
946
1029
|
)
|
|
947
1030
|
|
|
948
1031
|
# check file size
|
|
@@ -985,20 +1068,20 @@ class AbstractRepackTests(RepackHelperMixin):
|
|
|
985
1068
|
with zipfile.ZipFile(TESTFN) as zh:
|
|
986
1069
|
self.assertIsNone(zh.testzip())
|
|
987
1070
|
|
|
1071
|
+
@mock.patch.object(time, 'time', new=lambda: 315504000) # fix time for ZipFile.writestr()
|
|
988
1072
|
def test_repack_removed_bytes_between_files(self):
|
|
989
1073
|
"""Should not remove bytes between local file entries."""
|
|
990
1074
|
for ii in ([0], [1], [2]):
|
|
991
1075
|
with self.subTest(removed=ii):
|
|
992
1076
|
# calculate the expected results
|
|
993
|
-
expected_zinfos = []
|
|
994
1077
|
with open(TESTFN, 'wb') as fh:
|
|
995
1078
|
with zipfile.ZipFile(fh, 'w', self.compression) as zh:
|
|
996
1079
|
for j, (file, data) in enumerate(self.test_files):
|
|
997
1080
|
if j not in ii:
|
|
998
1081
|
zh.writestr(file, data)
|
|
999
|
-
expected_zinfos.append(ComparableZipInfo(zh.getinfo(file)))
|
|
1000
1082
|
fh.write(b' dummy bytes ')
|
|
1001
1083
|
zh.start_dir = fh.tell()
|
|
1084
|
+
expected_zinfos = list(zh.infolist())
|
|
1002
1085
|
expected_size = os.path.getsize(TESTFN)
|
|
1003
1086
|
|
|
1004
1087
|
# do the removal and check the result
|
|
@@ -1015,7 +1098,7 @@ class AbstractRepackTests(RepackHelperMixin):
|
|
|
1015
1098
|
# check infolist
|
|
1016
1099
|
self.assertEqual(
|
|
1017
1100
|
[ComparableZipInfo(zi) for zi in zh.infolist()],
|
|
1018
|
-
expected_zinfos,
|
|
1101
|
+
[ComparableZipInfo(zi) for zi in expected_zinfos],
|
|
1019
1102
|
)
|
|
1020
1103
|
|
|
1021
1104
|
# check file size
|
|
@@ -1071,7 +1154,7 @@ class AbstractRepackTests(RepackHelperMixin):
|
|
|
1071
1154
|
fh.write(b'dummy ')
|
|
1072
1155
|
fh.write(fz.read())
|
|
1073
1156
|
with zipfile.ZipFile(TESTFN) as zh:
|
|
1074
|
-
expected_zinfos =
|
|
1157
|
+
expected_zinfos = list(zh.infolist())
|
|
1075
1158
|
expected_size = os.path.getsize(TESTFN)
|
|
1076
1159
|
|
|
1077
1160
|
# do the removal and check the result
|
|
@@ -1088,7 +1171,7 @@ class AbstractRepackTests(RepackHelperMixin):
|
|
|
1088
1171
|
# check infolist
|
|
1089
1172
|
self.assertEqual(
|
|
1090
1173
|
[ComparableZipInfo(zi) for zi in zh.infolist()],
|
|
1091
|
-
expected_zinfos,
|
|
1174
|
+
[ComparableZipInfo(zi) for zi in expected_zinfos],
|
|
1092
1175
|
)
|
|
1093
1176
|
|
|
1094
1177
|
# check file size
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|