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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zipremove
3
- Version: 0.4.1
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 `ZipFile.repack` afterwards to reclaim space.
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 `ZipFile.repack` afterwards to reclaim space.
21
+ Call `repack` afterwards to reclaim space.
22
22
 
23
23
  The archive must be opened with mode ``'w'``, ``'x'`` or ``'a'``.
24
24
 
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  name = zipremove
3
- version = 0.4.1
3
+ version = 0.5.0
4
4
  author = Danny Lin
5
5
  author_email = danny0838@gmail.com
6
6
  url = https://github.com/danny0838/zipremove
@@ -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.deepcopy(zinfo)
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: update zinfo2._end_offset if exists
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 are stored consecutively, with no gaps
117
- or overlaps.
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
- 4. This is to prevent an unexpected data removal (false positive),
133
- though a false negative may happen in certain rare cases.
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 ZipInfo
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: update ZipInfo._end_offset if exists
285
+ # polyfill: clear ZipInfo._end_offset if exists
287
286
  # (Python >= 3.8 with fix #109858)
288
287
  if hasattr(ZipInfo, '_end_offset'):
289
- end_offset = zfile.start_dir
290
- for zinfo in reversed(filelist):
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.4.1
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 `ZipFile.repack` afterwards to reclaim space.
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
- def ComparableZipInfo(zinfo):
46
- return (zinfo.filename, zinfo.header_offset, zinfo.compress_size, zinfo.CRC)
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
- zinfo = zh.getinfo(file)
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 = ('file.txt', zh.start_dir, *zinfos[i][2:])
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 j, zi in enumerate(zinfos)), zi_new],
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 = ('file.txt', zh.start_dir, *zinfos[i][2:])
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 j, zi in enumerate(zinfos)), zi_new],
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 = ('file.txt', zh.start_dir, *zinfos[i][2:])
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 j, zi in enumerate(zinfos)), zi_new],
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 = ('file.txt', zh.start_dir, *zinfos[i][2:])
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 j, zi in enumerate(zinfos)), zi_new],
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 = ('file2.txt', zh.start_dir, *zinfos[i][2:])
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 j, zi in enumerate(zinfos)), zi_new],
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 = [ComparableZipInfo(zi) for zi in zh.infolist()]
226
-
227
- zi_new = ('file.txt', zh.start_dir, *zinfos[0][2:])
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 j, zi in enumerate(zinfos)), zi_new],
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
- zh.remove(self.test_files[0][0])
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 = [ComparableZipInfo(zi) for zi in zh.infolist()]
250
-
251
- zi_new = ('file.txt', zh.start_dir, *zinfos[0][2:])
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 j, zi in enumerate(zinfos)), zi_new],
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
- zh.remove(self.test_files[0][0])
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 = [ComparableZipInfo(zi) for zi in zh.infolist()]
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 = [ComparableZipInfo(zi) for zi in zh.infolist()]
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 = [ComparableZipInfo(zi) for zi in zh.infolist()]
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 = [ComparableZipInfo(zi) for zi in zh.infolist()]
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 = [ComparableZipInfo(zi) for zi in zh.infolist()]
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 = [ComparableZipInfo(zi) for zi in zh.infolist()]
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 = [ComparableZipInfo(zi) for zi in zh.infolist()]
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