blob: 4c20bfd7e2cd7d259d49e95f0005ff1869485049 [file] [log] [blame]
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02001import contextlib
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002import importlib.util
Ezio Melotti74c96ec2009-07-08 22:24:06 +00003import io
Daniel Hillierda6ce582019-10-29 18:24:18 +11004import itertools
Ezio Melotti74c96ec2009-07-08 22:24:06 +00005import os
Serhiy Storchaka8606e952017-03-08 14:37:51 +02006import pathlib
Serhiy Storchaka503f9082016-02-08 00:02:25 +02007import posixpath
Ezio Melotti74c96ec2009-07-08 22:24:06 +00008import struct
Gregory P. Smith3f4db4a2019-09-10 17:14:11 +01009import subprocess
10import sys
Jason R. Coombsb2758ff2019-05-08 09:45:06 -040011import time
Ezio Melotti74c96ec2009-07-08 22:24:06 +000012import unittest
Berker Peksag2f1b8572019-09-12 17:13:44 +030013import unittest.mock as mock
Jason R. Coombsb2758ff2019-05-08 09:45:06 -040014import zipfile
Ezio Melotti74c96ec2009-07-08 22:24:06 +000015
Tim Petersa45cacf2004-08-20 03:47:14 +000016
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +000017from tempfile import TemporaryFile
Serhiy Storchakafa6bc292013-07-22 21:00:11 +030018from random import randint, random, getrandbits
Tim Petersa19a1682001-03-29 04:36:09 +000019
Serhiy Storchaka61c4c442016-10-23 13:07:59 +030020from test.support import script_helper
Serhiy Storchaka8606e952017-03-08 14:37:51 +020021from test.support import (TESTFN, findfile, unlink, rmtree, temp_dir, temp_cwd,
Serhiy Storchakac5b75db2013-01-29 20:14:08 +020022 requires_zlib, requires_bz2, requires_lzma,
Victor Stinnerd6debb22017-03-27 16:05:26 +020023 captured_stdout)
Guido van Rossum368f04a2000-04-10 13:23:04 +000024
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +000025TESTFN2 = TESTFN + "2"
Martin v. Löwis59e47792009-01-24 14:10:07 +000026TESTFNDIR = TESTFN + "d"
Guido van Rossumb5a755e2007-07-18 18:15:48 +000027FIXEDTEST_SIZE = 1000
Georg Brandl5ba11de2011-01-01 10:09:32 +000028DATAFILES_DIR = 'zipfile_datafiles'
Guido van Rossum368f04a2000-04-10 13:23:04 +000029
Christian Heimes790c8232008-01-07 21:14:23 +000030SMALL_TEST_DATA = [('_ziptest1', '1q2w3e4r5t'),
31 ('ziptest2dir/_ziptest2', 'qawsedrftg'),
Gregory P. Smithb47acbf2013-02-01 11:22:43 -080032 ('ziptest2dir/ziptest3dir/_ziptest3', 'azsxdcfvgb'),
Christian Heimes790c8232008-01-07 21:14:23 +000033 ('ziptest2dir/ziptest3dir/ziptest4dir/_ziptest3', '6y7u8i9o0p')]
34
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +020035def getrandbytes(size):
36 return getrandbits(8 * size).to_bytes(size, 'little')
37
Serhiy Storchakafa6bc292013-07-22 21:00:11 +030038def get_files(test):
39 yield TESTFN2
40 with TemporaryFile() as f:
41 yield f
42 test.assertFalse(f.closed)
43 with io.BytesIO() as f:
44 yield f
45 test.assertFalse(f.closed)
Ezio Melotti76430242009-07-11 18:28:48 +000046
Serhiy Storchakafa6bc292013-07-22 21:00:11 +030047class AbstractTestsWithSourceFile:
48 @classmethod
49 def setUpClass(cls):
50 cls.line_gen = [bytes("Zipfile test line %d. random float: %f\n" %
51 (i, random()), "ascii")
52 for i in range(FIXEDTEST_SIZE)]
53 cls.data = b''.join(cls.line_gen)
54
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +000055 def setUp(self):
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +000056 # Make a source file with some lines
Ezio Melotti35386712009-12-31 13:22:41 +000057 with open(TESTFN, "wb") as fp:
58 fp.write(self.data)
Tim Peters7d3bad62001-04-04 18:56:49 +000059
Bo Baylesce237c72018-01-29 23:54:07 -060060 def make_test_archive(self, f, compression, compresslevel=None):
61 kwargs = {'compression': compression, 'compresslevel': compresslevel}
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +000062 # Create the ZIP archive
Bo Baylesce237c72018-01-29 23:54:07 -060063 with zipfile.ZipFile(f, "w", **kwargs) as zipfp:
Ezio Melottifaa6b7f2009-12-30 12:34:59 +000064 zipfp.write(TESTFN, "another.name")
65 zipfp.write(TESTFN, TESTFN)
66 zipfp.writestr("strfile", self.data)
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +030067 with zipfp.open('written-open-w', mode='w') as f:
68 for line in self.line_gen:
69 f.write(line)
Tim Peters7d3bad62001-04-04 18:56:49 +000070
Bo Baylesce237c72018-01-29 23:54:07 -060071 def zip_test(self, f, compression, compresslevel=None):
72 self.make_test_archive(f, compression, compresslevel)
Guido van Rossumd8faa362007-04-27 19:54:29 +000073
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +000074 # Read the ZIP archive
Ezio Melottifaa6b7f2009-12-30 12:34:59 +000075 with zipfile.ZipFile(f, "r", compression) as zipfp:
76 self.assertEqual(zipfp.read(TESTFN), self.data)
77 self.assertEqual(zipfp.read("another.name"), self.data)
78 self.assertEqual(zipfp.read("strfile"), self.data)
Thomas Wouters0e3f5912006-08-11 14:57:12 +000079
Ezio Melottifaa6b7f2009-12-30 12:34:59 +000080 # Print the ZIP directory
81 fp = io.StringIO()
82 zipfp.printdir(file=fp)
83 directory = fp.getvalue()
84 lines = directory.splitlines()
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +030085 self.assertEqual(len(lines), 5) # Number of files + header
Thomas Wouters0e3f5912006-08-11 14:57:12 +000086
Benjamin Peterson577473f2010-01-19 00:09:57 +000087 self.assertIn('File Name', lines[0])
88 self.assertIn('Modified', lines[0])
89 self.assertIn('Size', lines[0])
Thomas Wouters0e3f5912006-08-11 14:57:12 +000090
Ezio Melotti35386712009-12-31 13:22:41 +000091 fn, date, time_, size = lines[1].split()
92 self.assertEqual(fn, 'another.name')
93 self.assertTrue(time.strptime(date, '%Y-%m-%d'))
94 self.assertTrue(time.strptime(time_, '%H:%M:%S'))
95 self.assertEqual(size, str(len(self.data)))
Thomas Wouters0e3f5912006-08-11 14:57:12 +000096
Ezio Melottifaa6b7f2009-12-30 12:34:59 +000097 # Check the namelist
98 names = zipfp.namelist()
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +030099 self.assertEqual(len(names), 4)
Benjamin Peterson577473f2010-01-19 00:09:57 +0000100 self.assertIn(TESTFN, names)
101 self.assertIn("another.name", names)
102 self.assertIn("strfile", names)
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +0300103 self.assertIn("written-open-w", names)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000104
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000105 # Check infolist
106 infos = zipfp.infolist()
Ezio Melotti35386712009-12-31 13:22:41 +0000107 names = [i.filename for i in infos]
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +0300108 self.assertEqual(len(names), 4)
Benjamin Peterson577473f2010-01-19 00:09:57 +0000109 self.assertIn(TESTFN, names)
110 self.assertIn("another.name", names)
111 self.assertIn("strfile", names)
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +0300112 self.assertIn("written-open-w", names)
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000113 for i in infos:
Ezio Melotti35386712009-12-31 13:22:41 +0000114 self.assertEqual(i.file_size, len(self.data))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000115
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000116 # check getinfo
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +0300117 for nm in (TESTFN, "another.name", "strfile", "written-open-w"):
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000118 info = zipfp.getinfo(nm)
Ezio Melotti35386712009-12-31 13:22:41 +0000119 self.assertEqual(info.filename, nm)
120 self.assertEqual(info.file_size, len(self.data))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000121
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000122 # Check that testzip doesn't raise an exception
123 zipfp.testzip()
Tim Peters7d3bad62001-04-04 18:56:49 +0000124
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300125 def test_basic(self):
126 for f in get_files(self):
127 self.zip_test(f, self.compression)
Raymond Hettingerc0fac962003-06-27 22:25:03 +0000128
Ezio Melottiafd0d112009-07-15 17:17:17 +0000129 def zip_open_test(self, f, compression):
130 self.make_test_archive(f, compression)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000131
132 # Read the ZIP archive
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000133 with zipfile.ZipFile(f, "r", compression) as zipfp:
134 zipdata1 = []
Brian Curtin8fb9b862010-11-18 02:15:28 +0000135 with zipfp.open(TESTFN) as zipopen1:
136 while True:
137 read_data = zipopen1.read(256)
138 if not read_data:
139 break
140 zipdata1.append(read_data)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000141
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000142 zipdata2 = []
Brian Curtin8fb9b862010-11-18 02:15:28 +0000143 with zipfp.open("another.name") as zipopen2:
144 while True:
145 read_data = zipopen2.read(256)
146 if not read_data:
147 break
148 zipdata2.append(read_data)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000149
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000150 self.assertEqual(b''.join(zipdata1), self.data)
151 self.assertEqual(b''.join(zipdata2), self.data)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000152
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300153 def test_open(self):
154 for f in get_files(self):
155 self.zip_open_test(f, self.compression)
Georg Brandlb533e262008-05-25 18:19:30 +0000156
Serhiy Storchaka8606e952017-03-08 14:37:51 +0200157 def test_open_with_pathlike(self):
158 path = pathlib.Path(TESTFN2)
159 self.zip_open_test(path, self.compression)
160 with zipfile.ZipFile(path, "r", self.compression) as zipfp:
161 self.assertIsInstance(zipfp.filename, str)
162
Ezio Melottiafd0d112009-07-15 17:17:17 +0000163 def zip_random_open_test(self, f, compression):
164 self.make_test_archive(f, compression)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000165
166 # Read the ZIP archive
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000167 with zipfile.ZipFile(f, "r", compression) as zipfp:
168 zipdata1 = []
Brian Curtin8fb9b862010-11-18 02:15:28 +0000169 with zipfp.open(TESTFN) as zipopen1:
170 while True:
171 read_data = zipopen1.read(randint(1, 1024))
172 if not read_data:
173 break
174 zipdata1.append(read_data)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000175
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000176 self.assertEqual(b''.join(zipdata1), self.data)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000177
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300178 def test_random_open(self):
179 for f in get_files(self):
180 self.zip_random_open_test(f, self.compression)
Antoine Pitroua32f9a22010-01-27 21:18:57 +0000181
Serhiy Storchakad2c07a52013-09-27 22:11:57 +0300182 def zip_read1_test(self, f, compression):
183 self.make_test_archive(f, compression)
184
185 # Read the ZIP archive
186 with zipfile.ZipFile(f, "r") as zipfp, \
187 zipfp.open(TESTFN) as zipopen:
188 zipdata = []
189 while True:
190 read_data = zipopen.read1(-1)
191 if not read_data:
192 break
193 zipdata.append(read_data)
194
195 self.assertEqual(b''.join(zipdata), self.data)
196
197 def test_read1(self):
198 for f in get_files(self):
199 self.zip_read1_test(f, self.compression)
200
201 def zip_read1_10_test(self, f, compression):
202 self.make_test_archive(f, compression)
203
204 # Read the ZIP archive
205 with zipfile.ZipFile(f, "r") as zipfp, \
206 zipfp.open(TESTFN) as zipopen:
207 zipdata = []
208 while True:
209 read_data = zipopen.read1(10)
210 self.assertLessEqual(len(read_data), 10)
211 if not read_data:
212 break
213 zipdata.append(read_data)
214
215 self.assertEqual(b''.join(zipdata), self.data)
216
217 def test_read1_10(self):
218 for f in get_files(self):
219 self.zip_read1_10_test(f, self.compression)
220
Antoine Pitroua32f9a22010-01-27 21:18:57 +0000221 def zip_readline_read_test(self, f, compression):
222 self.make_test_archive(f, compression)
223
224 # Read the ZIP archive
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300225 with zipfile.ZipFile(f, "r") as zipfp, \
226 zipfp.open(TESTFN) as zipopen:
Brian Curtin8fb9b862010-11-18 02:15:28 +0000227 data = b''
228 while True:
229 read = zipopen.readline()
230 if not read:
231 break
232 data += read
Antoine Pitroua32f9a22010-01-27 21:18:57 +0000233
Brian Curtin8fb9b862010-11-18 02:15:28 +0000234 read = zipopen.read(100)
235 if not read:
236 break
237 data += read
Antoine Pitroua32f9a22010-01-27 21:18:57 +0000238
239 self.assertEqual(data, self.data)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300240
241 def test_readline_read(self):
242 # Issue #7610: calls to readline() interleaved with calls to read().
243 for f in get_files(self):
244 self.zip_readline_read_test(f, self.compression)
Antoine Pitroua32f9a22010-01-27 21:18:57 +0000245
Ezio Melottiafd0d112009-07-15 17:17:17 +0000246 def zip_readline_test(self, f, compression):
247 self.make_test_archive(f, compression)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000248
249 # Read the ZIP archive
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000250 with zipfile.ZipFile(f, "r") as zipfp:
Brian Curtin8fb9b862010-11-18 02:15:28 +0000251 with zipfp.open(TESTFN) as zipopen:
252 for line in self.line_gen:
253 linedata = zipopen.readline()
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300254 self.assertEqual(linedata, line)
255
256 def test_readline(self):
257 for f in get_files(self):
258 self.zip_readline_test(f, self.compression)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000259
Ezio Melottiafd0d112009-07-15 17:17:17 +0000260 def zip_readlines_test(self, f, compression):
261 self.make_test_archive(f, compression)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000262
263 # Read the ZIP archive
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000264 with zipfile.ZipFile(f, "r") as zipfp:
Brian Curtin8fb9b862010-11-18 02:15:28 +0000265 with zipfp.open(TESTFN) as zipopen:
266 ziplines = zipopen.readlines()
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000267 for line, zipline in zip(self.line_gen, ziplines):
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300268 self.assertEqual(zipline, line)
269
270 def test_readlines(self):
271 for f in get_files(self):
272 self.zip_readlines_test(f, self.compression)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000273
Ezio Melottiafd0d112009-07-15 17:17:17 +0000274 def zip_iterlines_test(self, f, compression):
275 self.make_test_archive(f, compression)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000276
277 # Read the ZIP archive
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000278 with zipfile.ZipFile(f, "r") as zipfp:
Brian Curtin8fb9b862010-11-18 02:15:28 +0000279 with zipfp.open(TESTFN) as zipopen:
280 for line, zipline in zip(self.line_gen, zipopen):
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300281 self.assertEqual(zipline, line)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000282
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300283 def test_iterlines(self):
284 for f in get_files(self):
285 self.zip_iterlines_test(f, self.compression)
Antoine Pitroua32f9a22010-01-27 21:18:57 +0000286
Ezio Melottiafd0d112009-07-15 17:17:17 +0000287 def test_low_compression(self):
Ezio Melotti35386712009-12-31 13:22:41 +0000288 """Check for cases where compressed data is larger than original."""
Ezio Melotti74c96ec2009-07-08 22:24:06 +0000289 # Create the ZIP archive
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300290 with zipfile.ZipFile(TESTFN2, "w", self.compression) as zipfp:
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000291 zipfp.writestr("strfile", '12')
Ezio Melotti74c96ec2009-07-08 22:24:06 +0000292
293 # Get an open object for strfile
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300294 with zipfile.ZipFile(TESTFN2, "r", self.compression) as zipfp:
Brian Curtin8fb9b862010-11-18 02:15:28 +0000295 with zipfp.open("strfile") as openobj:
296 self.assertEqual(openobj.read(1), b'1')
297 self.assertEqual(openobj.read(1), b'2')
Ezio Melotti74c96ec2009-07-08 22:24:06 +0000298
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300299 def test_writestr_compression(self):
300 zipfp = zipfile.ZipFile(TESTFN2, "w")
301 zipfp.writestr("b.txt", "hello world", compress_type=self.compression)
302 info = zipfp.getinfo('b.txt')
303 self.assertEqual(info.compress_type, self.compression)
Martin v. Löwisf6b16a42012-05-01 07:58:44 +0200304
Bo Baylesce237c72018-01-29 23:54:07 -0600305 def test_writestr_compresslevel(self):
306 zipfp = zipfile.ZipFile(TESTFN2, "w", compresslevel=1)
307 zipfp.writestr("a.txt", "hello world", compress_type=self.compression)
308 zipfp.writestr("b.txt", "hello world", compress_type=self.compression,
309 compresslevel=2)
310
311 # Compression level follows the constructor.
312 a_info = zipfp.getinfo('a.txt')
313 self.assertEqual(a_info.compress_type, self.compression)
314 self.assertEqual(a_info._compresslevel, 1)
315
316 # Compression level is overridden.
317 b_info = zipfp.getinfo('b.txt')
318 self.assertEqual(b_info.compress_type, self.compression)
319 self.assertEqual(b_info._compresslevel, 2)
320
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300321 def test_read_return_size(self):
322 # Issue #9837: ZipExtFile.read() shouldn't return more bytes
323 # than requested.
324 for test_size in (1, 4095, 4096, 4097, 16384):
325 file_size = test_size + 1
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +0200326 junk = getrandbytes(file_size)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300327 with zipfile.ZipFile(io.BytesIO(), "w", self.compression) as zipf:
328 zipf.writestr('foo', junk)
329 with zipf.open('foo', 'r') as fp:
330 buf = fp.read(test_size)
331 self.assertEqual(len(buf), test_size)
Martin v. Löwisf6b16a42012-05-01 07:58:44 +0200332
Serhiy Storchaka5ce3f102014-01-09 14:50:20 +0200333 def test_truncated_zipfile(self):
334 fp = io.BytesIO()
335 with zipfile.ZipFile(fp, mode='w') as zipf:
336 zipf.writestr('strfile', self.data, compress_type=self.compression)
337 end_offset = fp.tell()
338 zipfiledata = fp.getvalue()
339
340 fp = io.BytesIO(zipfiledata)
341 with zipfile.ZipFile(fp) as zipf:
342 with zipf.open('strfile') as zipopen:
343 fp.truncate(end_offset - 20)
344 with self.assertRaises(EOFError):
345 zipopen.read()
346
347 fp = io.BytesIO(zipfiledata)
348 with zipfile.ZipFile(fp) as zipf:
349 with zipf.open('strfile') as zipopen:
350 fp.truncate(end_offset - 20)
351 with self.assertRaises(EOFError):
352 while zipopen.read(100):
353 pass
354
355 fp = io.BytesIO(zipfiledata)
356 with zipfile.ZipFile(fp) as zipf:
357 with zipf.open('strfile') as zipopen:
358 fp.truncate(end_offset - 20)
359 with self.assertRaises(EOFError):
360 while zipopen.read1(100):
361 pass
362
Serhiy Storchaka51a43702014-10-29 22:42:06 +0200363 def test_repr(self):
364 fname = 'file.name'
365 for f in get_files(self):
366 with zipfile.ZipFile(f, 'w', self.compression) as zipfp:
367 zipfp.write(TESTFN, fname)
368 r = repr(zipfp)
369 self.assertIn("mode='w'", r)
370
371 with zipfile.ZipFile(f, 'r') as zipfp:
372 r = repr(zipfp)
373 if isinstance(f, str):
374 self.assertIn('filename=%r' % f, r)
375 else:
376 self.assertIn('file=%r' % f, r)
377 self.assertIn("mode='r'", r)
378 r = repr(zipfp.getinfo(fname))
379 self.assertIn('filename=%r' % fname, r)
380 self.assertIn('filemode=', r)
381 self.assertIn('file_size=', r)
382 if self.compression != zipfile.ZIP_STORED:
383 self.assertIn('compress_type=', r)
384 self.assertIn('compress_size=', r)
385 with zipfp.open(fname) as zipopen:
386 r = repr(zipopen)
387 self.assertIn('name=%r' % fname, r)
388 self.assertIn("mode='r'", r)
389 if self.compression != zipfile.ZIP_STORED:
390 self.assertIn('compress_type=', r)
391 self.assertIn('[closed]', repr(zipopen))
392 self.assertIn('[closed]', repr(zipfp))
393
Bo Baylesce237c72018-01-29 23:54:07 -0600394 def test_compresslevel_basic(self):
395 for f in get_files(self):
396 self.zip_test(f, self.compression, compresslevel=9)
397
398 def test_per_file_compresslevel(self):
399 """Check that files within a Zip archive can have different
400 compression levels."""
401 with zipfile.ZipFile(TESTFN2, "w", compresslevel=1) as zipfp:
402 zipfp.write(TESTFN, 'compress_1')
403 zipfp.write(TESTFN, 'compress_9', compresslevel=9)
404 one_info = zipfp.getinfo('compress_1')
405 nine_info = zipfp.getinfo('compress_9')
406 self.assertEqual(one_info._compresslevel, 1)
407 self.assertEqual(nine_info._compresslevel, 9)
408
Serhiy Storchaka2524fde2019-03-30 08:25:19 +0200409 def test_writing_errors(self):
410 class BrokenFile(io.BytesIO):
411 def write(self, data):
412 nonlocal count
413 if count is not None:
414 if count == stop:
415 raise OSError
416 count += 1
417 super().write(data)
418
419 stop = 0
420 while True:
421 testfile = BrokenFile()
422 count = None
423 with zipfile.ZipFile(testfile, 'w', self.compression) as zipfp:
424 with zipfp.open('file1', 'w') as f:
425 f.write(b'data1')
426 count = 0
427 try:
428 with zipfp.open('file2', 'w') as f:
429 f.write(b'data2')
430 except OSError:
431 stop += 1
432 else:
433 break
434 finally:
435 count = None
436 with zipfile.ZipFile(io.BytesIO(testfile.getvalue())) as zipfp:
437 self.assertEqual(zipfp.namelist(), ['file1'])
438 self.assertEqual(zipfp.read('file1'), b'data1')
439
440 with zipfile.ZipFile(io.BytesIO(testfile.getvalue())) as zipfp:
441 self.assertEqual(zipfp.namelist(), ['file1', 'file2'])
442 self.assertEqual(zipfp.read('file1'), b'data1')
443 self.assertEqual(zipfp.read('file2'), b'data2')
444
445
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300446 def tearDown(self):
447 unlink(TESTFN)
448 unlink(TESTFN2)
Martin v. Löwisf6b16a42012-05-01 07:58:44 +0200449
Martin v. Löwisf6b16a42012-05-01 07:58:44 +0200450
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300451class StoredTestsWithSourceFile(AbstractTestsWithSourceFile,
452 unittest.TestCase):
453 compression = zipfile.ZIP_STORED
454 test_low_compression = None
Martin v. Löwisf6b16a42012-05-01 07:58:44 +0200455
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300456 def zip_test_writestr_permissions(self, f, compression):
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +0300457 # Make sure that writestr and open(... mode='w') create files with
458 # mode 0600, when they are passed a name rather than a ZipInfo
459 # instance.
Martin v. Löwisf6b16a42012-05-01 07:58:44 +0200460
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300461 self.make_test_archive(f, compression)
462 with zipfile.ZipFile(f, "r") as zipfp:
463 zinfo = zipfp.getinfo('strfile')
464 self.assertEqual(zinfo.external_attr, 0o600 << 16)
Martin v. Löwisf6b16a42012-05-01 07:58:44 +0200465
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +0300466 zinfo2 = zipfp.getinfo('written-open-w')
467 self.assertEqual(zinfo2.external_attr, 0o600 << 16)
468
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300469 def test_writestr_permissions(self):
470 for f in get_files(self):
471 self.zip_test_writestr_permissions(f, zipfile.ZIP_STORED)
Martin v. Löwis7fb79fc2012-05-13 10:06:36 +0200472
Ezio Melottiafd0d112009-07-15 17:17:17 +0000473 def test_absolute_arcnames(self):
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000474 with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
475 zipfp.write(TESTFN, "/absolute")
Georg Brandl8f7c54e2006-02-20 08:40:38 +0000476
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000477 with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_STORED) as zipfp:
478 self.assertEqual(zipfp.namelist(), ["absolute"])
Tim Peters32cbc962006-02-20 21:42:18 +0000479
Ezio Melottiafd0d112009-07-15 17:17:17 +0000480 def test_append_to_zip_file(self):
Ezio Melotti35386712009-12-31 13:22:41 +0000481 """Test appending to an existing zipfile."""
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000482 with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
483 zipfp.write(TESTFN, TESTFN)
484
485 with zipfile.ZipFile(TESTFN2, "a", zipfile.ZIP_STORED) as zipfp:
486 zipfp.writestr("strfile", self.data)
487 self.assertEqual(zipfp.namelist(), [TESTFN, "strfile"])
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000488
Ezio Melottiafd0d112009-07-15 17:17:17 +0000489 def test_append_to_non_zip_file(self):
Ezio Melotti35386712009-12-31 13:22:41 +0000490 """Test appending to an existing file that is not a zipfile."""
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000491 # NOTE: this test fails if len(d) < 22 because of the first
492 # line "fpin.seek(-22, 2)" in _EndRecData
Ezio Melotti35386712009-12-31 13:22:41 +0000493 data = b'I am not a ZipFile!'*10
494 with open(TESTFN2, 'wb') as f:
495 f.write(data)
496
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000497 with zipfile.ZipFile(TESTFN2, "a", zipfile.ZIP_STORED) as zipfp:
498 zipfp.write(TESTFN, TESTFN)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000499
Ezio Melotti35386712009-12-31 13:22:41 +0000500 with open(TESTFN2, 'rb') as f:
501 f.seek(len(data))
502 with zipfile.ZipFile(f, "r") as zipfp:
503 self.assertEqual(zipfp.namelist(), [TESTFN])
Serhiy Storchaka8793b212016-10-07 22:20:50 +0300504 self.assertEqual(zipfp.read(TESTFN), self.data)
505 with open(TESTFN2, 'rb') as f:
506 self.assertEqual(f.read(len(data)), data)
507 zipfiledata = f.read()
508 with io.BytesIO(zipfiledata) as bio, zipfile.ZipFile(bio) as zipfp:
509 self.assertEqual(zipfp.namelist(), [TESTFN])
510 self.assertEqual(zipfp.read(TESTFN), self.data)
511
512 def test_read_concatenated_zip_file(self):
513 with io.BytesIO() as bio:
514 with zipfile.ZipFile(bio, 'w', zipfile.ZIP_STORED) as zipfp:
515 zipfp.write(TESTFN, TESTFN)
516 zipfiledata = bio.getvalue()
517 data = b'I am not a ZipFile!'*10
518 with open(TESTFN2, 'wb') as f:
519 f.write(data)
520 f.write(zipfiledata)
521
522 with zipfile.ZipFile(TESTFN2) as zipfp:
523 self.assertEqual(zipfp.namelist(), [TESTFN])
524 self.assertEqual(zipfp.read(TESTFN), self.data)
525
526 def test_append_to_concatenated_zip_file(self):
527 with io.BytesIO() as bio:
528 with zipfile.ZipFile(bio, 'w', zipfile.ZIP_STORED) as zipfp:
529 zipfp.write(TESTFN, TESTFN)
530 zipfiledata = bio.getvalue()
531 data = b'I am not a ZipFile!'*1000000
532 with open(TESTFN2, 'wb') as f:
533 f.write(data)
534 f.write(zipfiledata)
535
536 with zipfile.ZipFile(TESTFN2, 'a') as zipfp:
537 self.assertEqual(zipfp.namelist(), [TESTFN])
538 zipfp.writestr('strfile', self.data)
539
540 with open(TESTFN2, 'rb') as f:
541 self.assertEqual(f.read(len(data)), data)
542 zipfiledata = f.read()
543 with io.BytesIO(zipfiledata) as bio, zipfile.ZipFile(bio) as zipfp:
544 self.assertEqual(zipfp.namelist(), [TESTFN, 'strfile'])
545 self.assertEqual(zipfp.read(TESTFN), self.data)
546 self.assertEqual(zipfp.read('strfile'), self.data)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000547
R David Murray4fbb9db2011-06-09 15:50:51 -0400548 def test_ignores_newline_at_end(self):
549 with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
550 zipfp.write(TESTFN, TESTFN)
551 with open(TESTFN2, 'a') as f:
552 f.write("\r\n\00\00\00")
553 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
554 self.assertIsInstance(zipfp, zipfile.ZipFile)
555
556 def test_ignores_stuff_appended_past_comments(self):
557 with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
558 zipfp.comment = b"this is a comment"
559 zipfp.write(TESTFN, TESTFN)
560 with open(TESTFN2, 'a') as f:
561 f.write("abcdef\r\n")
562 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
563 self.assertIsInstance(zipfp, zipfile.ZipFile)
564 self.assertEqual(zipfp.comment, b"this is a comment")
565
Ezio Melottiafd0d112009-07-15 17:17:17 +0000566 def test_write_default_name(self):
Ezio Melotti35386712009-12-31 13:22:41 +0000567 """Check that calling ZipFile.write without arcname specified
568 produces the expected result."""
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000569 with zipfile.ZipFile(TESTFN2, "w") as zipfp:
570 zipfp.write(TESTFN)
Brian Curtin8fb9b862010-11-18 02:15:28 +0000571 with open(TESTFN, "rb") as f:
572 self.assertEqual(zipfp.read(TESTFN), f.read())
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000573
Daniel Hillier8d62df62019-11-30 19:30:47 +1100574 def test_io_on_closed_zipextfile(self):
575 fname = "somefile.txt"
576 with zipfile.ZipFile(TESTFN2, mode="w") as zipfp:
577 zipfp.writestr(fname, "bogus")
578
579 with zipfile.ZipFile(TESTFN2, mode="r") as zipfp:
580 with zipfp.open(fname) as fid:
581 fid.close()
582 self.assertRaises(ValueError, fid.read)
583 self.assertRaises(ValueError, fid.seek, 0)
584 self.assertRaises(ValueError, fid.tell)
585 self.assertRaises(ValueError, fid.readable)
586 self.assertRaises(ValueError, fid.seekable)
587
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300588 def test_write_to_readonly(self):
589 """Check that trying to call write() on a readonly ZipFile object
Serhiy Storchakab0d497c2016-09-10 21:28:07 +0300590 raises a ValueError."""
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300591 with zipfile.ZipFile(TESTFN2, mode="w") as zipfp:
592 zipfp.writestr("somefile.txt", "bogus")
593
594 with zipfile.ZipFile(TESTFN2, mode="r") as zipfp:
Serhiy Storchakab0d497c2016-09-10 21:28:07 +0300595 self.assertRaises(ValueError, zipfp.write, TESTFN)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300596
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +0300597 with zipfile.ZipFile(TESTFN2, mode="r") as zipfp:
Serhiy Storchakab0d497c2016-09-10 21:28:07 +0300598 with self.assertRaises(ValueError):
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +0300599 zipfp.open(TESTFN, mode='w')
600
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300601 def test_add_file_before_1980(self):
602 # Set atime and mtime to 1970-01-01
603 os.utime(TESTFN, (0, 0))
604 with zipfile.ZipFile(TESTFN2, "w") as zipfp:
605 self.assertRaises(ValueError, zipfp.write, TESTFN)
606
Marcel Plch77b112c2018-08-31 16:43:31 +0200607 with zipfile.ZipFile(TESTFN2, "w", strict_timestamps=False) as zipfp:
608 zipfp.write(TESTFN)
Marcel Plcha2fe1e52018-08-02 15:04:52 +0200609 zinfo = zipfp.getinfo(TESTFN)
610 self.assertEqual(zinfo.date_time, (1980, 1, 1, 0, 0, 0))
611
612 def test_add_file_after_2107(self):
613 # Set atime and mtime to 2108-12-30
Marcel Plch7b41dba2018-08-03 17:59:19 +0200614 try:
615 os.utime(TESTFN, (4386268800, 4386268800))
616 except OverflowError:
617 self.skipTest('Host fs cannot set timestamp to required value.')
618
Victor Stinner3cb49b62020-01-29 15:23:29 +0100619 mtime_ns = os.stat(TESTFN).st_mtime_ns
620 if mtime_ns != (4386268800 * 10**9):
621 # XFS filesystem is limited to 32-bit timestamp, but the syscall
622 # didn't fail. Moreover, there is a VFS bug which returns
623 # a cached timestamp which is different than the value on disk.
624 #
625 # Test st_mtime_ns rather than st_mtime to avoid rounding issues.
626 #
627 # https://bugzilla.redhat.com/show_bug.cgi?id=1795576
628 # https://bugs.python.org/issue39460#msg360952
629 self.skipTest(f"Linux VFS/XFS kernel bug detected: {mtime_ns=}")
630
Marcel Plcha2fe1e52018-08-02 15:04:52 +0200631 with zipfile.ZipFile(TESTFN2, "w") as zipfp:
632 self.assertRaises(struct.error, zipfp.write, TESTFN)
633
Marcel Plch77b112c2018-08-31 16:43:31 +0200634 with zipfile.ZipFile(TESTFN2, "w", strict_timestamps=False) as zipfp:
635 zipfp.write(TESTFN)
Marcel Plcha2fe1e52018-08-02 15:04:52 +0200636 zinfo = zipfp.getinfo(TESTFN)
637 self.assertEqual(zinfo.date_time, (2107, 12, 31, 23, 59, 59))
638
Serhiy Storchaka5ce3f102014-01-09 14:50:20 +0200639
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300640@requires_zlib
641class DeflateTestsWithSourceFile(AbstractTestsWithSourceFile,
642 unittest.TestCase):
643 compression = zipfile.ZIP_DEFLATED
644
Ezio Melottiafd0d112009-07-15 17:17:17 +0000645 def test_per_file_compression(self):
Ezio Melotti35386712009-12-31 13:22:41 +0000646 """Check that files within a Zip archive can have different
647 compression options."""
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000648 with zipfile.ZipFile(TESTFN2, "w") as zipfp:
649 zipfp.write(TESTFN, 'storeme', zipfile.ZIP_STORED)
650 zipfp.write(TESTFN, 'deflateme', zipfile.ZIP_DEFLATED)
651 sinfo = zipfp.getinfo('storeme')
652 dinfo = zipfp.getinfo('deflateme')
653 self.assertEqual(sinfo.compress_type, zipfile.ZIP_STORED)
654 self.assertEqual(dinfo.compress_type, zipfile.ZIP_DEFLATED)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000655
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300656@requires_bz2
657class Bzip2TestsWithSourceFile(AbstractTestsWithSourceFile,
658 unittest.TestCase):
659 compression = zipfile.ZIP_BZIP2
Ezio Melottifaa6b7f2009-12-30 12:34:59 +0000660
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300661@requires_lzma
662class LzmaTestsWithSourceFile(AbstractTestsWithSourceFile,
663 unittest.TestCase):
664 compression = zipfile.ZIP_LZMA
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000665
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300666
667class AbstractTestZip64InSmallFiles:
668 # These tests test the ZIP64 functionality without using large files,
669 # see test_zipfile64 for proper tests.
670
671 @classmethod
672 def setUpClass(cls):
673 line_gen = (bytes("Test of zipfile line %d." % i, "ascii")
674 for i in range(0, FIXEDTEST_SIZE))
675 cls.data = b'\n'.join(line_gen)
676
677 def setUp(self):
678 self._limit = zipfile.ZIP64_LIMIT
Serhiy Storchaka026a3992014-09-23 22:27:34 +0300679 self._filecount_limit = zipfile.ZIP_FILECOUNT_LIMIT
680 zipfile.ZIP64_LIMIT = 1000
681 zipfile.ZIP_FILECOUNT_LIMIT = 9
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300682
683 # Make a source file with some lines
684 with open(TESTFN, "wb") as fp:
685 fp.write(self.data)
686
687 def zip_test(self, f, compression):
688 # Create the ZIP archive
689 with zipfile.ZipFile(f, "w", compression, allowZip64=True) as zipfp:
690 zipfp.write(TESTFN, "another.name")
691 zipfp.write(TESTFN, TESTFN)
692 zipfp.writestr("strfile", self.data)
693
694 # Read the ZIP archive
695 with zipfile.ZipFile(f, "r", compression) as zipfp:
696 self.assertEqual(zipfp.read(TESTFN), self.data)
697 self.assertEqual(zipfp.read("another.name"), self.data)
698 self.assertEqual(zipfp.read("strfile"), self.data)
699
700 # Print the ZIP directory
701 fp = io.StringIO()
702 zipfp.printdir(fp)
703
704 directory = fp.getvalue()
705 lines = directory.splitlines()
706 self.assertEqual(len(lines), 4) # Number of files + header
707
708 self.assertIn('File Name', lines[0])
709 self.assertIn('Modified', lines[0])
710 self.assertIn('Size', lines[0])
711
712 fn, date, time_, size = lines[1].split()
713 self.assertEqual(fn, 'another.name')
714 self.assertTrue(time.strptime(date, '%Y-%m-%d'))
715 self.assertTrue(time.strptime(time_, '%H:%M:%S'))
716 self.assertEqual(size, str(len(self.data)))
717
718 # Check the namelist
719 names = zipfp.namelist()
720 self.assertEqual(len(names), 3)
721 self.assertIn(TESTFN, names)
722 self.assertIn("another.name", names)
723 self.assertIn("strfile", names)
724
725 # Check infolist
726 infos = zipfp.infolist()
727 names = [i.filename for i in infos]
728 self.assertEqual(len(names), 3)
729 self.assertIn(TESTFN, names)
730 self.assertIn("another.name", names)
731 self.assertIn("strfile", names)
732 for i in infos:
733 self.assertEqual(i.file_size, len(self.data))
734
735 # check getinfo
736 for nm in (TESTFN, "another.name", "strfile"):
737 info = zipfp.getinfo(nm)
738 self.assertEqual(info.filename, nm)
739 self.assertEqual(info.file_size, len(self.data))
740
741 # Check that testzip doesn't raise an exception
742 zipfp.testzip()
743
744 def test_basic(self):
745 for f in get_files(self):
746 self.zip_test(f, self.compression)
747
Serhiy Storchaka026a3992014-09-23 22:27:34 +0300748 def test_too_many_files(self):
749 # This test checks that more than 64k files can be added to an archive,
750 # and that the resulting archive can be read properly by ZipFile
751 zipf = zipfile.ZipFile(TESTFN, "w", self.compression,
752 allowZip64=True)
753 zipf.debug = 100
754 numfiles = 15
755 for i in range(numfiles):
756 zipf.writestr("foo%08d" % i, "%d" % (i**3 % 57))
757 self.assertEqual(len(zipf.namelist()), numfiles)
758 zipf.close()
759
760 zipf2 = zipfile.ZipFile(TESTFN, "r", self.compression)
761 self.assertEqual(len(zipf2.namelist()), numfiles)
762 for i in range(numfiles):
763 content = zipf2.read("foo%08d" % i).decode('ascii')
764 self.assertEqual(content, "%d" % (i**3 % 57))
765 zipf2.close()
766
767 def test_too_many_files_append(self):
768 zipf = zipfile.ZipFile(TESTFN, "w", self.compression,
769 allowZip64=False)
770 zipf.debug = 100
771 numfiles = 9
772 for i in range(numfiles):
773 zipf.writestr("foo%08d" % i, "%d" % (i**3 % 57))
774 self.assertEqual(len(zipf.namelist()), numfiles)
775 with self.assertRaises(zipfile.LargeZipFile):
776 zipf.writestr("foo%08d" % numfiles, b'')
777 self.assertEqual(len(zipf.namelist()), numfiles)
778 zipf.close()
779
780 zipf = zipfile.ZipFile(TESTFN, "a", self.compression,
781 allowZip64=False)
782 zipf.debug = 100
783 self.assertEqual(len(zipf.namelist()), numfiles)
784 with self.assertRaises(zipfile.LargeZipFile):
785 zipf.writestr("foo%08d" % numfiles, b'')
786 self.assertEqual(len(zipf.namelist()), numfiles)
787 zipf.close()
788
789 zipf = zipfile.ZipFile(TESTFN, "a", self.compression,
790 allowZip64=True)
791 zipf.debug = 100
792 self.assertEqual(len(zipf.namelist()), numfiles)
793 numfiles2 = 15
794 for i in range(numfiles, numfiles2):
795 zipf.writestr("foo%08d" % i, "%d" % (i**3 % 57))
796 self.assertEqual(len(zipf.namelist()), numfiles2)
797 zipf.close()
798
799 zipf2 = zipfile.ZipFile(TESTFN, "r", self.compression)
800 self.assertEqual(len(zipf2.namelist()), numfiles2)
801 for i in range(numfiles2):
802 content = zipf2.read("foo%08d" % i).decode('ascii')
803 self.assertEqual(content, "%d" % (i**3 % 57))
804 zipf2.close()
805
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300806 def tearDown(self):
807 zipfile.ZIP64_LIMIT = self._limit
Serhiy Storchaka026a3992014-09-23 22:27:34 +0300808 zipfile.ZIP_FILECOUNT_LIMIT = self._filecount_limit
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300809 unlink(TESTFN)
810 unlink(TESTFN2)
811
812
813class StoredTestZip64InSmallFiles(AbstractTestZip64InSmallFiles,
814 unittest.TestCase):
815 compression = zipfile.ZIP_STORED
816
817 def large_file_exception_test(self, f, compression):
Serhiy Storchaka235c5e02013-11-23 15:55:38 +0200818 with zipfile.ZipFile(f, "w", compression, allowZip64=False) as zipfp:
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300819 self.assertRaises(zipfile.LargeZipFile,
820 zipfp.write, TESTFN, "another.name")
821
822 def large_file_exception_test2(self, f, compression):
Serhiy Storchaka235c5e02013-11-23 15:55:38 +0200823 with zipfile.ZipFile(f, "w", compression, allowZip64=False) as zipfp:
Serhiy Storchakafa6bc292013-07-22 21:00:11 +0300824 self.assertRaises(zipfile.LargeZipFile,
825 zipfp.writestr, "another.name", self.data)
826
827 def test_large_file_exception(self):
828 for f in get_files(self):
829 self.large_file_exception_test(f, zipfile.ZIP_STORED)
830 self.large_file_exception_test2(f, zipfile.ZIP_STORED)
831
832 def test_absolute_arcnames(self):
833 with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED,
834 allowZip64=True) as zipfp:
835 zipfp.write(TESTFN, "/absolute")
836
837 with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_STORED) as zipfp:
838 self.assertEqual(zipfp.namelist(), ["absolute"])
839
Serhiy Storchaka9bdb7be2018-09-17 15:36:40 +0300840 def test_append(self):
841 # Test that appending to the Zip64 archive doesn't change
842 # extra fields of existing entries.
843 with zipfile.ZipFile(TESTFN2, "w", allowZip64=True) as zipfp:
844 zipfp.writestr("strfile", self.data)
845 with zipfile.ZipFile(TESTFN2, "r", allowZip64=True) as zipfp:
846 zinfo = zipfp.getinfo("strfile")
847 extra = zinfo.extra
848 with zipfile.ZipFile(TESTFN2, "a", allowZip64=True) as zipfp:
849 zipfp.writestr("strfile2", self.data)
850 with zipfile.ZipFile(TESTFN2, "r", allowZip64=True) as zipfp:
851 zinfo = zipfp.getinfo("strfile")
852 self.assertEqual(zinfo.extra, extra)
853
Daniel Hillierda6ce582019-10-29 18:24:18 +1100854 def make_zip64_file(
855 self, file_size_64_set=False, file_size_extra=False,
856 compress_size_64_set=False, compress_size_extra=False,
857 header_offset_64_set=False, header_offset_extra=False,
858 ):
859 """Generate bytes sequence for a zip with (incomplete) zip64 data.
860
861 The actual values (not the zip 64 0xffffffff values) stored in the file
862 are:
863 file_size: 8
864 compress_size: 8
865 header_offset: 0
866 """
867 actual_size = 8
868 actual_header_offset = 0
869 local_zip64_fields = []
870 central_zip64_fields = []
871
872 file_size = actual_size
873 if file_size_64_set:
874 file_size = 0xffffffff
875 if file_size_extra:
876 local_zip64_fields.append(actual_size)
877 central_zip64_fields.append(actual_size)
878 file_size = struct.pack("<L", file_size)
879
880 compress_size = actual_size
881 if compress_size_64_set:
882 compress_size = 0xffffffff
883 if compress_size_extra:
884 local_zip64_fields.append(actual_size)
885 central_zip64_fields.append(actual_size)
886 compress_size = struct.pack("<L", compress_size)
887
888 header_offset = actual_header_offset
889 if header_offset_64_set:
890 header_offset = 0xffffffff
891 if header_offset_extra:
892 central_zip64_fields.append(actual_header_offset)
893 header_offset = struct.pack("<L", header_offset)
894
895 local_extra = struct.pack(
896 '<HH' + 'Q'*len(local_zip64_fields),
897 0x0001,
898 8*len(local_zip64_fields),
899 *local_zip64_fields
900 )
901
902 central_extra = struct.pack(
903 '<HH' + 'Q'*len(central_zip64_fields),
904 0x0001,
905 8*len(central_zip64_fields),
906 *central_zip64_fields
907 )
908
909 central_dir_size = struct.pack('<Q', 58 + 8 * len(central_zip64_fields))
910 offset_to_central_dir = struct.pack('<Q', 50 + 8 * len(local_zip64_fields))
911
912 local_extra_length = struct.pack("<H", 4 + 8 * len(local_zip64_fields))
913 central_extra_length = struct.pack("<H", 4 + 8 * len(central_zip64_fields))
914
915 filename = b"test.txt"
916 content = b"test1234"
917 filename_length = struct.pack("<H", len(filename))
918 zip64_contents = (
919 # Local file header
920 b"PK\x03\x04\x14\x00\x00\x00\x00\x00\x00\x00!\x00\x9e%\xf5\xaf"
921 + compress_size
922 + file_size
923 + filename_length
924 + local_extra_length
925 + filename
926 + local_extra
927 + content
928 # Central directory:
929 + b"PK\x01\x02-\x03-\x00\x00\x00\x00\x00\x00\x00!\x00\x9e%\xf5\xaf"
930 + compress_size
931 + file_size
932 + filename_length
933 + central_extra_length
934 + b"\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01"
935 + header_offset
936 + filename
937 + central_extra
938 # Zip64 end of central directory
939 + b"PK\x06\x06,\x00\x00\x00\x00\x00\x00\x00-\x00-"
940 + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00"
941 + b"\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00"
942 + central_dir_size
943 + offset_to_central_dir
944 # Zip64 end of central directory locator
945 + b"PK\x06\x07\x00\x00\x00\x00l\x00\x00\x00\x00\x00\x00\x00\x01"
946 + b"\x00\x00\x00"
947 # end of central directory
948 + b"PK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x00:\x00\x00\x002\x00"
949 + b"\x00\x00\x00\x00"
950 )
951 return zip64_contents
952
953 def test_bad_zip64_extra(self):
954 """Missing zip64 extra records raises an exception.
955
956 There are 4 fields that the zip64 format handles (the disk number is
957 not used in this module and so is ignored here). According to the zip
958 spec:
959 The order of the fields in the zip64 extended
960 information record is fixed, but the fields MUST
961 only appear if the corresponding Local or Central
962 directory record field is set to 0xFFFF or 0xFFFFFFFF.
963
964 If the zip64 extra content doesn't contain enough entries for the
965 number of fields marked with 0xFFFF or 0xFFFFFFFF, we raise an error.
966 This test mismatches the length of the zip64 extra field and the number
967 of fields set to indicate the presence of zip64 data.
968 """
969 # zip64 file size present, no fields in extra, expecting one, equals
970 # missing file size.
971 missing_file_size_extra = self.make_zip64_file(
972 file_size_64_set=True,
973 )
974 with self.assertRaises(zipfile.BadZipFile) as e:
975 zipfile.ZipFile(io.BytesIO(missing_file_size_extra))
976 self.assertIn('file size', str(e.exception).lower())
977
978 # zip64 file size present, zip64 compress size present, one field in
979 # extra, expecting two, equals missing compress size.
980 missing_compress_size_extra = self.make_zip64_file(
981 file_size_64_set=True,
982 file_size_extra=True,
983 compress_size_64_set=True,
984 )
985 with self.assertRaises(zipfile.BadZipFile) as e:
986 zipfile.ZipFile(io.BytesIO(missing_compress_size_extra))
987 self.assertIn('compress size', str(e.exception).lower())
988
989 # zip64 compress size present, no fields in extra, expecting one,
990 # equals missing compress size.
991 missing_compress_size_extra = self.make_zip64_file(
992 compress_size_64_set=True,
993 )
994 with self.assertRaises(zipfile.BadZipFile) as e:
995 zipfile.ZipFile(io.BytesIO(missing_compress_size_extra))
996 self.assertIn('compress size', str(e.exception).lower())
997
998 # zip64 file size present, zip64 compress size present, zip64 header
999 # offset present, two fields in extra, expecting three, equals missing
1000 # header offset
1001 missing_header_offset_extra = self.make_zip64_file(
1002 file_size_64_set=True,
1003 file_size_extra=True,
1004 compress_size_64_set=True,
1005 compress_size_extra=True,
1006 header_offset_64_set=True,
1007 )
1008 with self.assertRaises(zipfile.BadZipFile) as e:
1009 zipfile.ZipFile(io.BytesIO(missing_header_offset_extra))
1010 self.assertIn('header offset', str(e.exception).lower())
1011
1012 # zip64 compress size present, zip64 header offset present, one field
1013 # in extra, expecting two, equals missing header offset
1014 missing_header_offset_extra = self.make_zip64_file(
1015 file_size_64_set=False,
1016 compress_size_64_set=True,
1017 compress_size_extra=True,
1018 header_offset_64_set=True,
1019 )
1020 with self.assertRaises(zipfile.BadZipFile) as e:
1021 zipfile.ZipFile(io.BytesIO(missing_header_offset_extra))
1022 self.assertIn('header offset', str(e.exception).lower())
1023
1024 # zip64 file size present, zip64 header offset present, one field in
1025 # extra, expecting two, equals missing header offset
1026 missing_header_offset_extra = self.make_zip64_file(
1027 file_size_64_set=True,
1028 file_size_extra=True,
1029 compress_size_64_set=False,
1030 header_offset_64_set=True,
1031 )
1032 with self.assertRaises(zipfile.BadZipFile) as e:
1033 zipfile.ZipFile(io.BytesIO(missing_header_offset_extra))
1034 self.assertIn('header offset', str(e.exception).lower())
1035
1036 # zip64 header offset present, no fields in extra, expecting one,
1037 # equals missing header offset
1038 missing_header_offset_extra = self.make_zip64_file(
1039 file_size_64_set=False,
1040 compress_size_64_set=False,
1041 header_offset_64_set=True,
1042 )
1043 with self.assertRaises(zipfile.BadZipFile) as e:
1044 zipfile.ZipFile(io.BytesIO(missing_header_offset_extra))
1045 self.assertIn('header offset', str(e.exception).lower())
1046
1047 def test_generated_valid_zip64_extra(self):
1048 # These values are what is set in the make_zip64_file method.
1049 expected_file_size = 8
1050 expected_compress_size = 8
1051 expected_header_offset = 0
1052 expected_content = b"test1234"
1053
1054 # Loop through the various valid combinations of zip64 masks
1055 # present and extra fields present.
1056 params = (
1057 {"file_size_64_set": True, "file_size_extra": True},
1058 {"compress_size_64_set": True, "compress_size_extra": True},
1059 {"header_offset_64_set": True, "header_offset_extra": True},
1060 )
1061
1062 for r in range(1, len(params) + 1):
1063 for combo in itertools.combinations(params, r):
1064 kwargs = {}
1065 for c in combo:
1066 kwargs.update(c)
1067 with zipfile.ZipFile(io.BytesIO(self.make_zip64_file(**kwargs))) as zf:
1068 zinfo = zf.infolist()[0]
1069 self.assertEqual(zinfo.file_size, expected_file_size)
1070 self.assertEqual(zinfo.compress_size, expected_compress_size)
1071 self.assertEqual(zinfo.header_offset, expected_header_offset)
1072 self.assertEqual(zf.read(zinfo), expected_content)
1073
1074
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001075@requires_zlib
1076class DeflateTestZip64InSmallFiles(AbstractTestZip64InSmallFiles,
1077 unittest.TestCase):
1078 compression = zipfile.ZIP_DEFLATED
1079
1080@requires_bz2
1081class Bzip2TestZip64InSmallFiles(AbstractTestZip64InSmallFiles,
1082 unittest.TestCase):
1083 compression = zipfile.ZIP_BZIP2
1084
1085@requires_lzma
1086class LzmaTestZip64InSmallFiles(AbstractTestZip64InSmallFiles,
1087 unittest.TestCase):
1088 compression = zipfile.ZIP_LZMA
1089
1090
Serhiy Storchaka4c0d9ea2017-04-12 16:03:23 +03001091class AbstractWriterTests:
1092
1093 def tearDown(self):
1094 unlink(TESTFN2)
1095
1096 def test_close_after_close(self):
1097 data = b'content'
1098 with zipfile.ZipFile(TESTFN2, "w", self.compression) as zipf:
1099 w = zipf.open('test', 'w')
1100 w.write(data)
1101 w.close()
1102 self.assertTrue(w.closed)
1103 w.close()
1104 self.assertTrue(w.closed)
1105 self.assertEqual(zipf.read('test'), data)
1106
1107 def test_write_after_close(self):
1108 data = b'content'
1109 with zipfile.ZipFile(TESTFN2, "w", self.compression) as zipf:
1110 w = zipf.open('test', 'w')
1111 w.write(data)
1112 w.close()
1113 self.assertTrue(w.closed)
1114 self.assertRaises(ValueError, w.write, b'')
1115 self.assertEqual(zipf.read('test'), data)
1116
1117class StoredWriterTests(AbstractWriterTests, unittest.TestCase):
1118 compression = zipfile.ZIP_STORED
1119
1120@requires_zlib
1121class DeflateWriterTests(AbstractWriterTests, unittest.TestCase):
1122 compression = zipfile.ZIP_DEFLATED
1123
1124@requires_bz2
1125class Bzip2WriterTests(AbstractWriterTests, unittest.TestCase):
1126 compression = zipfile.ZIP_BZIP2
1127
1128@requires_lzma
1129class LzmaWriterTests(AbstractWriterTests, unittest.TestCase):
1130 compression = zipfile.ZIP_LZMA
1131
1132
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001133class PyZipFileTests(unittest.TestCase):
1134 def assertCompiledIn(self, name, namelist):
1135 if name + 'o' not in namelist:
1136 self.assertIn(name + 'c', namelist)
1137
Serhiy Storchakadb724fe2015-02-14 23:04:35 +02001138 def requiresWriteAccess(self, path):
Berker Peksage1efc072015-02-16 04:36:18 +02001139 # effective_ids unavailable on windows
1140 if not os.access(path, os.W_OK,
1141 effective_ids=os.access in os.supports_effective_ids):
Serhiy Storchakadb724fe2015-02-14 23:04:35 +02001142 self.skipTest('requires write access to the installed location')
Serhiy Storchakad86a6ef2015-09-19 10:55:20 +03001143 filename = os.path.join(path, 'test_zipfile.try')
1144 try:
1145 fd = os.open(filename, os.O_WRONLY | os.O_CREAT)
1146 os.close(fd)
1147 except Exception:
1148 self.skipTest('requires write access to the installed location')
1149 unlink(filename)
Serhiy Storchakadb724fe2015-02-14 23:04:35 +02001150
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001151 def test_write_pyfile(self):
Serhiy Storchakadb724fe2015-02-14 23:04:35 +02001152 self.requiresWriteAccess(os.path.dirname(__file__))
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001153 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1154 fn = __file__
Brett Cannonf299abd2015-04-13 14:21:02 -04001155 if fn.endswith('.pyc'):
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001156 path_split = fn.split(os.sep)
1157 if os.altsep is not None:
1158 path_split.extend(fn.split(os.altsep))
1159 if '__pycache__' in path_split:
Serhiy Storchaka9068e4d2013-07-22 21:02:14 +03001160 fn = importlib.util.source_from_cache(fn)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001161 else:
1162 fn = fn[:-1]
1163
1164 zipfp.writepy(fn)
1165
1166 bn = os.path.basename(fn)
1167 self.assertNotIn(bn, zipfp.namelist())
1168 self.assertCompiledIn(bn, zipfp.namelist())
1169
1170 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1171 fn = __file__
Brett Cannonf299abd2015-04-13 14:21:02 -04001172 if fn.endswith('.pyc'):
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001173 fn = fn[:-1]
1174
1175 zipfp.writepy(fn, "testpackage")
1176
1177 bn = "%s/%s" % ("testpackage", os.path.basename(fn))
1178 self.assertNotIn(bn, zipfp.namelist())
1179 self.assertCompiledIn(bn, zipfp.namelist())
1180
1181 def test_write_python_package(self):
1182 import email
1183 packagedir = os.path.dirname(email.__file__)
Serhiy Storchakadb724fe2015-02-14 23:04:35 +02001184 self.requiresWriteAccess(packagedir)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001185
1186 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1187 zipfp.writepy(packagedir)
1188
1189 # Check for a couple of modules at different levels of the
1190 # hierarchy
1191 names = zipfp.namelist()
1192 self.assertCompiledIn('email/__init__.py', names)
1193 self.assertCompiledIn('email/mime/text.py', names)
1194
Christian Tismer59202e52013-10-21 03:59:23 +02001195 def test_write_filtered_python_package(self):
1196 import test
1197 packagedir = os.path.dirname(test.__file__)
Serhiy Storchakadb724fe2015-02-14 23:04:35 +02001198 self.requiresWriteAccess(packagedir)
Christian Tismer59202e52013-10-21 03:59:23 +02001199
1200 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1201
Christian Tismer59202e52013-10-21 03:59:23 +02001202 # first make sure that the test folder gives error messages
Georg Brandla6065422013-10-21 08:29:29 +02001203 # (on the badsyntax_... files)
1204 with captured_stdout() as reportSIO:
1205 zipfp.writepy(packagedir)
Christian Tismer59202e52013-10-21 03:59:23 +02001206 reportStr = reportSIO.getvalue()
1207 self.assertTrue('SyntaxError' in reportStr)
1208
Christian Tismer410d9312013-10-22 04:09:28 +02001209 # then check that the filter works on the whole package
Georg Brandla6065422013-10-21 08:29:29 +02001210 with captured_stdout() as reportSIO:
1211 zipfp.writepy(packagedir, filterfunc=lambda whatever: False)
Christian Tismer59202e52013-10-21 03:59:23 +02001212 reportStr = reportSIO.getvalue()
1213 self.assertTrue('SyntaxError' not in reportStr)
1214
Christian Tismer410d9312013-10-22 04:09:28 +02001215 # then check that the filter works on individual files
Larry Hastings7e63b362015-05-08 06:54:58 -07001216 def filter(path):
1217 return not os.path.basename(path).startswith("bad")
Serhiy Storchakac46d1fa2014-01-20 21:59:33 +02001218 with captured_stdout() as reportSIO, self.assertWarns(UserWarning):
Larry Hastings7e63b362015-05-08 06:54:58 -07001219 zipfp.writepy(packagedir, filterfunc=filter)
Christian Tismer410d9312013-10-22 04:09:28 +02001220 reportStr = reportSIO.getvalue()
1221 if reportStr:
1222 print(reportStr)
1223 self.assertTrue('SyntaxError' not in reportStr)
1224
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001225 def test_write_with_optimization(self):
1226 import email
1227 packagedir = os.path.dirname(email.__file__)
Serhiy Storchakadb724fe2015-02-14 23:04:35 +02001228 self.requiresWriteAccess(packagedir)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001229 optlevel = 1 if __debug__ else 0
Brett Cannonf299abd2015-04-13 14:21:02 -04001230 ext = '.pyc'
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001231
1232 with TemporaryFile() as t, \
Christian Tismer59202e52013-10-21 03:59:23 +02001233 zipfile.PyZipFile(t, "w", optimize=optlevel) as zipfp:
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001234 zipfp.writepy(packagedir)
1235
1236 names = zipfp.namelist()
1237 self.assertIn('email/__init__' + ext, names)
1238 self.assertIn('email/mime/text' + ext, names)
1239
1240 def test_write_python_directory(self):
1241 os.mkdir(TESTFN2)
1242 try:
1243 with open(os.path.join(TESTFN2, "mod1.py"), "w") as fp:
1244 fp.write("print(42)\n")
1245
1246 with open(os.path.join(TESTFN2, "mod2.py"), "w") as fp:
1247 fp.write("print(42 * 42)\n")
1248
1249 with open(os.path.join(TESTFN2, "mod2.txt"), "w") as fp:
1250 fp.write("bla bla bla\n")
1251
1252 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1253 zipfp.writepy(TESTFN2)
1254
1255 names = zipfp.namelist()
1256 self.assertCompiledIn('mod1.py', names)
1257 self.assertCompiledIn('mod2.py', names)
1258 self.assertNotIn('mod2.txt', names)
1259
1260 finally:
Victor Stinner57004c62014-09-04 00:49:01 +02001261 rmtree(TESTFN2)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001262
Christian Tismer410d9312013-10-22 04:09:28 +02001263 def test_write_python_directory_filtered(self):
1264 os.mkdir(TESTFN2)
1265 try:
1266 with open(os.path.join(TESTFN2, "mod1.py"), "w") as fp:
1267 fp.write("print(42)\n")
1268
1269 with open(os.path.join(TESTFN2, "mod2.py"), "w") as fp:
1270 fp.write("print(42 * 42)\n")
1271
1272 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1273 zipfp.writepy(TESTFN2, filterfunc=lambda fn:
1274 not fn.endswith('mod2.py'))
1275
1276 names = zipfp.namelist()
1277 self.assertCompiledIn('mod1.py', names)
1278 self.assertNotIn('mod2.py', names)
1279
1280 finally:
Victor Stinner57004c62014-09-04 00:49:01 +02001281 rmtree(TESTFN2)
Christian Tismer410d9312013-10-22 04:09:28 +02001282
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001283 def test_write_non_pyfile(self):
1284 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1285 with open(TESTFN, 'w') as f:
1286 f.write('most definitely not a python file')
1287 self.assertRaises(RuntimeError, zipfp.writepy, TESTFN)
Victor Stinner88b215e2014-09-04 00:51:09 +02001288 unlink(TESTFN)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001289
1290 def test_write_pyfile_bad_syntax(self):
1291 os.mkdir(TESTFN2)
1292 try:
1293 with open(os.path.join(TESTFN2, "mod1.py"), "w") as fp:
1294 fp.write("Bad syntax in python file\n")
1295
1296 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1297 # syntax errors are printed to stdout
1298 with captured_stdout() as s:
1299 zipfp.writepy(os.path.join(TESTFN2, "mod1.py"))
1300
1301 self.assertIn("SyntaxError", s.getvalue())
1302
1303 # as it will not have compiled the python file, it will
Brett Cannonf299abd2015-04-13 14:21:02 -04001304 # include the .py file not .pyc
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001305 names = zipfp.namelist()
1306 self.assertIn('mod1.py', names)
1307 self.assertNotIn('mod1.pyc', names)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001308
1309 finally:
Victor Stinner57004c62014-09-04 00:49:01 +02001310 rmtree(TESTFN2)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001311
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001312 def test_write_pathlike(self):
1313 os.mkdir(TESTFN2)
1314 try:
1315 with open(os.path.join(TESTFN2, "mod1.py"), "w") as fp:
1316 fp.write("print(42)\n")
1317
1318 with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
1319 zipfp.writepy(pathlib.Path(TESTFN2) / "mod1.py")
1320 names = zipfp.namelist()
1321 self.assertCompiledIn('mod1.py', names)
1322 finally:
1323 rmtree(TESTFN2)
1324
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001325
1326class ExtractTests(unittest.TestCase):
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001327
1328 def make_test_file(self):
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001329 with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
1330 for fpath, fdata in SMALL_TEST_DATA:
1331 zipfp.writestr(fpath, fdata)
Christian Heimes790c8232008-01-07 21:14:23 +00001332
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001333 def test_extract(self):
1334 with temp_cwd():
1335 self.make_test_file()
1336 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
1337 for fpath, fdata in SMALL_TEST_DATA:
1338 writtenfile = zipfp.extract(fpath)
1339
1340 # make sure it was written to the right place
1341 correctfile = os.path.join(os.getcwd(), fpath)
1342 correctfile = os.path.normpath(correctfile)
1343
1344 self.assertEqual(writtenfile, correctfile)
1345
1346 # make sure correct data is in correct file
1347 with open(writtenfile, "rb") as f:
1348 self.assertEqual(fdata.encode(), f.read())
1349
1350 unlink(writtenfile)
1351
1352 def _test_extract_with_target(self, target):
1353 self.make_test_file()
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001354 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
1355 for fpath, fdata in SMALL_TEST_DATA:
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001356 writtenfile = zipfp.extract(fpath, target)
Christian Heimes790c8232008-01-07 21:14:23 +00001357
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001358 # make sure it was written to the right place
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001359 correctfile = os.path.join(target, fpath)
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001360 correctfile = os.path.normpath(correctfile)
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001361 self.assertTrue(os.path.samefile(writtenfile, correctfile), (writtenfile, target))
Christian Heimes790c8232008-01-07 21:14:23 +00001362
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001363 # make sure correct data is in correct file
Brian Curtin8fb9b862010-11-18 02:15:28 +00001364 with open(writtenfile, "rb") as f:
1365 self.assertEqual(fdata.encode(), f.read())
Christian Heimes790c8232008-01-07 21:14:23 +00001366
Victor Stinner88b215e2014-09-04 00:51:09 +02001367 unlink(writtenfile)
Christian Heimes790c8232008-01-07 21:14:23 +00001368
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001369 unlink(TESTFN2)
1370
1371 def test_extract_with_target(self):
1372 with temp_dir() as extdir:
1373 self._test_extract_with_target(extdir)
1374
1375 def test_extract_with_target_pathlike(self):
1376 with temp_dir() as extdir:
1377 self._test_extract_with_target(pathlib.Path(extdir))
Christian Heimes790c8232008-01-07 21:14:23 +00001378
Ezio Melottiafd0d112009-07-15 17:17:17 +00001379 def test_extract_all(self):
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001380 with temp_cwd():
1381 self.make_test_file()
1382 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
1383 zipfp.extractall()
1384 for fpath, fdata in SMALL_TEST_DATA:
1385 outfile = os.path.join(os.getcwd(), fpath)
Christian Heimes790c8232008-01-07 21:14:23 +00001386
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001387 with open(outfile, "rb") as f:
1388 self.assertEqual(fdata.encode(), f.read())
1389
1390 unlink(outfile)
1391
1392 def _test_extract_all_with_target(self, target):
1393 self.make_test_file()
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001394 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001395 zipfp.extractall(target)
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001396 for fpath, fdata in SMALL_TEST_DATA:
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001397 outfile = os.path.join(target, fpath)
Christian Heimes790c8232008-01-07 21:14:23 +00001398
Brian Curtin8fb9b862010-11-18 02:15:28 +00001399 with open(outfile, "rb") as f:
1400 self.assertEqual(fdata.encode(), f.read())
Christian Heimes790c8232008-01-07 21:14:23 +00001401
Victor Stinner88b215e2014-09-04 00:51:09 +02001402 unlink(outfile)
Christian Heimes790c8232008-01-07 21:14:23 +00001403
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001404 unlink(TESTFN2)
1405
1406 def test_extract_all_with_target(self):
1407 with temp_dir() as extdir:
1408 self._test_extract_all_with_target(extdir)
1409
1410 def test_extract_all_with_target_pathlike(self):
1411 with temp_dir() as extdir:
1412 self._test_extract_all_with_target(pathlib.Path(extdir))
Christian Heimes790c8232008-01-07 21:14:23 +00001413
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001414 def check_file(self, filename, content):
1415 self.assertTrue(os.path.isfile(filename))
1416 with open(filename, 'rb') as f:
1417 self.assertEqual(f.read(), content)
1418
Gregory P. Smith09aa7522013-02-03 00:36:32 -08001419 def test_sanitize_windows_name(self):
1420 san = zipfile.ZipFile._sanitize_windows_name
1421 # Passing pathsep in allows this test to work regardless of platform.
1422 self.assertEqual(san(r',,?,C:,foo,bar/z', ','), r'_,C_,foo,bar/z')
1423 self.assertEqual(san(r'a\b,c<d>e|f"g?h*i', ','), r'a\b,c_d_e_f_g_h_i')
1424 self.assertEqual(san('../../foo../../ba..r', '/'), r'foo/ba..r')
1425
1426 def test_extract_hackers_arcnames_common_cases(self):
1427 common_hacknames = [
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001428 ('../foo/bar', 'foo/bar'),
1429 ('foo/../bar', 'foo/bar'),
1430 ('foo/../../bar', 'foo/bar'),
1431 ('foo/bar/..', 'foo/bar'),
1432 ('./../foo/bar', 'foo/bar'),
1433 ('/foo/bar', 'foo/bar'),
1434 ('/foo/../bar', 'foo/bar'),
1435 ('/foo/../../bar', 'foo/bar'),
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001436 ]
Gregory P. Smith09aa7522013-02-03 00:36:32 -08001437 self._test_extract_hackers_arcnames(common_hacknames)
1438
1439 @unittest.skipIf(os.path.sep != '\\', 'Requires \\ as path separator.')
1440 def test_extract_hackers_arcnames_windows_only(self):
1441 """Test combination of path fixing and windows name sanitization."""
1442 windows_hacknames = [
Christian Tismer59202e52013-10-21 03:59:23 +02001443 (r'..\foo\bar', 'foo/bar'),
1444 (r'..\/foo\/bar', 'foo/bar'),
1445 (r'foo/\..\/bar', 'foo/bar'),
1446 (r'foo\/../\bar', 'foo/bar'),
1447 (r'C:foo/bar', 'foo/bar'),
1448 (r'C:/foo/bar', 'foo/bar'),
1449 (r'C://foo/bar', 'foo/bar'),
1450 (r'C:\foo\bar', 'foo/bar'),
1451 (r'//conky/mountpoint/foo/bar', 'foo/bar'),
1452 (r'\\conky\mountpoint\foo\bar', 'foo/bar'),
1453 (r'///conky/mountpoint/foo/bar', 'conky/mountpoint/foo/bar'),
1454 (r'\\\conky\mountpoint\foo\bar', 'conky/mountpoint/foo/bar'),
1455 (r'//conky//mountpoint/foo/bar', 'conky/mountpoint/foo/bar'),
1456 (r'\\conky\\mountpoint\foo\bar', 'conky/mountpoint/foo/bar'),
1457 (r'//?/C:/foo/bar', 'foo/bar'),
1458 (r'\\?\C:\foo\bar', 'foo/bar'),
1459 (r'C:/../C:/foo/bar', 'C_/foo/bar'),
1460 (r'a:b\c<d>e|f"g?h*i', 'b/c_d_e_f_g_h_i'),
1461 ('../../foo../../ba..r', 'foo/ba..r'),
Gregory P. Smith09aa7522013-02-03 00:36:32 -08001462 ]
1463 self._test_extract_hackers_arcnames(windows_hacknames)
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001464
Gregory P. Smith09aa7522013-02-03 00:36:32 -08001465 @unittest.skipIf(os.path.sep != '/', r'Requires / as path separator.')
1466 def test_extract_hackers_arcnames_posix_only(self):
1467 posix_hacknames = [
1468 ('//foo/bar', 'foo/bar'),
1469 ('../../foo../../ba..r', 'foo../ba..r'),
1470 (r'foo/..\bar', r'foo/..\bar'),
1471 ]
1472 self._test_extract_hackers_arcnames(posix_hacknames)
1473
1474 def _test_extract_hackers_arcnames(self, hacknames):
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001475 for arcname, fixedname in hacknames:
1476 content = b'foobar' + arcname.encode()
1477 with zipfile.ZipFile(TESTFN2, 'w', zipfile.ZIP_STORED) as zipfp:
Serhiy Storchakae5e64442013-02-02 19:50:59 +02001478 zinfo = zipfile.ZipInfo()
1479 # preserve backslashes
1480 zinfo.filename = arcname
1481 zinfo.external_attr = 0o600 << 16
1482 zipfp.writestr(zinfo, content)
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001483
Serhiy Storchakae5e64442013-02-02 19:50:59 +02001484 arcname = arcname.replace(os.sep, "/")
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001485 targetpath = os.path.join('target', 'subdir', 'subsub')
1486 correctfile = os.path.join(targetpath, *fixedname.split('/'))
1487
1488 with zipfile.ZipFile(TESTFN2, 'r') as zipfp:
1489 writtenfile = zipfp.extract(arcname, targetpath)
Serhiy Storchakae5e64442013-02-02 19:50:59 +02001490 self.assertEqual(writtenfile, correctfile,
Gregory P. Smith09aa7522013-02-03 00:36:32 -08001491 msg='extract %r: %r != %r' %
1492 (arcname, writtenfile, correctfile))
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001493 self.check_file(correctfile, content)
Victor Stinner57004c62014-09-04 00:49:01 +02001494 rmtree('target')
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001495
1496 with zipfile.ZipFile(TESTFN2, 'r') as zipfp:
1497 zipfp.extractall(targetpath)
1498 self.check_file(correctfile, content)
Victor Stinner57004c62014-09-04 00:49:01 +02001499 rmtree('target')
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001500
1501 correctfile = os.path.join(os.getcwd(), *fixedname.split('/'))
1502
1503 with zipfile.ZipFile(TESTFN2, 'r') as zipfp:
1504 writtenfile = zipfp.extract(arcname)
Serhiy Storchakae5e64442013-02-02 19:50:59 +02001505 self.assertEqual(writtenfile, correctfile,
1506 msg="extract %r" % arcname)
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001507 self.check_file(correctfile, content)
Victor Stinner57004c62014-09-04 00:49:01 +02001508 rmtree(fixedname.split('/')[0])
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001509
1510 with zipfile.ZipFile(TESTFN2, 'r') as zipfp:
1511 zipfp.extractall()
1512 self.check_file(correctfile, content)
Victor Stinner57004c62014-09-04 00:49:01 +02001513 rmtree(fixedname.split('/')[0])
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001514
Victor Stinner88b215e2014-09-04 00:51:09 +02001515 unlink(TESTFN2)
Gregory P. Smithb47acbf2013-02-01 11:22:43 -08001516
Ronald Oussorenee5c8852010-02-07 20:24:02 +00001517
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001518class OtherTests(unittest.TestCase):
1519 def test_open_via_zip_info(self):
1520 # Create the ZIP archive
1521 with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
1522 zipfp.writestr("name", "foo")
Serhiy Storchaka9b7a1a12014-01-20 21:57:40 +02001523 with self.assertWarns(UserWarning):
1524 zipfp.writestr("name", "bar")
1525 self.assertEqual(zipfp.namelist(), ["name"] * 2)
Ronald Oussorenee5c8852010-02-07 20:24:02 +00001526
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001527 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
1528 infos = zipfp.infolist()
1529 data = b""
1530 for info in infos:
1531 with zipfp.open(info) as zipopen:
1532 data += zipopen.read()
1533 self.assertIn(data, {b"foobar", b"barfoo"})
1534 data = b""
1535 for info in infos:
1536 data += zipfp.read(info)
1537 self.assertIn(data, {b"foobar", b"barfoo"})
Martin v. Löwisf6b16a42012-05-01 07:58:44 +02001538
Gregory P. Smithb0d9ca92009-07-07 05:06:04 +00001539 def test_writestr_extended_local_header_issue1202(self):
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001540 with zipfile.ZipFile(TESTFN2, 'w') as orig_zip:
1541 for data in 'abcdefghijklmnop':
1542 zinfo = zipfile.ZipInfo(data)
1543 zinfo.flag_bits |= 0x08 # Include an extended local header.
1544 orig_zip.writestr(zinfo, data)
1545
1546 def test_close(self):
1547 """Check that the zipfile is closed after the 'with' block."""
1548 with zipfile.ZipFile(TESTFN2, "w") as zipfp:
1549 for fpath, fdata in SMALL_TEST_DATA:
1550 zipfp.writestr(fpath, fdata)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001551 self.assertIsNotNone(zipfp.fp, 'zipfp is not open')
1552 self.assertIsNone(zipfp.fp, 'zipfp is not closed')
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001553
1554 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001555 self.assertIsNotNone(zipfp.fp, 'zipfp is not open')
1556 self.assertIsNone(zipfp.fp, 'zipfp is not closed')
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001557
1558 def test_close_on_exception(self):
1559 """Check that the zipfile is closed if an exception is raised in the
1560 'with' block."""
1561 with zipfile.ZipFile(TESTFN2, "w") as zipfp:
1562 for fpath, fdata in SMALL_TEST_DATA:
1563 zipfp.writestr(fpath, fdata)
1564
1565 try:
1566 with zipfile.ZipFile(TESTFN2, "r") as zipfp2:
Georg Brandl4d540882010-10-28 06:42:33 +00001567 raise zipfile.BadZipFile()
1568 except zipfile.BadZipFile:
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001569 self.assertIsNone(zipfp2.fp, 'zipfp is not closed')
Antoine Pitrou7c8bcb62010-08-12 15:11:50 +00001570
Martin v. Löwisd099b562012-05-01 14:08:22 +02001571 def test_unsupported_version(self):
1572 # File has an extract_version of 120
1573 data = (b'PK\x03\x04x\x00\x00\x00\x00\x00!p\xa1@\x00\x00\x00\x00\x00\x00'
Christian Tismer59202e52013-10-21 03:59:23 +02001574 b'\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00xPK\x01\x02x\x03x\x00\x00\x00\x00'
1575 b'\x00!p\xa1@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00'
1576 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01\x00\x00\x00\x00xPK\x05\x06'
1577 b'\x00\x00\x00\x00\x01\x00\x01\x00/\x00\x00\x00\x1f\x00\x00\x00\x00\x00')
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001578
Martin v. Löwisd099b562012-05-01 14:08:22 +02001579 self.assertRaises(NotImplementedError, zipfile.ZipFile,
1580 io.BytesIO(data), 'r')
1581
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001582 @requires_zlib
1583 def test_read_unicode_filenames(self):
1584 # bug #10801
1585 fname = findfile('zip_cp437_header.zip')
1586 with zipfile.ZipFile(fname) as zipfp:
1587 for name in zipfp.namelist():
1588 zipfp.open(name).close()
1589
1590 def test_write_unicode_filenames(self):
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001591 with zipfile.ZipFile(TESTFN, "w") as zf:
1592 zf.writestr("foo.txt", "Test for unicode filename")
1593 zf.writestr("\xf6.txt", "Test for unicode filename")
Ezio Melottie9615932010-01-24 19:26:24 +00001594 self.assertIsInstance(zf.infolist()[0].filename, str)
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001595
1596 with zipfile.ZipFile(TESTFN, "r") as zf:
1597 self.assertEqual(zf.filelist[0].filename, "foo.txt")
1598 self.assertEqual(zf.filelist[1].filename, "\xf6.txt")
Martin v. Löwis8570f6a2008-05-05 17:44:38 +00001599
Serhiy Storchaka764fc9b2015-03-25 10:09:41 +02001600 def test_exclusive_create_zip_file(self):
1601 """Test exclusive creating a new zipfile."""
1602 unlink(TESTFN2)
1603 filename = 'testfile.txt'
1604 content = b'hello, world. this is some content.'
1605 with zipfile.ZipFile(TESTFN2, "x", zipfile.ZIP_STORED) as zipfp:
1606 zipfp.writestr(filename, content)
1607 with self.assertRaises(FileExistsError):
1608 zipfile.ZipFile(TESTFN2, "x", zipfile.ZIP_STORED)
1609 with zipfile.ZipFile(TESTFN2, "r") as zipfp:
1610 self.assertEqual(zipfp.namelist(), [filename])
1611 self.assertEqual(zipfp.read(filename), content)
1612
Ezio Melottiafd0d112009-07-15 17:17:17 +00001613 def test_create_non_existent_file_for_append(self):
Thomas Wouterscf297e42007-02-23 15:07:44 +00001614 if os.path.exists(TESTFN):
1615 os.unlink(TESTFN)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001616
Thomas Wouterscf297e42007-02-23 15:07:44 +00001617 filename = 'testfile.txt'
Guido van Rossumd6ca5462007-05-22 01:29:33 +00001618 content = b'hello, world. this is some content.'
Guido van Rossumd8faa362007-04-27 19:54:29 +00001619
Thomas Wouterscf297e42007-02-23 15:07:44 +00001620 try:
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001621 with zipfile.ZipFile(TESTFN, 'a') as zf:
1622 zf.writestr(filename, content)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001623 except OSError:
Thomas Wouterscf297e42007-02-23 15:07:44 +00001624 self.fail('Could not append data to a non-existent zip file.')
1625
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001626 self.assertTrue(os.path.exists(TESTFN))
Thomas Wouterscf297e42007-02-23 15:07:44 +00001627
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001628 with zipfile.ZipFile(TESTFN, 'r') as zf:
1629 self.assertEqual(zf.read(filename), content)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001630
Ezio Melottiafd0d112009-07-15 17:17:17 +00001631 def test_close_erroneous_file(self):
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001632 # This test checks that the ZipFile constructor closes the file object
Ezio Melotti35386712009-12-31 13:22:41 +00001633 # it opens if there's an error in the file. If it doesn't, the
1634 # traceback holds a reference to the ZipFile object and, indirectly,
1635 # the file object.
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001636 # On Windows, this causes the os.unlink() call to fail because the
1637 # underlying file is still open. This is SF bug #412214.
1638 #
Ezio Melotti35386712009-12-31 13:22:41 +00001639 with open(TESTFN, "w") as fp:
1640 fp.write("this is not a legal zip file\n")
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001641 try:
1642 zf = zipfile.ZipFile(TESTFN)
Georg Brandl4d540882010-10-28 06:42:33 +00001643 except zipfile.BadZipFile:
Guido van Rossumd8faa362007-04-27 19:54:29 +00001644 pass
1645
Ezio Melottiafd0d112009-07-15 17:17:17 +00001646 def test_is_zip_erroneous_file(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001647 """Check that is_zipfile() correctly identifies non-zip files."""
Antoine Pitroudb5fe662008-12-27 15:50:40 +00001648 # - passing a filename
1649 with open(TESTFN, "w") as fp:
1650 fp.write("this is not a legal zip file\n")
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001651 self.assertFalse(zipfile.is_zipfile(TESTFN))
Serhiy Storchaka8606e952017-03-08 14:37:51 +02001652 # - passing a path-like object
1653 self.assertFalse(zipfile.is_zipfile(pathlib.Path(TESTFN)))
Antoine Pitroudb5fe662008-12-27 15:50:40 +00001654 # - passing a file object
1655 with open(TESTFN, "rb") as fp:
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001656 self.assertFalse(zipfile.is_zipfile(fp))
Antoine Pitroudb5fe662008-12-27 15:50:40 +00001657 # - passing a file-like object
1658 fp = io.BytesIO()
1659 fp.write(b"this is not a legal zip file\n")
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001660 self.assertFalse(zipfile.is_zipfile(fp))
Ezio Melotti35386712009-12-31 13:22:41 +00001661 fp.seek(0, 0)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001662 self.assertFalse(zipfile.is_zipfile(fp))
Guido van Rossumd8faa362007-04-27 19:54:29 +00001663
Serhiy Storchakad2b15272013-01-31 15:27:07 +02001664 def test_damaged_zipfile(self):
1665 """Check that zipfiles with missing bytes at the end raise BadZipFile."""
1666 # - Create a valid zip file
1667 fp = io.BytesIO()
1668 with zipfile.ZipFile(fp, mode="w") as zipf:
1669 zipf.writestr("foo.txt", b"O, for a Muse of Fire!")
1670 zipfiledata = fp.getvalue()
1671
1672 # - Now create copies of it missing the last N bytes and make sure
1673 # a BadZipFile exception is raised when we try to open it
1674 for N in range(len(zipfiledata)):
1675 fp = io.BytesIO(zipfiledata[:N])
1676 self.assertRaises(zipfile.BadZipFile, zipfile.ZipFile, fp)
1677
Ezio Melottiafd0d112009-07-15 17:17:17 +00001678 def test_is_zip_valid_file(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001679 """Check that is_zipfile() correctly identifies zip files."""
Antoine Pitroudb5fe662008-12-27 15:50:40 +00001680 # - passing a filename
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001681 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1682 zipf.writestr("foo.txt", b"O, for a Muse of Fire!")
1683
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001684 self.assertTrue(zipfile.is_zipfile(TESTFN))
Antoine Pitroudb5fe662008-12-27 15:50:40 +00001685 # - passing a file object
1686 with open(TESTFN, "rb") as fp:
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001687 self.assertTrue(zipfile.is_zipfile(fp))
Ezio Melotti35386712009-12-31 13:22:41 +00001688 fp.seek(0, 0)
Antoine Pitroudb5fe662008-12-27 15:50:40 +00001689 zip_contents = fp.read()
1690 # - passing a file-like object
1691 fp = io.BytesIO()
1692 fp.write(zip_contents)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001693 self.assertTrue(zipfile.is_zipfile(fp))
Ezio Melotti35386712009-12-31 13:22:41 +00001694 fp.seek(0, 0)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03001695 self.assertTrue(zipfile.is_zipfile(fp))
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001696
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001697 def test_non_existent_file_raises_OSError(self):
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001698 # make sure we don't raise an AttributeError when a partially-constructed
1699 # ZipFile instance is finalized; this tests for regression on SF tracker
1700 # bug #403871.
1701
1702 # The bug we're testing for caused an AttributeError to be raised
1703 # when a ZipFile instance was created for a file that did not
1704 # exist; the .fp member was not initialized but was needed by the
1705 # __del__() method. Since the AttributeError is in the __del__(),
1706 # it is ignored, but the user should be sufficiently annoyed by
1707 # the message on the output that regression will be noticed
1708 # quickly.
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001709 self.assertRaises(OSError, zipfile.ZipFile, TESTFN)
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001710
Amaury Forgeot d'Arcbc347802009-07-28 22:18:57 +00001711 def test_empty_file_raises_BadZipFile(self):
1712 f = open(TESTFN, 'w')
1713 f.close()
Georg Brandl4d540882010-10-28 06:42:33 +00001714 self.assertRaises(zipfile.BadZipFile, zipfile.ZipFile, TESTFN)
Amaury Forgeot d'Arcbc347802009-07-28 22:18:57 +00001715
Ezio Melotti35386712009-12-31 13:22:41 +00001716 with open(TESTFN, 'w') as fp:
1717 fp.write("short file")
Georg Brandl4d540882010-10-28 06:42:33 +00001718 self.assertRaises(zipfile.BadZipFile, zipfile.ZipFile, TESTFN)
Amaury Forgeot d'Arcbc347802009-07-28 22:18:57 +00001719
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001720 def test_closed_zip_raises_ValueError(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001721 """Verify that testzip() doesn't swallow inappropriate exceptions."""
Guido van Rossumd6ca5462007-05-22 01:29:33 +00001722 data = io.BytesIO()
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001723 with zipfile.ZipFile(data, mode="w") as zipf:
1724 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001725
Andrew Svetlov737fb892012-12-18 21:14:22 +02001726 # This is correct; calling .read on a closed ZipFile should raise
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001727 # a ValueError, and so should calling .testzip. An earlier
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001728 # version of .testzip would swallow this exception (and any other)
1729 # and report that the first file in the archive was corrupt.
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001730 self.assertRaises(ValueError, zipf.read, "foo.txt")
1731 self.assertRaises(ValueError, zipf.open, "foo.txt")
1732 self.assertRaises(ValueError, zipf.testzip)
1733 self.assertRaises(ValueError, zipf.writestr, "bogus.txt", "bogus")
Brian Curtin8fb9b862010-11-18 02:15:28 +00001734 with open(TESTFN, 'w') as f:
1735 f.write('zipfile test data')
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001736 self.assertRaises(ValueError, zipf.write, TESTFN)
Guido van Rossumb5a755e2007-07-18 18:15:48 +00001737
Ezio Melottiafd0d112009-07-15 17:17:17 +00001738 def test_bad_constructor_mode(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001739 """Check that bad modes passed to ZipFile constructor are caught."""
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001740 self.assertRaises(ValueError, zipfile.ZipFile, TESTFN, "q")
Guido van Rossumb5a755e2007-07-18 18:15:48 +00001741
Ezio Melottiafd0d112009-07-15 17:17:17 +00001742 def test_bad_open_mode(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001743 """Check that bad modes passed to ZipFile.open are caught."""
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001744 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1745 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1746
1747 with zipfile.ZipFile(TESTFN, mode="r") as zipf:
Serhiy Storchakae670be22016-06-11 19:32:44 +03001748 # read the data to make sure the file is there
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001749 zipf.read("foo.txt")
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001750 self.assertRaises(ValueError, zipf.open, "foo.txt", "q")
Serhiy Storchakae670be22016-06-11 19:32:44 +03001751 # universal newlines support is removed
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001752 self.assertRaises(ValueError, zipf.open, "foo.txt", "U")
1753 self.assertRaises(ValueError, zipf.open, "foo.txt", "rU")
Guido van Rossumb5a755e2007-07-18 18:15:48 +00001754
Ezio Melottiafd0d112009-07-15 17:17:17 +00001755 def test_read0(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001756 """Check that calling read(0) on a ZipExtFile object returns an empty
1757 string and doesn't advance file pointer."""
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001758 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1759 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1760 # read the data to make sure the file is there
Brian Curtin8fb9b862010-11-18 02:15:28 +00001761 with zipf.open("foo.txt") as f:
1762 for i in range(FIXEDTEST_SIZE):
1763 self.assertEqual(f.read(0), b'')
Guido van Rossumb5a755e2007-07-18 18:15:48 +00001764
Brian Curtin8fb9b862010-11-18 02:15:28 +00001765 self.assertEqual(f.read(), b"O, for a Muse of Fire!")
Guido van Rossumb5a755e2007-07-18 18:15:48 +00001766
Ezio Melottiafd0d112009-07-15 17:17:17 +00001767 def test_open_non_existent_item(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001768 """Check that attempting to call open() for an item that doesn't
1769 exist in the archive raises a RuntimeError."""
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001770 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1771 self.assertRaises(KeyError, zipf.open, "foo.txt", "r")
Guido van Rossumb5a755e2007-07-18 18:15:48 +00001772
Ezio Melottiafd0d112009-07-15 17:17:17 +00001773 def test_bad_compression_mode(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001774 """Check that bad compression methods passed to ZipFile.open are
1775 caught."""
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001776 self.assertRaises(NotImplementedError, zipfile.ZipFile, TESTFN, "w", -1)
Guido van Rossumb5a755e2007-07-18 18:15:48 +00001777
Martin v. Löwisb3260f02012-05-01 08:38:01 +02001778 def test_unsupported_compression(self):
1779 # data is declared as shrunk, but actually deflated
1780 data = (b'PK\x03\x04.\x00\x00\x00\x01\x00\xe4C\xa1@\x00\x00\x00'
Christian Tismer59202e52013-10-21 03:59:23 +02001781 b'\x00\x02\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00x\x03\x00PK\x01'
1782 b'\x02.\x03.\x00\x00\x00\x01\x00\xe4C\xa1@\x00\x00\x00\x00\x02\x00\x00'
1783 b'\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
1784 b'\x80\x01\x00\x00\x00\x00xPK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x00'
1785 b'/\x00\x00\x00!\x00\x00\x00\x00\x00')
Martin v. Löwisb3260f02012-05-01 08:38:01 +02001786 with zipfile.ZipFile(io.BytesIO(data), 'r') as zipf:
1787 self.assertRaises(NotImplementedError, zipf.open, 'x')
1788
Ezio Melottiafd0d112009-07-15 17:17:17 +00001789 def test_null_byte_in_filename(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001790 """Check that a filename containing a null byte is properly
1791 terminated."""
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001792 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1793 zipf.writestr("foo.txt\x00qqq", b"O, for a Muse of Fire!")
1794 self.assertEqual(zipf.namelist(), ['foo.txt'])
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00001795
Ezio Melottiafd0d112009-07-15 17:17:17 +00001796 def test_struct_sizes(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001797 """Check that ZIP internal structure sizes are calculated correctly."""
Martin v. Löwisb09b8442008-07-03 14:13:42 +00001798 self.assertEqual(zipfile.sizeEndCentDir, 22)
1799 self.assertEqual(zipfile.sizeCentralDir, 46)
1800 self.assertEqual(zipfile.sizeEndCentDir64, 56)
1801 self.assertEqual(zipfile.sizeEndCentDir64Locator, 20)
1802
Ezio Melottiafd0d112009-07-15 17:17:17 +00001803 def test_comments(self):
Ezio Melotti35386712009-12-31 13:22:41 +00001804 """Check that comments on the archive are handled properly."""
Martin v. Löwisb09b8442008-07-03 14:13:42 +00001805
1806 # check default comment is empty
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001807 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1808 self.assertEqual(zipf.comment, b'')
1809 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1810
1811 with zipfile.ZipFile(TESTFN, mode="r") as zipfr:
1812 self.assertEqual(zipfr.comment, b'')
Martin v. Löwisb09b8442008-07-03 14:13:42 +00001813
1814 # check a simple short comment
1815 comment = b'Bravely taking to his feet, he beat a very brave retreat.'
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001816 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1817 zipf.comment = comment
1818 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1819 with zipfile.ZipFile(TESTFN, mode="r") as zipfr:
1820 self.assertEqual(zipf.comment, comment)
Martin v. Löwisb09b8442008-07-03 14:13:42 +00001821
1822 # check a comment of max length
1823 comment2 = ''.join(['%d' % (i**3 % 10) for i in range((1 << 16)-1)])
1824 comment2 = comment2.encode("ascii")
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001825 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
1826 zipf.comment = comment2
1827 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1828
1829 with zipfile.ZipFile(TESTFN, mode="r") as zipfr:
1830 self.assertEqual(zipfr.comment, comment2)
Martin v. Löwisb09b8442008-07-03 14:13:42 +00001831
1832 # check a comment that is too long is truncated
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001833 with zipfile.ZipFile(TESTFN, mode="w") as zipf:
Serhiy Storchaka9b7a1a12014-01-20 21:57:40 +02001834 with self.assertWarns(UserWarning):
1835 zipf.comment = comment2 + b'oops'
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00001836 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1837 with zipfile.ZipFile(TESTFN, mode="r") as zipfr:
1838 self.assertEqual(zipfr.comment, comment2)
Martin v. Löwisb09b8442008-07-03 14:13:42 +00001839
Antoine Pitrouc3991852012-06-30 17:31:37 +02001840 # check that comments are correctly modified in append mode
1841 with zipfile.ZipFile(TESTFN,mode="w") as zipf:
1842 zipf.comment = b"original comment"
1843 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1844 with zipfile.ZipFile(TESTFN,mode="a") as zipf:
1845 zipf.comment = b"an updated comment"
1846 with zipfile.ZipFile(TESTFN,mode="r") as zipf:
1847 self.assertEqual(zipf.comment, b"an updated comment")
1848
1849 # check that comments are correctly shortened in append mode
1850 with zipfile.ZipFile(TESTFN,mode="w") as zipf:
1851 zipf.comment = b"original comment that's longer"
1852 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1853 with zipfile.ZipFile(TESTFN,mode="a") as zipf:
1854 zipf.comment = b"shorter comment"
1855 with zipfile.ZipFile(TESTFN,mode="r") as zipf:
1856 self.assertEqual(zipf.comment, b"shorter comment")
1857
R David Murrayf50b38a2012-04-12 18:44:58 -04001858 def test_unicode_comment(self):
1859 with zipfile.ZipFile(TESTFN, "w", zipfile.ZIP_STORED) as zipf:
1860 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1861 with self.assertRaises(TypeError):
1862 zipf.comment = "this is an error"
1863
1864 def test_change_comment_in_empty_archive(self):
1865 with zipfile.ZipFile(TESTFN, "a", zipfile.ZIP_STORED) as zipf:
1866 self.assertFalse(zipf.filelist)
1867 zipf.comment = b"this is a comment"
1868 with zipfile.ZipFile(TESTFN, "r") as zipf:
1869 self.assertEqual(zipf.comment, b"this is a comment")
1870
1871 def test_change_comment_in_nonempty_archive(self):
1872 with zipfile.ZipFile(TESTFN, "w", zipfile.ZIP_STORED) as zipf:
1873 zipf.writestr("foo.txt", "O, for a Muse of Fire!")
1874 with zipfile.ZipFile(TESTFN, "a", zipfile.ZIP_STORED) as zipf:
1875 self.assertTrue(zipf.filelist)
1876 zipf.comment = b"this is a comment"
1877 with zipfile.ZipFile(TESTFN, "r") as zipf:
1878 self.assertEqual(zipf.comment, b"this is a comment")
1879
Georg Brandl268e4d42010-10-14 06:59:45 +00001880 def test_empty_zipfile(self):
1881 # Check that creating a file in 'w' or 'a' mode and closing without
1882 # adding any files to the archives creates a valid empty ZIP file
1883 zipf = zipfile.ZipFile(TESTFN, mode="w")
1884 zipf.close()
1885 try:
1886 zipf = zipfile.ZipFile(TESTFN, mode="r")
1887 except zipfile.BadZipFile:
1888 self.fail("Unable to create empty ZIP file in 'w' mode")
1889
1890 zipf = zipfile.ZipFile(TESTFN, mode="a")
1891 zipf.close()
1892 try:
1893 zipf = zipfile.ZipFile(TESTFN, mode="r")
1894 except:
1895 self.fail("Unable to create empty ZIP file in 'a' mode")
1896
1897 def test_open_empty_file(self):
1898 # Issue 1710703: Check that opening a file with less than 22 bytes
Georg Brandl4d540882010-10-28 06:42:33 +00001899 # raises a BadZipFile exception (rather than the previously unhelpful
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001900 # OSError)
Georg Brandl268e4d42010-10-14 06:59:45 +00001901 f = open(TESTFN, 'w')
1902 f.close()
Georg Brandl4d540882010-10-28 06:42:33 +00001903 self.assertRaises(zipfile.BadZipFile, zipfile.ZipFile, TESTFN, 'r')
Georg Brandl268e4d42010-10-14 06:59:45 +00001904
Senthil Kumaran29fa9d42011-10-20 01:46:00 +08001905 def test_create_zipinfo_before_1980(self):
1906 self.assertRaises(ValueError,
1907 zipfile.ZipInfo, 'seventies', (1979, 1, 1, 0, 0, 0))
1908
Mickaël Schoentgen992347d2019-09-09 15:08:54 +02001909 def test_create_empty_zipinfo_repr(self):
1910 """Before bpo-26185, repr() on empty ZipInfo object was failing."""
1911 zi = zipfile.ZipInfo(filename="empty")
1912 self.assertEqual(repr(zi), "<ZipInfo filename='empty' file_size=0>")
1913
1914 def test_create_empty_zipinfo_default_attributes(self):
1915 """Ensure all required attributes are set."""
1916 zi = zipfile.ZipInfo()
1917 self.assertEqual(zi.orig_filename, "NoName")
1918 self.assertEqual(zi.filename, "NoName")
1919 self.assertEqual(zi.date_time, (1980, 1, 1, 0, 0, 0))
1920 self.assertEqual(zi.compress_type, zipfile.ZIP_STORED)
1921 self.assertEqual(zi.comment, b"")
1922 self.assertEqual(zi.extra, b"")
1923 self.assertIn(zi.create_system, (0, 3))
1924 self.assertEqual(zi.create_version, zipfile.DEFAULT_VERSION)
1925 self.assertEqual(zi.extract_version, zipfile.DEFAULT_VERSION)
1926 self.assertEqual(zi.reserved, 0)
1927 self.assertEqual(zi.flag_bits, 0)
1928 self.assertEqual(zi.volume, 0)
1929 self.assertEqual(zi.internal_attr, 0)
1930 self.assertEqual(zi.external_attr, 0)
1931
1932 # Before bpo-26185, both were missing
1933 self.assertEqual(zi.file_size, 0)
1934 self.assertEqual(zi.compress_size, 0)
1935
Gregory P. Smith0af8a862014-05-29 23:42:14 -07001936 def test_zipfile_with_short_extra_field(self):
1937 """If an extra field in the header is less than 4 bytes, skip it."""
1938 zipdata = (
1939 b'PK\x03\x04\x14\x00\x00\x00\x00\x00\x93\x9b\xad@\x8b\x9e'
1940 b'\xd9\xd3\x01\x00\x00\x00\x01\x00\x00\x00\x03\x00\x03\x00ab'
1941 b'c\x00\x00\x00APK\x01\x02\x14\x03\x14\x00\x00\x00\x00'
1942 b'\x00\x93\x9b\xad@\x8b\x9e\xd9\xd3\x01\x00\x00\x00\x01\x00\x00'
1943 b'\x00\x03\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x00'
1944 b'\x00\x00\x00abc\x00\x00PK\x05\x06\x00\x00\x00\x00'
1945 b'\x01\x00\x01\x003\x00\x00\x00%\x00\x00\x00\x00\x00'
1946 )
1947 with zipfile.ZipFile(io.BytesIO(zipdata), 'r') as zipf:
1948 # testzip returns the name of the first corrupt file, or None
1949 self.assertIsNone(zipf.testzip())
1950
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03001951 def test_open_conflicting_handles(self):
1952 # It's only possible to open one writable file handle at a time
1953 msg1 = b"It's fun to charter an accountant!"
1954 msg2 = b"And sail the wide accountant sea"
1955 msg3 = b"To find, explore the funds offshore"
1956 with zipfile.ZipFile(TESTFN2, 'w', zipfile.ZIP_STORED) as zipf:
1957 with zipf.open('foo', mode='w') as w2:
1958 w2.write(msg1)
1959 with zipf.open('bar', mode='w') as w1:
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001960 with self.assertRaises(ValueError):
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03001961 zipf.open('handle', mode='w')
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001962 with self.assertRaises(ValueError):
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03001963 zipf.open('foo', mode='r')
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001964 with self.assertRaises(ValueError):
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03001965 zipf.writestr('str', 'abcde')
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001966 with self.assertRaises(ValueError):
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03001967 zipf.write(__file__, 'file')
Serhiy Storchakab0d497c2016-09-10 21:28:07 +03001968 with self.assertRaises(ValueError):
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03001969 zipf.close()
1970 w1.write(msg2)
1971 with zipf.open('baz', mode='w') as w2:
1972 w2.write(msg3)
1973
1974 with zipfile.ZipFile(TESTFN2, 'r') as zipf:
1975 self.assertEqual(zipf.read('foo'), msg1)
1976 self.assertEqual(zipf.read('bar'), msg2)
1977 self.assertEqual(zipf.read('baz'), msg3)
1978 self.assertEqual(zipf.namelist(), ['foo', 'bar', 'baz'])
1979
John Jolly066df4f2018-01-30 01:51:35 -07001980 def test_seek_tell(self):
1981 # Test seek functionality
1982 txt = b"Where's Bruce?"
1983 bloc = txt.find(b"Bruce")
1984 # Check seek on a file
1985 with zipfile.ZipFile(TESTFN, "w") as zipf:
1986 zipf.writestr("foo.txt", txt)
1987 with zipfile.ZipFile(TESTFN, "r") as zipf:
1988 with zipf.open("foo.txt", "r") as fp:
1989 fp.seek(bloc, os.SEEK_SET)
1990 self.assertEqual(fp.tell(), bloc)
1991 fp.seek(-bloc, os.SEEK_CUR)
1992 self.assertEqual(fp.tell(), 0)
1993 fp.seek(bloc, os.SEEK_CUR)
1994 self.assertEqual(fp.tell(), bloc)
1995 self.assertEqual(fp.read(5), txt[bloc:bloc+5])
1996 fp.seek(0, os.SEEK_END)
1997 self.assertEqual(fp.tell(), len(txt))
Mickaël Schoentgen3f8c6912018-07-29 20:26:52 +02001998 fp.seek(0, os.SEEK_SET)
1999 self.assertEqual(fp.tell(), 0)
John Jolly066df4f2018-01-30 01:51:35 -07002000 # Check seek on memory file
2001 data = io.BytesIO()
2002 with zipfile.ZipFile(data, mode="w") as zipf:
2003 zipf.writestr("foo.txt", txt)
2004 with zipfile.ZipFile(data, mode="r") as zipf:
2005 with zipf.open("foo.txt", "r") as fp:
2006 fp.seek(bloc, os.SEEK_SET)
2007 self.assertEqual(fp.tell(), bloc)
2008 fp.seek(-bloc, os.SEEK_CUR)
2009 self.assertEqual(fp.tell(), 0)
2010 fp.seek(bloc, os.SEEK_CUR)
2011 self.assertEqual(fp.tell(), bloc)
2012 self.assertEqual(fp.read(5), txt[bloc:bloc+5])
2013 fp.seek(0, os.SEEK_END)
2014 self.assertEqual(fp.tell(), len(txt))
Mickaël Schoentgen3f8c6912018-07-29 20:26:52 +02002015 fp.seek(0, os.SEEK_SET)
2016 self.assertEqual(fp.tell(), 0)
John Jolly066df4f2018-01-30 01:51:35 -07002017
Berker Peksag2f1b8572019-09-12 17:13:44 +03002018 @requires_bz2
2019 def test_decompress_without_3rd_party_library(self):
2020 data = b'PK\x05\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
2021 zip_file = io.BytesIO(data)
2022 with zipfile.ZipFile(zip_file, 'w', compression=zipfile.ZIP_BZIP2) as zf:
2023 zf.writestr('a.txt', b'a')
2024 with mock.patch('zipfile.bz2', None):
2025 with zipfile.ZipFile(zip_file) as zf:
2026 self.assertRaises(RuntimeError, zf.extract, 'a.txt')
2027
Guido van Rossumd8faa362007-04-27 19:54:29 +00002028 def tearDown(self):
Ezio Melotti76430242009-07-11 18:28:48 +00002029 unlink(TESTFN)
2030 unlink(TESTFN2)
2031
Thomas Wouterscf297e42007-02-23 15:07:44 +00002032
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002033class AbstractBadCrcTests:
2034 def test_testzip_with_bad_crc(self):
2035 """Tests that files with bad CRCs return their name from testzip."""
2036 zipdata = self.zip_with_bad_crc
2037
2038 with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf:
2039 # testzip returns the name of the first corrupt file, or None
2040 self.assertEqual('afile', zipf.testzip())
2041
2042 def test_read_with_bad_crc(self):
2043 """Tests that files with bad CRCs raise a BadZipFile exception when read."""
2044 zipdata = self.zip_with_bad_crc
2045
2046 # Using ZipFile.read()
2047 with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf:
2048 self.assertRaises(zipfile.BadZipFile, zipf.read, 'afile')
2049
2050 # Using ZipExtFile.read()
2051 with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf:
2052 with zipf.open('afile', 'r') as corrupt_file:
2053 self.assertRaises(zipfile.BadZipFile, corrupt_file.read)
2054
2055 # Same with small reads (in order to exercise the buffering logic)
2056 with zipfile.ZipFile(io.BytesIO(zipdata), mode="r") as zipf:
2057 with zipf.open('afile', 'r') as corrupt_file:
2058 corrupt_file.MIN_READ_SIZE = 2
2059 with self.assertRaises(zipfile.BadZipFile):
2060 while corrupt_file.read(2):
2061 pass
2062
2063
2064class StoredBadCrcTests(AbstractBadCrcTests, unittest.TestCase):
2065 compression = zipfile.ZIP_STORED
2066 zip_with_bad_crc = (
Christian Tismer59202e52013-10-21 03:59:23 +02002067 b'PK\003\004\024\0\0\0\0\0 \213\212;:r'
2068 b'\253\377\f\0\0\0\f\0\0\0\005\0\0\000af'
2069 b'ilehello,AworldP'
2070 b'K\001\002\024\003\024\0\0\0\0\0 \213\212;:'
2071 b'r\253\377\f\0\0\0\f\0\0\0\005\0\0\0\0'
2072 b'\0\0\0\0\0\0\0\200\001\0\0\0\000afi'
2073 b'lePK\005\006\0\0\0\0\001\0\001\0003\000'
2074 b'\0\0/\0\0\0\0\0')
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002075
2076@requires_zlib
2077class DeflateBadCrcTests(AbstractBadCrcTests, unittest.TestCase):
2078 compression = zipfile.ZIP_DEFLATED
2079 zip_with_bad_crc = (
Christian Tismer59202e52013-10-21 03:59:23 +02002080 b'PK\x03\x04\x14\x00\x00\x00\x08\x00n}\x0c=FA'
2081 b'KE\x10\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00af'
2082 b'ile\xcbH\xcd\xc9\xc9W(\xcf/\xcaI\xc9\xa0'
2083 b'=\x13\x00PK\x01\x02\x14\x03\x14\x00\x00\x00\x08\x00n'
2084 b'}\x0c=FAKE\x10\x00\x00\x00n\x00\x00\x00\x05'
2085 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01\x00\x00\x00'
2086 b'\x00afilePK\x05\x06\x00\x00\x00\x00\x01\x00'
2087 b'\x01\x003\x00\x00\x003\x00\x00\x00\x00\x00')
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002088
2089@requires_bz2
2090class Bzip2BadCrcTests(AbstractBadCrcTests, unittest.TestCase):
2091 compression = zipfile.ZIP_BZIP2
2092 zip_with_bad_crc = (
Christian Tismer59202e52013-10-21 03:59:23 +02002093 b'PK\x03\x04\x14\x03\x00\x00\x0c\x00nu\x0c=FA'
2094 b'KE8\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00af'
2095 b'ileBZh91AY&SY\xd4\xa8\xca'
2096 b'\x7f\x00\x00\x0f\x11\x80@\x00\x06D\x90\x80 \x00 \xa5'
2097 b'P\xd9!\x03\x03\x13\x13\x13\x89\xa9\xa9\xc2u5:\x9f'
2098 b'\x8b\xb9"\x9c(HjTe?\x80PK\x01\x02\x14'
2099 b'\x03\x14\x03\x00\x00\x0c\x00nu\x0c=FAKE8'
2100 b'\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00'
2101 b'\x00 \x80\x80\x81\x00\x00\x00\x00afilePK'
2102 b'\x05\x06\x00\x00\x00\x00\x01\x00\x01\x003\x00\x00\x00[\x00'
2103 b'\x00\x00\x00\x00')
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002104
2105@requires_lzma
2106class LzmaBadCrcTests(AbstractBadCrcTests, unittest.TestCase):
2107 compression = zipfile.ZIP_LZMA
2108 zip_with_bad_crc = (
Christian Tismer59202e52013-10-21 03:59:23 +02002109 b'PK\x03\x04\x14\x03\x00\x00\x0e\x00nu\x0c=FA'
2110 b'KE\x1b\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00af'
2111 b'ile\t\x04\x05\x00]\x00\x00\x00\x04\x004\x19I'
2112 b'\xee\x8d\xe9\x17\x89:3`\tq!.8\x00PK'
2113 b'\x01\x02\x14\x03\x14\x03\x00\x00\x0e\x00nu\x0c=FA'
2114 b'KE\x1b\x00\x00\x00n\x00\x00\x00\x05\x00\x00\x00\x00\x00'
2115 b'\x00\x00\x00\x00 \x80\x80\x81\x00\x00\x00\x00afil'
2116 b'ePK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x003\x00\x00'
2117 b'\x00>\x00\x00\x00\x00\x00')
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002118
2119
Thomas Wouterscf297e42007-02-23 15:07:44 +00002120class DecryptionTests(unittest.TestCase):
Ezio Melotti35386712009-12-31 13:22:41 +00002121 """Check that ZIP decryption works. Since the library does not
2122 support encryption at the moment, we use a pre-generated encrypted
2123 ZIP file."""
Thomas Wouterscf297e42007-02-23 15:07:44 +00002124
2125 data = (
Christian Tismer59202e52013-10-21 03:59:23 +02002126 b'PK\x03\x04\x14\x00\x01\x00\x00\x00n\x92i.#y\xef?&\x00\x00\x00\x1a\x00'
2127 b'\x00\x00\x08\x00\x00\x00test.txt\xfa\x10\xa0gly|\xfa-\xc5\xc0=\xf9y'
2128 b'\x18\xe0\xa8r\xb3Z}Lg\xbc\xae\xf9|\x9b\x19\xe4\x8b\xba\xbb)\x8c\xb0\xdbl'
2129 b'PK\x01\x02\x14\x00\x14\x00\x01\x00\x00\x00n\x92i.#y\xef?&\x00\x00\x00'
2130 b'\x1a\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x01\x00 \x00\xb6\x81'
2131 b'\x00\x00\x00\x00test.txtPK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x006\x00'
2132 b'\x00\x00L\x00\x00\x00\x00\x00' )
Christian Heimesfdab48e2008-01-20 09:06:41 +00002133 data2 = (
Christian Tismer59202e52013-10-21 03:59:23 +02002134 b'PK\x03\x04\x14\x00\t\x00\x08\x00\xcf}38xu\xaa\xb2\x14\x00\x00\x00\x00\x02'
2135 b'\x00\x00\x04\x00\x15\x00zeroUT\t\x00\x03\xd6\x8b\x92G\xda\x8b\x92GUx\x04'
2136 b'\x00\xe8\x03\xe8\x03\xc7<M\xb5a\xceX\xa3Y&\x8b{oE\xd7\x9d\x8c\x98\x02\xc0'
2137 b'PK\x07\x08xu\xaa\xb2\x14\x00\x00\x00\x00\x02\x00\x00PK\x01\x02\x17\x03'
2138 b'\x14\x00\t\x00\x08\x00\xcf}38xu\xaa\xb2\x14\x00\x00\x00\x00\x02\x00\x00'
2139 b'\x04\x00\r\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x00\x00\x00\x00ze'
2140 b'roUT\x05\x00\x03\xd6\x8b\x92GUx\x00\x00PK\x05\x06\x00\x00\x00\x00\x01'
2141 b'\x00\x01\x00?\x00\x00\x00[\x00\x00\x00\x00\x00' )
Thomas Wouterscf297e42007-02-23 15:07:44 +00002142
Guido van Rossumd6ca5462007-05-22 01:29:33 +00002143 plain = b'zipfile.py encryption test'
Christian Heimesfdab48e2008-01-20 09:06:41 +00002144 plain2 = b'\x00'*512
Thomas Wouterscf297e42007-02-23 15:07:44 +00002145
2146 def setUp(self):
Ezio Melotti35386712009-12-31 13:22:41 +00002147 with open(TESTFN, "wb") as fp:
2148 fp.write(self.data)
Thomas Wouterscf297e42007-02-23 15:07:44 +00002149 self.zip = zipfile.ZipFile(TESTFN, "r")
Ezio Melotti35386712009-12-31 13:22:41 +00002150 with open(TESTFN2, "wb") as fp:
2151 fp.write(self.data2)
Christian Heimesfdab48e2008-01-20 09:06:41 +00002152 self.zip2 = zipfile.ZipFile(TESTFN2, "r")
Thomas Wouterscf297e42007-02-23 15:07:44 +00002153
2154 def tearDown(self):
2155 self.zip.close()
2156 os.unlink(TESTFN)
Christian Heimesfdab48e2008-01-20 09:06:41 +00002157 self.zip2.close()
2158 os.unlink(TESTFN2)
Thomas Wouterscf297e42007-02-23 15:07:44 +00002159
Ezio Melottiafd0d112009-07-15 17:17:17 +00002160 def test_no_password(self):
Thomas Wouterscf297e42007-02-23 15:07:44 +00002161 # Reading the encrypted file without password
2162 # must generate a RunTime exception
2163 self.assertRaises(RuntimeError, self.zip.read, "test.txt")
Christian Heimesfdab48e2008-01-20 09:06:41 +00002164 self.assertRaises(RuntimeError, self.zip2.read, "zero")
Thomas Wouterscf297e42007-02-23 15:07:44 +00002165
Ezio Melottiafd0d112009-07-15 17:17:17 +00002166 def test_bad_password(self):
Guido van Rossumd6ca5462007-05-22 01:29:33 +00002167 self.zip.setpassword(b"perl")
Thomas Wouterscf297e42007-02-23 15:07:44 +00002168 self.assertRaises(RuntimeError, self.zip.read, "test.txt")
Christian Heimesfdab48e2008-01-20 09:06:41 +00002169 self.zip2.setpassword(b"perl")
2170 self.assertRaises(RuntimeError, self.zip2.read, "zero")
Guido van Rossumd8faa362007-04-27 19:54:29 +00002171
Ezio Melotti975077a2011-05-19 22:03:22 +03002172 @requires_zlib
Ezio Melottiafd0d112009-07-15 17:17:17 +00002173 def test_good_password(self):
Guido van Rossumd6ca5462007-05-22 01:29:33 +00002174 self.zip.setpassword(b"python")
Ezio Melotti35386712009-12-31 13:22:41 +00002175 self.assertEqual(self.zip.read("test.txt"), self.plain)
Christian Heimesfdab48e2008-01-20 09:06:41 +00002176 self.zip2.setpassword(b"12345")
Ezio Melotti35386712009-12-31 13:22:41 +00002177 self.assertEqual(self.zip2.read("zero"), self.plain2)
Thomas Wouterscf297e42007-02-23 15:07:44 +00002178
R. David Murray8d855d82010-12-21 21:53:37 +00002179 def test_unicode_password(self):
2180 self.assertRaises(TypeError, self.zip.setpassword, "unicode")
2181 self.assertRaises(TypeError, self.zip.read, "test.txt", "python")
2182 self.assertRaises(TypeError, self.zip.open, "test.txt", pwd="python")
2183 self.assertRaises(TypeError, self.zip.extract, "test.txt", pwd="python")
2184
Serhiy Storchaka5c32af72019-10-27 10:22:14 +02002185 def test_seek_tell(self):
2186 self.zip.setpassword(b"python")
2187 txt = self.plain
2188 test_word = b'encryption'
2189 bloc = txt.find(test_word)
2190 bloc_len = len(test_word)
2191 with self.zip.open("test.txt", "r") as fp:
2192 fp.seek(bloc, os.SEEK_SET)
2193 self.assertEqual(fp.tell(), bloc)
2194 fp.seek(-bloc, os.SEEK_CUR)
2195 self.assertEqual(fp.tell(), 0)
2196 fp.seek(bloc, os.SEEK_CUR)
2197 self.assertEqual(fp.tell(), bloc)
2198 self.assertEqual(fp.read(bloc_len), txt[bloc:bloc+bloc_len])
2199
2200 # Make sure that the second read after seeking back beyond
2201 # _readbuffer returns the same content (ie. rewind to the start of
2202 # the file to read forward to the required position).
2203 old_read_size = fp.MIN_READ_SIZE
2204 fp.MIN_READ_SIZE = 1
2205 fp._readbuffer = b''
2206 fp._offset = 0
2207 fp.seek(0, os.SEEK_SET)
2208 self.assertEqual(fp.tell(), 0)
2209 fp.seek(bloc, os.SEEK_CUR)
2210 self.assertEqual(fp.read(bloc_len), txt[bloc:bloc+bloc_len])
2211 fp.MIN_READ_SIZE = old_read_size
2212
2213 fp.seek(0, os.SEEK_END)
2214 self.assertEqual(fp.tell(), len(txt))
2215 fp.seek(0, os.SEEK_SET)
2216 self.assertEqual(fp.tell(), 0)
2217
2218 # Read the file completely to definitely call any eof integrity
2219 # checks (crc) and make sure they still pass.
2220 fp.read()
2221
2222
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002223class AbstractTestsWithRandomBinaryFiles:
2224 @classmethod
2225 def setUpClass(cls):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002226 datacount = randint(16, 64)*1024 + randint(1, 1024)
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002227 cls.data = b''.join(struct.pack('<f', random()*randint(-1000, 1000))
2228 for i in range(datacount))
Guido van Rossumd8faa362007-04-27 19:54:29 +00002229
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002230 def setUp(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002231 # Make a source file with some lines
Ezio Melotti35386712009-12-31 13:22:41 +00002232 with open(TESTFN, "wb") as fp:
2233 fp.write(self.data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002234
2235 def tearDown(self):
Ezio Melotti76430242009-07-11 18:28:48 +00002236 unlink(TESTFN)
2237 unlink(TESTFN2)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002238
Ezio Melottiafd0d112009-07-15 17:17:17 +00002239 def make_test_archive(self, f, compression):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002240 # Create the ZIP archive
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002241 with zipfile.ZipFile(f, "w", compression) as zipfp:
2242 zipfp.write(TESTFN, "another.name")
2243 zipfp.write(TESTFN, TESTFN)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002244
Ezio Melottiafd0d112009-07-15 17:17:17 +00002245 def zip_test(self, f, compression):
2246 self.make_test_archive(f, compression)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002247
2248 # Read the ZIP archive
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002249 with zipfile.ZipFile(f, "r", compression) as zipfp:
2250 testdata = zipfp.read(TESTFN)
2251 self.assertEqual(len(testdata), len(self.data))
2252 self.assertEqual(testdata, self.data)
2253 self.assertEqual(zipfp.read("another.name"), self.data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002254
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002255 def test_read(self):
2256 for f in get_files(self):
2257 self.zip_test(f, self.compression)
Martin v. Löwis7fb79fc2012-05-13 10:06:36 +02002258
Ezio Melottiafd0d112009-07-15 17:17:17 +00002259 def zip_open_test(self, f, compression):
2260 self.make_test_archive(f, compression)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002261
2262 # Read the ZIP archive
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002263 with zipfile.ZipFile(f, "r", compression) as zipfp:
2264 zipdata1 = []
Brian Curtin8fb9b862010-11-18 02:15:28 +00002265 with zipfp.open(TESTFN) as zipopen1:
2266 while True:
2267 read_data = zipopen1.read(256)
2268 if not read_data:
2269 break
2270 zipdata1.append(read_data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002271
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002272 zipdata2 = []
Brian Curtin8fb9b862010-11-18 02:15:28 +00002273 with zipfp.open("another.name") as zipopen2:
2274 while True:
2275 read_data = zipopen2.read(256)
2276 if not read_data:
2277 break
2278 zipdata2.append(read_data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002279
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002280 testdata1 = b''.join(zipdata1)
2281 self.assertEqual(len(testdata1), len(self.data))
2282 self.assertEqual(testdata1, self.data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002283
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002284 testdata2 = b''.join(zipdata2)
Ezio Melotti35386712009-12-31 13:22:41 +00002285 self.assertEqual(len(testdata2), len(self.data))
2286 self.assertEqual(testdata2, self.data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002287
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002288 def test_open(self):
2289 for f in get_files(self):
2290 self.zip_open_test(f, self.compression)
Martin v. Löwis7fb79fc2012-05-13 10:06:36 +02002291
Ezio Melottiafd0d112009-07-15 17:17:17 +00002292 def zip_random_open_test(self, f, compression):
2293 self.make_test_archive(f, compression)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002294
2295 # Read the ZIP archive
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002296 with zipfile.ZipFile(f, "r", compression) as zipfp:
2297 zipdata1 = []
Brian Curtin8fb9b862010-11-18 02:15:28 +00002298 with zipfp.open(TESTFN) as zipopen1:
2299 while True:
2300 read_data = zipopen1.read(randint(1, 1024))
2301 if not read_data:
2302 break
2303 zipdata1.append(read_data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002304
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002305 testdata = b''.join(zipdata1)
2306 self.assertEqual(len(testdata), len(self.data))
2307 self.assertEqual(testdata, self.data)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002308
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002309 def test_random_open(self):
2310 for f in get_files(self):
2311 self.zip_random_open_test(f, self.compression)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002312
Antoine Pitrou7c8bcb62010-08-12 15:11:50 +00002313
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002314class StoredTestsWithRandomBinaryFiles(AbstractTestsWithRandomBinaryFiles,
2315 unittest.TestCase):
2316 compression = zipfile.ZIP_STORED
Martin v. Löwisf6b16a42012-05-01 07:58:44 +02002317
Serhiy Storchakafa6bc292013-07-22 21:00:11 +03002318@requires_zlib
2319class DeflateTestsWithRandomBinaryFiles(AbstractTestsWithRandomBinaryFiles,
2320 unittest.TestCase):
2321 compression = zipfile.ZIP_DEFLATED
2322
2323@requires_bz2
2324class Bzip2TestsWithRandomBinaryFiles(AbstractTestsWithRandomBinaryFiles,
2325 unittest.TestCase):
2326 compression = zipfile.ZIP_BZIP2
2327
2328@requires_lzma
2329class LzmaTestsWithRandomBinaryFiles(AbstractTestsWithRandomBinaryFiles,
2330 unittest.TestCase):
2331 compression = zipfile.ZIP_LZMA
Martin v. Löwis7fb79fc2012-05-13 10:06:36 +02002332
Ezio Melotti76430242009-07-11 18:28:48 +00002333
luzpaza5293b42017-11-05 07:37:50 -06002334# Provide the tell() method but not seek()
Serhiy Storchakaa14f7d22015-01-26 14:01:27 +02002335class Tellable:
2336 def __init__(self, fp):
2337 self.fp = fp
2338 self.offset = 0
2339
2340 def write(self, data):
Serhiy Storchaka77d89972015-03-23 01:09:35 +02002341 n = self.fp.write(data)
2342 self.offset += n
2343 return n
Serhiy Storchakaa14f7d22015-01-26 14:01:27 +02002344
2345 def tell(self):
2346 return self.offset
2347
2348 def flush(self):
Serhiy Storchaka77d89972015-03-23 01:09:35 +02002349 self.fp.flush()
2350
2351class Unseekable:
2352 def __init__(self, fp):
2353 self.fp = fp
2354
2355 def write(self, data):
2356 return self.fp.write(data)
2357
2358 def flush(self):
2359 self.fp.flush()
Serhiy Storchakaa14f7d22015-01-26 14:01:27 +02002360
2361class UnseekableTests(unittest.TestCase):
Serhiy Storchaka77d89972015-03-23 01:09:35 +02002362 def test_writestr(self):
2363 for wrapper in (lambda f: f), Tellable, Unseekable:
2364 with self.subTest(wrapper=wrapper):
2365 f = io.BytesIO()
2366 f.write(b'abc')
2367 bf = io.BufferedWriter(f)
2368 with zipfile.ZipFile(wrapper(bf), 'w', zipfile.ZIP_STORED) as zipfp:
2369 zipfp.writestr('ones', b'111')
2370 zipfp.writestr('twos', b'222')
2371 self.assertEqual(f.getvalue()[:5], b'abcPK')
2372 with zipfile.ZipFile(f, mode='r') as zipf:
2373 with zipf.open('ones') as zopen:
2374 self.assertEqual(zopen.read(), b'111')
2375 with zipf.open('twos') as zopen:
2376 self.assertEqual(zopen.read(), b'222')
2377
2378 def test_write(self):
2379 for wrapper in (lambda f: f), Tellable, Unseekable:
2380 with self.subTest(wrapper=wrapper):
2381 f = io.BytesIO()
2382 f.write(b'abc')
2383 bf = io.BufferedWriter(f)
2384 with zipfile.ZipFile(wrapper(bf), 'w', zipfile.ZIP_STORED) as zipfp:
2385 self.addCleanup(unlink, TESTFN)
2386 with open(TESTFN, 'wb') as f2:
2387 f2.write(b'111')
2388 zipfp.write(TESTFN, 'ones')
2389 with open(TESTFN, 'wb') as f2:
2390 f2.write(b'222')
2391 zipfp.write(TESTFN, 'twos')
2392 self.assertEqual(f.getvalue()[:5], b'abcPK')
2393 with zipfile.ZipFile(f, mode='r') as zipf:
2394 with zipf.open('ones') as zopen:
2395 self.assertEqual(zopen.read(), b'111')
2396 with zipf.open('twos') as zopen:
2397 self.assertEqual(zopen.read(), b'222')
Serhiy Storchakaa14f7d22015-01-26 14:01:27 +02002398
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03002399 def test_open_write(self):
2400 for wrapper in (lambda f: f), Tellable, Unseekable:
2401 with self.subTest(wrapper=wrapper):
2402 f = io.BytesIO()
2403 f.write(b'abc')
2404 bf = io.BufferedWriter(f)
2405 with zipfile.ZipFile(wrapper(bf), 'w', zipfile.ZIP_STORED) as zipf:
2406 with zipf.open('ones', 'w') as zopen:
2407 zopen.write(b'111')
2408 with zipf.open('twos', 'w') as zopen:
2409 zopen.write(b'222')
2410 self.assertEqual(f.getvalue()[:5], b'abcPK')
2411 with zipfile.ZipFile(f) as zipf:
2412 self.assertEqual(zipf.read('ones'), b'111')
2413 self.assertEqual(zipf.read('twos'), b'222')
2414
Serhiy Storchakaa14f7d22015-01-26 14:01:27 +02002415
Ezio Melotti975077a2011-05-19 22:03:22 +03002416@requires_zlib
Guido van Rossumd8faa362007-04-27 19:54:29 +00002417class TestsWithMultipleOpens(unittest.TestCase):
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002418 @classmethod
2419 def setUpClass(cls):
2420 cls.data1 = b'111' + getrandbytes(10000)
2421 cls.data2 = b'222' + getrandbytes(10000)
2422
2423 def make_test_archive(self, f):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002424 # Create the ZIP archive
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002425 with zipfile.ZipFile(f, "w", zipfile.ZIP_DEFLATED) as zipfp:
2426 zipfp.writestr('ones', self.data1)
2427 zipfp.writestr('twos', self.data2)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002428
Ezio Melottiafd0d112009-07-15 17:17:17 +00002429 def test_same_file(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002430 # Verify that (when the ZipFile is in control of creating file objects)
2431 # multiple open() calls can be made without interfering with each other.
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002432 for f in get_files(self):
2433 self.make_test_archive(f)
2434 with zipfile.ZipFile(f, mode="r") as zipf:
2435 with zipf.open('ones') as zopen1, zipf.open('ones') as zopen2:
2436 data1 = zopen1.read(500)
2437 data2 = zopen2.read(500)
2438 data1 += zopen1.read()
2439 data2 += zopen2.read()
2440 self.assertEqual(data1, data2)
2441 self.assertEqual(data1, self.data1)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002442
Ezio Melottiafd0d112009-07-15 17:17:17 +00002443 def test_different_file(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002444 # Verify that (when the ZipFile is in control of creating file objects)
2445 # multiple open() calls can be made without interfering with each other.
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002446 for f in get_files(self):
2447 self.make_test_archive(f)
2448 with zipfile.ZipFile(f, mode="r") as zipf:
2449 with zipf.open('ones') as zopen1, zipf.open('twos') as zopen2:
2450 data1 = zopen1.read(500)
2451 data2 = zopen2.read(500)
2452 data1 += zopen1.read()
2453 data2 += zopen2.read()
2454 self.assertEqual(data1, self.data1)
2455 self.assertEqual(data2, self.data2)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002456
Ezio Melottiafd0d112009-07-15 17:17:17 +00002457 def test_interleaved(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +00002458 # Verify that (when the ZipFile is in control of creating file objects)
2459 # multiple open() calls can be made without interfering with each other.
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002460 for f in get_files(self):
2461 self.make_test_archive(f)
2462 with zipfile.ZipFile(f, mode="r") as zipf:
Serhiy Storchakad76c7c22016-05-13 21:18:58 +03002463 with zipf.open('ones') as zopen1:
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002464 data1 = zopen1.read(500)
Serhiy Storchakad76c7c22016-05-13 21:18:58 +03002465 with zipf.open('twos') as zopen2:
2466 data2 = zopen2.read(500)
2467 data1 += zopen1.read()
2468 data2 += zopen2.read()
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002469 self.assertEqual(data1, self.data1)
2470 self.assertEqual(data2, self.data2)
2471
2472 def test_read_after_close(self):
2473 for f in get_files(self):
2474 self.make_test_archive(f)
2475 with contextlib.ExitStack() as stack:
2476 with zipfile.ZipFile(f, 'r') as zipf:
2477 zopen1 = stack.enter_context(zipf.open('ones'))
2478 zopen2 = stack.enter_context(zipf.open('twos'))
Brian Curtin8fb9b862010-11-18 02:15:28 +00002479 data1 = zopen1.read(500)
2480 data2 = zopen2.read(500)
Serhiy Storchaka1ad088f2014-12-03 09:11:57 +02002481 data1 += zopen1.read()
2482 data2 += zopen2.read()
2483 self.assertEqual(data1, self.data1)
2484 self.assertEqual(data2, self.data2)
2485
2486 def test_read_after_write(self):
2487 for f in get_files(self):
2488 with zipfile.ZipFile(f, 'w', zipfile.ZIP_DEFLATED) as zipf:
2489 zipf.writestr('ones', self.data1)
2490 zipf.writestr('twos', self.data2)
2491 with zipf.open('ones') as zopen1:
2492 data1 = zopen1.read(500)
2493 self.assertEqual(data1, self.data1[:500])
2494 with zipfile.ZipFile(f, 'r') as zipf:
2495 data1 = zipf.read('ones')
2496 data2 = zipf.read('twos')
2497 self.assertEqual(data1, self.data1)
2498 self.assertEqual(data2, self.data2)
2499
2500 def test_write_after_read(self):
2501 for f in get_files(self):
2502 with zipfile.ZipFile(f, "w", zipfile.ZIP_DEFLATED) as zipf:
2503 zipf.writestr('ones', self.data1)
2504 with zipf.open('ones') as zopen1:
2505 zopen1.read(500)
2506 zipf.writestr('twos', self.data2)
2507 with zipfile.ZipFile(f, 'r') as zipf:
2508 data1 = zipf.read('ones')
2509 data2 = zipf.read('twos')
2510 self.assertEqual(data1, self.data1)
2511 self.assertEqual(data2, self.data2)
2512
2513 def test_many_opens(self):
2514 # Verify that read() and open() promptly close the file descriptor,
2515 # and don't rely on the garbage collector to free resources.
2516 self.make_test_archive(TESTFN2)
2517 with zipfile.ZipFile(TESTFN2, mode="r") as zipf:
2518 for x in range(100):
2519 zipf.read('ones')
2520 with zipf.open('ones') as zopen1:
2521 pass
2522 with open(os.devnull) as f:
2523 self.assertLess(f.fileno(), 100)
Guido van Rossumd8faa362007-04-27 19:54:29 +00002524
Serhiy Storchaka18ee29d2016-05-13 13:52:49 +03002525 def test_write_while_reading(self):
2526 with zipfile.ZipFile(TESTFN2, 'w', zipfile.ZIP_DEFLATED) as zipf:
2527 zipf.writestr('ones', self.data1)
2528 with zipfile.ZipFile(TESTFN2, 'a', zipfile.ZIP_DEFLATED) as zipf:
2529 with zipf.open('ones', 'r') as r1:
2530 data1 = r1.read(500)
2531 with zipf.open('twos', 'w') as w1:
2532 w1.write(self.data2)
2533 data1 += r1.read()
2534 self.assertEqual(data1, self.data1)
2535 with zipfile.ZipFile(TESTFN2) as zipf:
2536 self.assertEqual(zipf.read('twos'), self.data2)
2537
Guido van Rossumd8faa362007-04-27 19:54:29 +00002538 def tearDown(self):
Ezio Melotti76430242009-07-11 18:28:48 +00002539 unlink(TESTFN2)
2540
Guido van Rossumd8faa362007-04-27 19:54:29 +00002541
Martin v. Löwis59e47792009-01-24 14:10:07 +00002542class TestWithDirectory(unittest.TestCase):
2543 def setUp(self):
2544 os.mkdir(TESTFN2)
2545
Ezio Melottiafd0d112009-07-15 17:17:17 +00002546 def test_extract_dir(self):
Ezio Melottifaa6b7f2009-12-30 12:34:59 +00002547 with zipfile.ZipFile(findfile("zipdir.zip")) as zipf:
2548 zipf.extractall(TESTFN2)
Martin v. Löwis59e47792009-01-24 14:10:07 +00002549 self.assertTrue(os.path.isdir(os.path.join(TESTFN2, "a")))
2550 self.assertTrue(os.path.isdir(os.path.join(TESTFN2, "a", "b")))
2551 self.assertTrue(os.path.exists(os.path.join(TESTFN2, "a", "b", "c")))
2552
Ezio Melottiafd0d112009-07-15 17:17:17 +00002553 def test_bug_6050(self):
Martin v. Löwis70ccd162009-05-24 19:47:22 +00002554 # Extraction should succeed if directories already exist
2555 os.mkdir(os.path.join(TESTFN2, "a"))
Ezio Melottiafd0d112009-07-15 17:17:17 +00002556 self.test_extract_dir()
Martin v. Löwis70ccd162009-05-24 19:47:22 +00002557
Serhiy Storchaka46a34922014-09-23 22:40:23 +03002558 def test_write_dir(self):
2559 dirpath = os.path.join(TESTFN2, "x")
2560 os.mkdir(dirpath)
2561 mode = os.stat(dirpath).st_mode & 0xFFFF
2562 with zipfile.ZipFile(TESTFN, "w") as zipf:
2563 zipf.write(dirpath)
2564 zinfo = zipf.filelist[0]
2565 self.assertTrue(zinfo.filename.endswith("/x/"))
2566 self.assertEqual(zinfo.external_attr, (mode << 16) | 0x10)
2567 zipf.write(dirpath, "y")
2568 zinfo = zipf.filelist[1]
2569 self.assertTrue(zinfo.filename, "y/")
2570 self.assertEqual(zinfo.external_attr, (mode << 16) | 0x10)
2571 with zipfile.ZipFile(TESTFN, "r") as zipf:
2572 zinfo = zipf.filelist[0]
2573 self.assertTrue(zinfo.filename.endswith("/x/"))
2574 self.assertEqual(zinfo.external_attr, (mode << 16) | 0x10)
2575 zinfo = zipf.filelist[1]
2576 self.assertTrue(zinfo.filename, "y/")
2577 self.assertEqual(zinfo.external_attr, (mode << 16) | 0x10)
2578 target = os.path.join(TESTFN2, "target")
2579 os.mkdir(target)
2580 zipf.extractall(target)
2581 self.assertTrue(os.path.isdir(os.path.join(target, "y")))
2582 self.assertEqual(len(os.listdir(target)), 2)
2583
2584 def test_writestr_dir(self):
Martin v. Löwis59e47792009-01-24 14:10:07 +00002585 os.mkdir(os.path.join(TESTFN2, "x"))
Serhiy Storchaka46a34922014-09-23 22:40:23 +03002586 with zipfile.ZipFile(TESTFN, "w") as zipf:
2587 zipf.writestr("x/", b'')
2588 zinfo = zipf.filelist[0]
2589 self.assertEqual(zinfo.filename, "x/")
2590 self.assertEqual(zinfo.external_attr, (0o40775 << 16) | 0x10)
2591 with zipfile.ZipFile(TESTFN, "r") as zipf:
2592 zinfo = zipf.filelist[0]
2593 self.assertTrue(zinfo.filename.endswith("x/"))
2594 self.assertEqual(zinfo.external_attr, (0o40775 << 16) | 0x10)
2595 target = os.path.join(TESTFN2, "target")
2596 os.mkdir(target)
2597 zipf.extractall(target)
2598 self.assertTrue(os.path.isdir(os.path.join(target, "x")))
2599 self.assertEqual(os.listdir(target), ["x"])
Martin v. Löwis59e47792009-01-24 14:10:07 +00002600
2601 def tearDown(self):
Victor Stinner57004c62014-09-04 00:49:01 +02002602 rmtree(TESTFN2)
Martin v. Löwis59e47792009-01-24 14:10:07 +00002603 if os.path.exists(TESTFN):
Ezio Melotti76430242009-07-11 18:28:48 +00002604 unlink(TESTFN)
Martin v. Löwis59e47792009-01-24 14:10:07 +00002605
Guido van Rossumd8faa362007-04-27 19:54:29 +00002606
Serhiy Storchaka503f9082016-02-08 00:02:25 +02002607class ZipInfoTests(unittest.TestCase):
2608 def test_from_file(self):
2609 zi = zipfile.ZipInfo.from_file(__file__)
2610 self.assertEqual(posixpath.basename(zi.filename), 'test_zipfile.py')
2611 self.assertFalse(zi.is_dir())
Serhiy Storchaka8606e952017-03-08 14:37:51 +02002612 self.assertEqual(zi.file_size, os.path.getsize(__file__))
2613
2614 def test_from_file_pathlike(self):
2615 zi = zipfile.ZipInfo.from_file(pathlib.Path(__file__))
2616 self.assertEqual(posixpath.basename(zi.filename), 'test_zipfile.py')
2617 self.assertFalse(zi.is_dir())
2618 self.assertEqual(zi.file_size, os.path.getsize(__file__))
2619
2620 def test_from_file_bytes(self):
2621 zi = zipfile.ZipInfo.from_file(os.fsencode(__file__), 'test')
2622 self.assertEqual(posixpath.basename(zi.filename), 'test')
2623 self.assertFalse(zi.is_dir())
2624 self.assertEqual(zi.file_size, os.path.getsize(__file__))
2625
2626 def test_from_file_fileno(self):
2627 with open(__file__, 'rb') as f:
2628 zi = zipfile.ZipInfo.from_file(f.fileno(), 'test')
2629 self.assertEqual(posixpath.basename(zi.filename), 'test')
2630 self.assertFalse(zi.is_dir())
2631 self.assertEqual(zi.file_size, os.path.getsize(__file__))
Serhiy Storchaka503f9082016-02-08 00:02:25 +02002632
2633 def test_from_dir(self):
2634 dirpath = os.path.dirname(os.path.abspath(__file__))
2635 zi = zipfile.ZipInfo.from_file(dirpath, 'stdlib_tests')
2636 self.assertEqual(zi.filename, 'stdlib_tests/')
2637 self.assertTrue(zi.is_dir())
2638 self.assertEqual(zi.compress_type, zipfile.ZIP_STORED)
2639 self.assertEqual(zi.file_size, 0)
2640
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002641
2642class CommandLineTest(unittest.TestCase):
2643
2644 def zipfilecmd(self, *args, **kwargs):
2645 rc, out, err = script_helper.assert_python_ok('-m', 'zipfile', *args,
2646 **kwargs)
2647 return out.replace(os.linesep.encode(), b'\n')
2648
2649 def zipfilecmd_failure(self, *args):
2650 return script_helper.assert_python_failure('-m', 'zipfile', *args)
2651
Serhiy Storchaka150cd192017-04-07 18:56:12 +03002652 def test_bad_use(self):
2653 rc, out, err = self.zipfilecmd_failure()
2654 self.assertEqual(out, b'')
2655 self.assertIn(b'usage', err.lower())
2656 self.assertIn(b'error', err.lower())
2657 self.assertIn(b'required', err.lower())
2658 rc, out, err = self.zipfilecmd_failure('-l', '')
2659 self.assertEqual(out, b'')
2660 self.assertNotEqual(err.strip(), b'')
2661
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002662 def test_test_command(self):
2663 zip_name = findfile('zipdir.zip')
Serhiy Storchaka8c933102016-10-23 13:32:12 +03002664 for opt in '-t', '--test':
2665 out = self.zipfilecmd(opt, zip_name)
2666 self.assertEqual(out.rstrip(), b'Done testing')
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002667 zip_name = findfile('testtar.tar')
2668 rc, out, err = self.zipfilecmd_failure('-t', zip_name)
2669 self.assertEqual(out, b'')
2670
2671 def test_list_command(self):
2672 zip_name = findfile('zipdir.zip')
2673 t = io.StringIO()
2674 with zipfile.ZipFile(zip_name, 'r') as tf:
2675 tf.printdir(t)
2676 expected = t.getvalue().encode('ascii', 'backslashreplace')
Serhiy Storchaka8c933102016-10-23 13:32:12 +03002677 for opt in '-l', '--list':
2678 out = self.zipfilecmd(opt, zip_name,
2679 PYTHONIOENCODING='ascii:backslashreplace')
2680 self.assertEqual(out, expected)
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002681
Serhiy Storchakab4293ef2016-10-23 22:32:30 +03002682 @requires_zlib
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002683 def test_create_command(self):
2684 self.addCleanup(unlink, TESTFN)
2685 with open(TESTFN, 'w') as f:
2686 f.write('test 1')
2687 os.mkdir(TESTFNDIR)
2688 self.addCleanup(rmtree, TESTFNDIR)
2689 with open(os.path.join(TESTFNDIR, 'file.txt'), 'w') as f:
2690 f.write('test 2')
2691 files = [TESTFN, TESTFNDIR]
2692 namelist = [TESTFN, TESTFNDIR + '/', TESTFNDIR + '/file.txt']
Serhiy Storchaka8c933102016-10-23 13:32:12 +03002693 for opt in '-c', '--create':
2694 try:
2695 out = self.zipfilecmd(opt, TESTFN2, *files)
2696 self.assertEqual(out, b'')
2697 with zipfile.ZipFile(TESTFN2) as zf:
2698 self.assertEqual(zf.namelist(), namelist)
2699 self.assertEqual(zf.read(namelist[0]), b'test 1')
2700 self.assertEqual(zf.read(namelist[2]), b'test 2')
2701 finally:
2702 unlink(TESTFN2)
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002703
2704 def test_extract_command(self):
2705 zip_name = findfile('zipdir.zip')
Serhiy Storchaka8c933102016-10-23 13:32:12 +03002706 for opt in '-e', '--extract':
2707 with temp_dir() as extdir:
2708 out = self.zipfilecmd(opt, zip_name, extdir)
2709 self.assertEqual(out, b'')
2710 with zipfile.ZipFile(zip_name) as zf:
2711 for zi in zf.infolist():
2712 path = os.path.join(extdir,
2713 zi.filename.replace('/', os.sep))
2714 if zi.is_dir():
2715 self.assertTrue(os.path.isdir(path))
2716 else:
2717 self.assertTrue(os.path.isfile(path))
2718 with open(path, 'rb') as f:
2719 self.assertEqual(f.read(), zf.read(zi))
Serhiy Storchaka61c4c442016-10-23 13:07:59 +03002720
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002721
2722# Poor man's technique to consume a (smallish) iterable.
2723consume = tuple
2724
2725
shireenraoa4e29912019-08-24 11:26:41 -04002726def add_dirs(zf):
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002727 """
shireenraoa4e29912019-08-24 11:26:41 -04002728 Given a writable zip file zf, inject directory entries for
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002729 any directories implied by the presence of children.
2730 """
shireenraoa4e29912019-08-24 11:26:41 -04002731 for name in zipfile.Path._implied_dirs(zf.namelist()):
2732 zf.writestr(name, b"")
2733 return zf
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002734
2735
shireenraoa4e29912019-08-24 11:26:41 -04002736def build_alpharep_fixture():
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002737 """
2738 Create a zip file with this structure:
2739
2740 .
2741 ├── a.txt
shireenraoa4e29912019-08-24 11:26:41 -04002742 ├── b
2743 │ ├── c.txt
2744 │ ├── d
2745 │ │ └── e.txt
2746 │ └── f.txt
2747 └── g
2748 └── h
2749 └── i.txt
2750
2751 This fixture has the following key characteristics:
2752
2753 - a file at the root (a)
2754 - a file two levels deep (b/d/e)
2755 - multiple files in a directory (b/c, b/f)
2756 - a directory containing only a directory (g/h)
2757
2758 "alpha" because it uses alphabet
2759 "rep" because it's a representative example
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002760 """
2761 data = io.BytesIO()
2762 zf = zipfile.ZipFile(data, "w")
2763 zf.writestr("a.txt", b"content of a")
2764 zf.writestr("b/c.txt", b"content of c")
2765 zf.writestr("b/d/e.txt", b"content of e")
shireenraoa4e29912019-08-24 11:26:41 -04002766 zf.writestr("b/f.txt", b"content of f")
2767 zf.writestr("g/h/i.txt", b"content of i")
2768 zf.filename = "alpharep.zip"
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002769 return zf
2770
2771
Gregory P. Smith3f4db4a2019-09-10 17:14:11 +01002772class TestExecutablePrependedZip(unittest.TestCase):
2773 """Test our ability to open zip files with an executable prepended."""
2774
2775 def setUp(self):
2776 self.exe_zip = findfile('exe_with_zip', subdir='ziptestdata')
2777 self.exe_zip64 = findfile('exe_with_z64', subdir='ziptestdata')
2778
2779 def _test_zip_works(self, name):
2780 # bpo-28494 sanity check: ensure is_zipfile works on these.
2781 self.assertTrue(zipfile.is_zipfile(name),
2782 f'is_zipfile failed on {name}')
2783 # Ensure we can operate on these via ZipFile.
2784 with zipfile.ZipFile(name) as zipfp:
2785 for n in zipfp.namelist():
2786 data = zipfp.read(n)
2787 self.assertIn(b'FAVORITE_NUMBER', data)
2788
2789 def test_read_zip_with_exe_prepended(self):
2790 self._test_zip_works(self.exe_zip)
2791
2792 def test_read_zip64_with_exe_prepended(self):
2793 self._test_zip_works(self.exe_zip64)
2794
2795 @unittest.skipUnless(sys.executable, 'sys.executable required.')
2796 @unittest.skipUnless(os.access('/bin/bash', os.X_OK),
2797 'Test relies on #!/bin/bash working.')
2798 def test_execute_zip2(self):
2799 output = subprocess.check_output([self.exe_zip, sys.executable])
2800 self.assertIn(b'number in executable: 5', output)
2801
2802 @unittest.skipUnless(sys.executable, 'sys.executable required.')
2803 @unittest.skipUnless(os.access('/bin/bash', os.X_OK),
2804 'Test relies on #!/bin/bash working.')
2805 def test_execute_zip64(self):
2806 output = subprocess.check_output([self.exe_zip64, sys.executable])
2807 self.assertIn(b'number in executable: 5', output)
2808
2809
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002810class TestPath(unittest.TestCase):
2811 def setUp(self):
2812 self.fixtures = contextlib.ExitStack()
2813 self.addCleanup(self.fixtures.close)
2814
shireenraoa4e29912019-08-24 11:26:41 -04002815 def zipfile_alpharep(self):
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002816 with self.subTest():
shireenraoa4e29912019-08-24 11:26:41 -04002817 yield build_alpharep_fixture()
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002818 with self.subTest():
shireenraoa4e29912019-08-24 11:26:41 -04002819 yield add_dirs(build_alpharep_fixture())
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002820
2821 def zipfile_ondisk(self):
2822 tmpdir = pathlib.Path(self.fixtures.enter_context(temp_dir()))
shireenraoa4e29912019-08-24 11:26:41 -04002823 for alpharep in self.zipfile_alpharep():
2824 buffer = alpharep.fp
2825 alpharep.close()
2826 path = tmpdir / alpharep.filename
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002827 with path.open("wb") as strm:
2828 strm.write(buffer.getvalue())
2829 yield path
2830
shireenraoa4e29912019-08-24 11:26:41 -04002831 def test_iterdir_and_types(self):
2832 for alpharep in self.zipfile_alpharep():
2833 root = zipfile.Path(alpharep)
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002834 assert root.is_dir()
shireenraoa4e29912019-08-24 11:26:41 -04002835 a, b, g = root.iterdir()
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002836 assert a.is_file()
2837 assert b.is_dir()
shireenraoa4e29912019-08-24 11:26:41 -04002838 assert g.is_dir()
2839 c, f, d = b.iterdir()
2840 assert c.is_file() and f.is_file()
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002841 e, = d.iterdir()
2842 assert e.is_file()
shireenraoa4e29912019-08-24 11:26:41 -04002843 h, = g.iterdir()
2844 i, = h.iterdir()
2845 assert i.is_file()
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002846
2847 def test_open(self):
shireenraoa4e29912019-08-24 11:26:41 -04002848 for alpharep in self.zipfile_alpharep():
2849 root = zipfile.Path(alpharep)
2850 a, b, g = root.iterdir()
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002851 with a.open() as strm:
2852 data = strm.read()
2853 assert data == b"content of a"
2854
2855 def test_read(self):
shireenraoa4e29912019-08-24 11:26:41 -04002856 for alpharep in self.zipfile_alpharep():
2857 root = zipfile.Path(alpharep)
2858 a, b, g = root.iterdir()
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002859 assert a.read_text() == "content of a"
2860 assert a.read_bytes() == b"content of a"
2861
Jason R. Coombs33e067d2019-05-09 11:34:36 -04002862 def test_joinpath(self):
shireenraoa4e29912019-08-24 11:26:41 -04002863 for alpharep in self.zipfile_alpharep():
2864 root = zipfile.Path(alpharep)
Jason R. Coombs33e067d2019-05-09 11:34:36 -04002865 a = root.joinpath("a")
2866 assert a.is_file()
2867 e = root.joinpath("b").joinpath("d").joinpath("e.txt")
2868 assert e.read_text() == "content of e"
2869
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002870 def test_traverse_truediv(self):
shireenraoa4e29912019-08-24 11:26:41 -04002871 for alpharep in self.zipfile_alpharep():
2872 root = zipfile.Path(alpharep)
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002873 a = root / "a"
2874 assert a.is_file()
2875 e = root / "b" / "d" / "e.txt"
2876 assert e.read_text() == "content of e"
2877
2878 def test_pathlike_construction(self):
2879 """
2880 zipfile.Path should be constructable from a path-like object
2881 """
2882 for zipfile_ondisk in self.zipfile_ondisk():
2883 pathlike = pathlib.Path(str(zipfile_ondisk))
2884 zipfile.Path(pathlike)
2885
2886 def test_traverse_pathlike(self):
shireenraoa4e29912019-08-24 11:26:41 -04002887 for alpharep in self.zipfile_alpharep():
2888 root = zipfile.Path(alpharep)
Jason R. Coombsb2758ff2019-05-08 09:45:06 -04002889 root / pathlib.Path("a")
2890
Jason R. Coombs33e067d2019-05-09 11:34:36 -04002891 def test_parent(self):
shireenraoa4e29912019-08-24 11:26:41 -04002892 for alpharep in self.zipfile_alpharep():
2893 root = zipfile.Path(alpharep)
Jason R. Coombs33e067d2019-05-09 11:34:36 -04002894 assert (root / 'a').parent.at == ''
2895 assert (root / 'a' / 'b').parent.at == 'a/'
2896
Jason R. Coombs38f44b42019-07-07 17:37:50 -04002897 def test_dir_parent(self):
shireenraoa4e29912019-08-24 11:26:41 -04002898 for alpharep in self.zipfile_alpharep():
2899 root = zipfile.Path(alpharep)
Jason R. Coombs38f44b42019-07-07 17:37:50 -04002900 assert (root / 'b').parent.at == ''
2901 assert (root / 'b/').parent.at == ''
2902
2903 def test_missing_dir_parent(self):
shireenraoa4e29912019-08-24 11:26:41 -04002904 for alpharep in self.zipfile_alpharep():
2905 root = zipfile.Path(alpharep)
Jason R. Coombs38f44b42019-07-07 17:37:50 -04002906 assert (root / 'missing dir/').parent.at == ''
2907
shireenraoa4e29912019-08-24 11:26:41 -04002908
Johannes Gijsbers3caf9c12004-08-19 15:11:50 +00002909if __name__ == "__main__":
Brett Cannond5b4e1d2013-06-12 19:57:19 -04002910 unittest.main()