blob: f86e767ac0e59cbe7e04088a8e02730bc02666fb [file] [log] [blame]
Andrew M. Kuchlinga6f68e12005-06-09 14:12:36 +00001"""Test script for the gzip module.
2"""
3
Stéphane Wirtel84eec112018-10-09 23:16:43 +02004import array
5import functools
6import io
Christian Heimes05e8be12008-02-23 18:30:17 +00007import os
Berker Peksag03020cf2016-10-02 13:47:58 +03008import pathlib
Antoine Pitrou42db3ef2009-01-04 21:37:59 +00009import struct
Stéphane Wirtel84eec112018-10-09 23:16:43 +020010import sys
11import unittest
12from subprocess import PIPE, Popen
Hai Shibb0424b2020-08-04 00:47:42 +080013from test.support import import_helper
14from test.support import os_helper
Stéphane Wirtel84eec112018-10-09 23:16:43 +020015from test.support import _4G, bigmemtest
Stéphane Wirtel3e28eed2018-11-03 16:24:23 +010016from test.support.script_helper import assert_python_ok, assert_python_failure
Stéphane Wirtel84eec112018-10-09 23:16:43 +020017
Hai Shibb0424b2020-08-04 00:47:42 +080018gzip = import_helper.import_module('gzip')
Andrew M. Kuchling605ebdd1999-03-25 21:50:27 +000019
Walter Dörwald5b1284d2007-06-06 16:43:59 +000020data1 = b""" int length=DEFAULTALLOC, err = Z_OK;
Andrew M. Kuchling605ebdd1999-03-25 21:50:27 +000021 PyObject *RetVal;
22 int flushmode = Z_FINISH;
23 unsigned long start_total_out;
24
25"""
26
Walter Dörwald5b1284d2007-06-06 16:43:59 +000027data2 = b"""/* zlibmodule.c -- gzip-compatible data compression */
Neal Norwitz014f1032004-07-29 03:55:56 +000028/* See http://www.gzip.org/zlib/
Andrew M. Kuchling605ebdd1999-03-25 21:50:27 +000029/* See http://www.winimage.com/zLibDll for Windows */
30"""
31
Andrew M. Kuchling605ebdd1999-03-25 21:50:27 +000032
Hai Shibb0424b2020-08-04 00:47:42 +080033TEMPDIR = os.path.abspath(os_helper.TESTFN) + '-gzdir'
Stéphane Wirtel84eec112018-10-09 23:16:43 +020034
35
Antoine Pitrou7b969842010-09-23 16:22:51 +000036class UnseekableIO(io.BytesIO):
37 def seekable(self):
38 return False
39
40 def tell(self):
41 raise io.UnsupportedOperation
42
43 def seek(self, *args):
44 raise io.UnsupportedOperation
45
46
Nadeem Vawda1b8a14d2012-05-06 15:17:52 +020047class BaseTest(unittest.TestCase):
Hai Shibb0424b2020-08-04 00:47:42 +080048 filename = os_helper.TESTFN
Tim Peters5cfb05e2004-07-27 21:02:02 +000049
Georg Brandlb533e262008-05-25 18:19:30 +000050 def setUp(self):
Hai Shibb0424b2020-08-04 00:47:42 +080051 os_helper.unlink(self.filename)
Andrew M. Kuchling605ebdd1999-03-25 21:50:27 +000052
Georg Brandlb533e262008-05-25 18:19:30 +000053 def tearDown(self):
Hai Shibb0424b2020-08-04 00:47:42 +080054 os_helper.unlink(self.filename)
Andrew M. Kuchling605ebdd1999-03-25 21:50:27 +000055
Andrew M. Kuchling85ab7382000-07-29 20:18:34 +000056
Nadeem Vawda1b8a14d2012-05-06 15:17:52 +020057class TestGzip(BaseTest):
Serhiy Storchakabca63b32015-03-23 14:59:48 +020058 def write_and_read_back(self, data, mode='b'):
59 b_data = bytes(data)
60 with gzip.GzipFile(self.filename, 'w'+mode) as f:
61 l = f.write(data)
62 self.assertEqual(l, len(b_data))
63 with gzip.GzipFile(self.filename, 'r'+mode) as f:
64 self.assertEqual(f.read(), b_data)
65
Georg Brandlb533e262008-05-25 18:19:30 +000066 def test_write(self):
Brian Curtin28f96b52010-10-13 02:21:42 +000067 with gzip.GzipFile(self.filename, 'wb') as f:
68 f.write(data1 * 50)
Andrew M. Kuchling85ab7382000-07-29 20:18:34 +000069
Brian Curtin28f96b52010-10-13 02:21:42 +000070 # Try flush and fileno.
71 f.flush()
72 f.fileno()
73 if hasattr(os, 'fsync'):
74 os.fsync(f.fileno())
75 f.close()
Andrew M. Kuchling85ab7382000-07-29 20:18:34 +000076
Georg Brandlb533e262008-05-25 18:19:30 +000077 # Test multiple close() calls.
78 f.close()
79
Berker Peksag03020cf2016-10-02 13:47:58 +030080 def test_write_read_with_pathlike_file(self):
81 filename = pathlib.Path(self.filename)
82 with gzip.GzipFile(filename, 'w') as f:
83 f.write(data1 * 50)
84 self.assertIsInstance(f.name, str)
85 with gzip.GzipFile(filename, 'a') as f:
86 f.write(data1)
87 with gzip.GzipFile(filename) as f:
88 d = f.read()
89 self.assertEqual(d, data1 * 51)
90 self.assertIsInstance(f.name, str)
91
Serhiy Storchakabca63b32015-03-23 14:59:48 +020092 # The following test_write_xy methods test that write accepts
93 # the corresponding bytes-like object type as input
94 # and that the data written equals bytes(xy) in all cases.
95 def test_write_memoryview(self):
96 self.write_and_read_back(memoryview(data1 * 50))
97 m = memoryview(bytes(range(256)))
98 data = m.cast('B', shape=[8,8,4])
99 self.write_and_read_back(data)
100
101 def test_write_bytearray(self):
102 self.write_and_read_back(bytearray(data1 * 50))
103
104 def test_write_array(self):
105 self.write_and_read_back(array.array('I', data1 * 40))
106
107 def test_write_incompatible_type(self):
108 # Test that non-bytes-like types raise TypeError.
109 # Issue #21560: attempts to write incompatible types
110 # should not affect the state of the fileobject
111 with gzip.GzipFile(self.filename, 'wb') as f:
112 with self.assertRaises(TypeError):
113 f.write('')
114 with self.assertRaises(TypeError):
115 f.write([])
116 f.write(data1)
117 with gzip.GzipFile(self.filename, 'rb') as f:
118 self.assertEqual(f.read(), data1)
119
Andrew M. Kuchlinga6f68e12005-06-09 14:12:36 +0000120 def test_read(self):
121 self.test_write()
122 # Try reading.
Brian Curtin28f96b52010-10-13 02:21:42 +0000123 with gzip.GzipFile(self.filename, 'r') as f:
124 d = f.read()
Andrew M. Kuchlinga6f68e12005-06-09 14:12:36 +0000125 self.assertEqual(d, data1*50)
Andrew M. Kuchling85ab7382000-07-29 20:18:34 +0000126
Antoine Pitrou4ec4b0c2011-04-04 21:00:37 +0200127 def test_read1(self):
128 self.test_write()
129 blocks = []
130 nread = 0
131 with gzip.GzipFile(self.filename, 'r') as f:
132 while True:
133 d = f.read1()
134 if not d:
135 break
136 blocks.append(d)
137 nread += len(d)
138 # Check that position was updated correctly (see issue10791).
139 self.assertEqual(f.tell(), nread)
140 self.assertEqual(b''.join(blocks), data1 * 50)
141
Martin Pantere99e9772015-11-20 08:13:35 +0000142 @bigmemtest(size=_4G, memuse=1)
143 def test_read_large(self, size):
144 # Read chunk size over UINT_MAX should be supported, despite zlib's
145 # limitation per low-level call
146 compressed = gzip.compress(data1, compresslevel=1)
147 f = gzip.GzipFile(fileobj=io.BytesIO(compressed), mode='rb')
148 self.assertEqual(f.read(size), data1)
149
Antoine Pitrou7980eaa2010-10-06 21:21:18 +0000150 def test_io_on_closed_object(self):
151 # Test that I/O operations on closed GzipFile objects raise a
152 # ValueError, just like the corresponding functions on file objects.
153
154 # Write to a file, open it for reading, then close it.
155 self.test_write()
156 f = gzip.GzipFile(self.filename, 'r')
Antoine Pitrou2dbc6e62015-04-11 00:31:01 +0200157 fileobj = f.fileobj
158 self.assertFalse(fileobj.closed)
Antoine Pitrou7980eaa2010-10-06 21:21:18 +0000159 f.close()
Antoine Pitrou2dbc6e62015-04-11 00:31:01 +0200160 self.assertTrue(fileobj.closed)
Antoine Pitrou7980eaa2010-10-06 21:21:18 +0000161 with self.assertRaises(ValueError):
162 f.read(1)
163 with self.assertRaises(ValueError):
164 f.seek(0)
165 with self.assertRaises(ValueError):
166 f.tell()
167 # Open the file for writing, then close it.
168 f = gzip.GzipFile(self.filename, 'w')
Antoine Pitrou2dbc6e62015-04-11 00:31:01 +0200169 fileobj = f.fileobj
170 self.assertFalse(fileobj.closed)
Antoine Pitrou7980eaa2010-10-06 21:21:18 +0000171 f.close()
Antoine Pitrou2dbc6e62015-04-11 00:31:01 +0200172 self.assertTrue(fileobj.closed)
Antoine Pitrou7980eaa2010-10-06 21:21:18 +0000173 with self.assertRaises(ValueError):
174 f.write(b'')
175 with self.assertRaises(ValueError):
176 f.flush()
177
Andrew M. Kuchlinga6f68e12005-06-09 14:12:36 +0000178 def test_append(self):
179 self.test_write()
180 # Append to the previous file
Brian Curtin28f96b52010-10-13 02:21:42 +0000181 with gzip.GzipFile(self.filename, 'ab') as f:
182 f.write(data2 * 15)
Andrew M. Kuchling85ab7382000-07-29 20:18:34 +0000183
Brian Curtin28f96b52010-10-13 02:21:42 +0000184 with gzip.GzipFile(self.filename, 'rb') as f:
185 d = f.read()
Andrew M. Kuchlinga6f68e12005-06-09 14:12:36 +0000186 self.assertEqual(d, (data1*50) + (data2*15))
Andrew M. Kuchling85ab7382000-07-29 20:18:34 +0000187
Andrew M. Kuchling01cb47b2005-06-09 14:19:32 +0000188 def test_many_append(self):
189 # Bug #1074261 was triggered when reading a file that contained
190 # many, many members. Create such a file and verify that reading it
191 # works.
Nadeem Vawda1b8a14d2012-05-06 15:17:52 +0200192 with gzip.GzipFile(self.filename, 'wb', 9) as f:
Walter Dörwald5b1284d2007-06-06 16:43:59 +0000193 f.write(b'a')
Brian Curtin28f96b52010-10-13 02:21:42 +0000194 for i in range(0, 200):
Nadeem Vawda1b8a14d2012-05-06 15:17:52 +0200195 with gzip.GzipFile(self.filename, "ab", 9) as f: # append
Brian Curtin28f96b52010-10-13 02:21:42 +0000196 f.write(b'a')
Andrew M. Kuchling01cb47b2005-06-09 14:19:32 +0000197
198 # Try reading the file
Nadeem Vawda1b8a14d2012-05-06 15:17:52 +0200199 with gzip.GzipFile(self.filename, "rb") as zgfile:
Brian Curtin28f96b52010-10-13 02:21:42 +0000200 contents = b""
201 while 1:
202 ztxt = zgfile.read(8192)
203 contents += ztxt
204 if not ztxt: break
Ezio Melottib3aedd42010-11-20 19:04:17 +0000205 self.assertEqual(contents, b'a'*201)
Andrew M. Kuchling01cb47b2005-06-09 14:19:32 +0000206
Nadeem Vawdaee1be992013-10-19 00:11:13 +0200207 def test_exclusive_write(self):
208 with gzip.GzipFile(self.filename, 'xb') as f:
209 f.write(data1 * 50)
210 with gzip.GzipFile(self.filename, 'rb') as f:
211 self.assertEqual(f.read(), data1 * 50)
212 with self.assertRaises(FileExistsError):
213 gzip.GzipFile(self.filename, 'xb')
214
Antoine Pitroub1f88352010-01-03 22:37:40 +0000215 def test_buffered_reader(self):
216 # Issue #7471: a GzipFile can be wrapped in a BufferedReader for
217 # performance.
218 self.test_write()
219
Brian Curtin28f96b52010-10-13 02:21:42 +0000220 with gzip.GzipFile(self.filename, 'rb') as f:
221 with io.BufferedReader(f) as r:
222 lines = [line for line in r]
Antoine Pitroub1f88352010-01-03 22:37:40 +0000223
Ezio Melottid8b509b2011-09-28 17:37:55 +0300224 self.assertEqual(lines, 50 * data1.splitlines(keepends=True))
Andrew M. Kuchling01cb47b2005-06-09 14:19:32 +0000225
Andrew M. Kuchlinga6f68e12005-06-09 14:12:36 +0000226 def test_readline(self):
227 self.test_write()
228 # Try .readline() with varying line lengths
Martin v. Löwis8cc965c2001-08-09 07:21:56 +0000229
Brian Curtin28f96b52010-10-13 02:21:42 +0000230 with gzip.GzipFile(self.filename, 'rb') as f:
231 line_length = 0
232 while 1:
233 L = f.readline(line_length)
234 if not L and line_length != 0: break
235 self.assertTrue(len(L) <= line_length)
236 line_length = (line_length + 1) % 50
Martin v. Löwis8cc965c2001-08-09 07:21:56 +0000237
Andrew M. Kuchlinga6f68e12005-06-09 14:12:36 +0000238 def test_readlines(self):
239 self.test_write()
240 # Try .readlines()
Andrew M. Kuchling605ebdd1999-03-25 21:50:27 +0000241
Brian Curtin28f96b52010-10-13 02:21:42 +0000242 with gzip.GzipFile(self.filename, 'rb') as f:
243 L = f.readlines()
Skip Montanaro12424bc2002-05-23 01:43:05 +0000244
Brian Curtin28f96b52010-10-13 02:21:42 +0000245 with gzip.GzipFile(self.filename, 'rb') as f:
246 while 1:
247 L = f.readlines(150)
248 if L == []: break
Andrew M. Kuchlinga6f68e12005-06-09 14:12:36 +0000249
250 def test_seek_read(self):
251 self.test_write()
252 # Try seek, read test
253
Brian Curtin28f96b52010-10-13 02:21:42 +0000254 with gzip.GzipFile(self.filename) as f:
255 while 1:
256 oldpos = f.tell()
257 line1 = f.readline()
258 if not line1: break
259 newpos = f.tell()
260 f.seek(oldpos) # negative seek
261 if len(line1)>10:
262 amount = 10
263 else:
264 amount = len(line1)
265 line2 = f.read(amount)
266 self.assertEqual(line1[:amount], line2)
267 f.seek(newpos) # positive seek
Andrew M. Kuchlinga6f68e12005-06-09 14:12:36 +0000268
Thomas Wouters89f507f2006-12-13 04:49:30 +0000269 def test_seek_whence(self):
270 self.test_write()
271 # Try seek(whence=1), read test
272
Brian Curtin28f96b52010-10-13 02:21:42 +0000273 with gzip.GzipFile(self.filename) as f:
274 f.read(10)
275 f.seek(10, whence=1)
276 y = f.read(10)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000277 self.assertEqual(y, data1[20:30])
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000278
Andrew M. Kuchlinga6f68e12005-06-09 14:12:36 +0000279 def test_seek_write(self):
280 # Try seek, write test
Brian Curtin28f96b52010-10-13 02:21:42 +0000281 with gzip.GzipFile(self.filename, 'w') as f:
282 for pos in range(0, 256, 16):
283 f.seek(pos)
284 f.write(b'GZ\n')
Andrew M. Kuchlinga6f68e12005-06-09 14:12:36 +0000285
286 def test_mode(self):
287 self.test_write()
Brian Curtin28f96b52010-10-13 02:21:42 +0000288 with gzip.GzipFile(self.filename, 'r') as f:
289 self.assertEqual(f.myfileobj.mode, 'rb')
Hai Shibb0424b2020-08-04 00:47:42 +0800290 os_helper.unlink(self.filename)
Nadeem Vawdaee1be992013-10-19 00:11:13 +0200291 with gzip.GzipFile(self.filename, 'x') as f:
292 self.assertEqual(f.myfileobj.mode, 'xb')
Andrew M. Kuchlinga6f68e12005-06-09 14:12:36 +0000293
Thomas Wouterscf297e42007-02-23 15:07:44 +0000294 def test_1647484(self):
295 for mode in ('wb', 'rb'):
Brian Curtin28f96b52010-10-13 02:21:42 +0000296 with gzip.GzipFile(self.filename, mode) as f:
297 self.assertTrue(hasattr(f, "name"))
298 self.assertEqual(f.name, self.filename)
Thomas Wouterscf297e42007-02-23 15:07:44 +0000299
Georg Brandl9f1c1dc2010-11-20 11:25:01 +0000300 def test_paddedfile_getattr(self):
301 self.test_write()
302 with gzip.GzipFile(self.filename, 'rb') as f:
303 self.assertTrue(hasattr(f.fileobj, "name"))
304 self.assertEqual(f.fileobj.name, self.filename)
305
Antoine Pitrou42db3ef2009-01-04 21:37:59 +0000306 def test_mtime(self):
307 mtime = 123456789
Brian Curtin28f96b52010-10-13 02:21:42 +0000308 with gzip.GzipFile(self.filename, 'w', mtime = mtime) as fWrite:
309 fWrite.write(data1)
310 with gzip.GzipFile(self.filename) as fRead:
Antoine Pitrou2dbc6e62015-04-11 00:31:01 +0200311 self.assertTrue(hasattr(fRead, 'mtime'))
312 self.assertIsNone(fRead.mtime)
Brian Curtin28f96b52010-10-13 02:21:42 +0000313 dataRead = fRead.read()
314 self.assertEqual(dataRead, data1)
Brian Curtin28f96b52010-10-13 02:21:42 +0000315 self.assertEqual(fRead.mtime, mtime)
Antoine Pitrou42db3ef2009-01-04 21:37:59 +0000316
317 def test_metadata(self):
318 mtime = 123456789
319
Brian Curtin28f96b52010-10-13 02:21:42 +0000320 with gzip.GzipFile(self.filename, 'w', mtime = mtime) as fWrite:
321 fWrite.write(data1)
Antoine Pitrou42db3ef2009-01-04 21:37:59 +0000322
Brian Curtin28f96b52010-10-13 02:21:42 +0000323 with open(self.filename, 'rb') as fRead:
324 # see RFC 1952: http://www.faqs.org/rfcs/rfc1952.html
Antoine Pitrou42db3ef2009-01-04 21:37:59 +0000325
Brian Curtin28f96b52010-10-13 02:21:42 +0000326 idBytes = fRead.read(2)
327 self.assertEqual(idBytes, b'\x1f\x8b') # gzip ID
Antoine Pitrou42db3ef2009-01-04 21:37:59 +0000328
Brian Curtin28f96b52010-10-13 02:21:42 +0000329 cmByte = fRead.read(1)
330 self.assertEqual(cmByte, b'\x08') # deflate
Antoine Pitrou42db3ef2009-01-04 21:37:59 +0000331
Serhiy Storchaka700cfa82020-06-25 17:56:31 +0300332 try:
333 expectedname = self.filename.encode('Latin-1') + b'\x00'
334 expectedflags = b'\x08' # only the FNAME flag is set
335 except UnicodeEncodeError:
336 expectedname = b''
337 expectedflags = b'\x00'
338
Brian Curtin28f96b52010-10-13 02:21:42 +0000339 flagsByte = fRead.read(1)
Serhiy Storchaka700cfa82020-06-25 17:56:31 +0300340 self.assertEqual(flagsByte, expectedflags)
Antoine Pitrou42db3ef2009-01-04 21:37:59 +0000341
Brian Curtin28f96b52010-10-13 02:21:42 +0000342 mtimeBytes = fRead.read(4)
343 self.assertEqual(mtimeBytes, struct.pack('<i', mtime)) # little-endian
Antoine Pitrou42db3ef2009-01-04 21:37:59 +0000344
Brian Curtin28f96b52010-10-13 02:21:42 +0000345 xflByte = fRead.read(1)
346 self.assertEqual(xflByte, b'\x02') # maximum compression
Antoine Pitrou42db3ef2009-01-04 21:37:59 +0000347
Brian Curtin28f96b52010-10-13 02:21:42 +0000348 osByte = fRead.read(1)
349 self.assertEqual(osByte, b'\xff') # OS "unknown" (OS-independent)
Antoine Pitrou42db3ef2009-01-04 21:37:59 +0000350
Brian Curtin28f96b52010-10-13 02:21:42 +0000351 # Since the FNAME flag is set, the zero-terminated filename follows.
352 # RFC 1952 specifies that this is the name of the input file, if any.
353 # However, the gzip module defaults to storing the name of the output
354 # file in this field.
Serhiy Storchaka700cfa82020-06-25 17:56:31 +0300355 nameBytes = fRead.read(len(expectedname))
356 self.assertEqual(nameBytes, expectedname)
Antoine Pitrou42db3ef2009-01-04 21:37:59 +0000357
Brian Curtin28f96b52010-10-13 02:21:42 +0000358 # Since no other flags were set, the header ends here.
359 # Rather than process the compressed data, let's seek to the trailer.
360 fRead.seek(os.stat(self.filename).st_size - 8)
Antoine Pitrou42db3ef2009-01-04 21:37:59 +0000361
Brian Curtin28f96b52010-10-13 02:21:42 +0000362 crc32Bytes = fRead.read(4) # CRC32 of uncompressed data [data1]
363 self.assertEqual(crc32Bytes, b'\xaf\xd7d\x83')
Antoine Pitrou42db3ef2009-01-04 21:37:59 +0000364
Brian Curtin28f96b52010-10-13 02:21:42 +0000365 isizeBytes = fRead.read(4)
366 self.assertEqual(isizeBytes, struct.pack('<i', len(data1)))
Antoine Pitrou42db3ef2009-01-04 21:37:59 +0000367
Serhiy Storchaka700cfa82020-06-25 17:56:31 +0300368 def test_metadata_ascii_name(self):
Hai Shibb0424b2020-08-04 00:47:42 +0800369 self.filename = os_helper.TESTFN_ASCII
Serhiy Storchaka700cfa82020-06-25 17:56:31 +0300370 self.test_metadata()
371
William Chargineab3b3f2020-01-21 03:25:24 -0800372 def test_compresslevel_metadata(self):
373 # see RFC 1952: http://www.faqs.org/rfcs/rfc1952.html
374 # specifically, discussion of XFL in section 2.3.1
375 cases = [
376 ('fast', 1, b'\x04'),
377 ('best', 9, b'\x02'),
378 ('tradeoff', 6, b'\x00'),
379 ]
380 xflOffset = 8
381
382 for (name, level, expectedXflByte) in cases:
383 with self.subTest(name):
384 fWrite = gzip.GzipFile(self.filename, 'w', compresslevel=level)
385 with fWrite:
386 fWrite.write(data1)
387 with open(self.filename, 'rb') as fRead:
388 fRead.seek(xflOffset)
389 xflByte = fRead.read(1)
390 self.assertEqual(xflByte, expectedXflByte)
391
Antoine Pitrou308705e2009-01-10 16:22:51 +0000392 def test_with_open(self):
393 # GzipFile supports the context management protocol
394 with gzip.GzipFile(self.filename, "wb") as f:
395 f.write(b"xxx")
396 f = gzip.GzipFile(self.filename, "rb")
397 f.close()
398 try:
399 with f:
400 pass
401 except ValueError:
402 pass
403 else:
404 self.fail("__enter__ on a closed file didn't raise an exception")
405 try:
406 with gzip.GzipFile(self.filename, "wb") as f:
407 1/0
408 except ZeroDivisionError:
409 pass
410 else:
411 self.fail("1/0 didn't raise an exception")
412
Antoine Pitrou8e33fd72010-01-13 14:37:26 +0000413 def test_zero_padded_file(self):
414 with gzip.GzipFile(self.filename, "wb") as f:
415 f.write(data1 * 50)
416
417 # Pad the file with zeroes
418 with open(self.filename, "ab") as f:
419 f.write(b"\x00" * 50)
420
421 with gzip.GzipFile(self.filename, "rb") as f:
422 d = f.read()
423 self.assertEqual(d, data1 * 50, "Incorrect data in file")
424
Zackery Spytzcf599f62019-05-13 01:50:52 -0600425 def test_gzip_BadGzipFile_exception(self):
426 self.assertTrue(issubclass(gzip.BadGzipFile, OSError))
427
428 def test_bad_gzip_file(self):
429 with open(self.filename, 'wb') as file:
430 file.write(data1 * 50)
431 with gzip.GzipFile(self.filename, 'r') as file:
432 self.assertRaises(gzip.BadGzipFile, file.readlines)
433
Antoine Pitrou7b969842010-09-23 16:22:51 +0000434 def test_non_seekable_file(self):
435 uncompressed = data1 * 50
436 buf = UnseekableIO()
437 with gzip.GzipFile(fileobj=buf, mode="wb") as f:
438 f.write(uncompressed)
439 compressed = buf.getvalue()
440 buf = UnseekableIO(compressed)
441 with gzip.GzipFile(fileobj=buf, mode="rb") as f:
442 self.assertEqual(f.read(), uncompressed)
443
Antoine Pitrouc3ed2e72010-09-29 10:49:46 +0000444 def test_peek(self):
445 uncompressed = data1 * 200
446 with gzip.GzipFile(self.filename, "wb") as f:
447 f.write(uncompressed)
448
449 def sizes():
450 while True:
451 for n in range(5, 50, 10):
452 yield n
453
454 with gzip.GzipFile(self.filename, "rb") as f:
455 f.max_read_chunk = 33
456 nread = 0
457 for n in sizes():
458 s = f.peek(n)
459 if s == b'':
460 break
461 self.assertEqual(f.read(len(s)), s)
462 nread += len(s)
463 self.assertEqual(f.read(100), b'')
464 self.assertEqual(nread, len(uncompressed))
465
Antoine Pitrou4ec4b0c2011-04-04 21:00:37 +0200466 def test_textio_readlines(self):
467 # Issue #10791: TextIOWrapper.readlines() fails when wrapping GzipFile.
Ezio Melottid8b509b2011-09-28 17:37:55 +0300468 lines = (data1 * 50).decode("ascii").splitlines(keepends=True)
Antoine Pitrou4ec4b0c2011-04-04 21:00:37 +0200469 self.test_write()
470 with gzip.GzipFile(self.filename, 'r') as f:
471 with io.TextIOWrapper(f, encoding="ascii") as t:
472 self.assertEqual(t.readlines(), lines)
473
Nadeem Vawda892b0b92012-01-18 09:25:58 +0200474 def test_fileobj_from_fdopen(self):
475 # Issue #13781: Opening a GzipFile for writing fails when using a
476 # fileobj created with os.fdopen().
477 fd = os.open(self.filename, os.O_WRONLY | os.O_CREAT)
478 with os.fdopen(fd, "wb") as f:
479 with gzip.GzipFile(fileobj=f, mode="w") as g:
480 pass
481
Serhiy Storchakabcbdd2f2017-10-22 13:18:21 +0300482 def test_fileobj_mode(self):
483 gzip.GzipFile(self.filename, "wb").close()
484 with open(self.filename, "r+b") as f:
485 with gzip.GzipFile(fileobj=f, mode='r') as g:
486 self.assertEqual(g.mode, gzip.READ)
487 with gzip.GzipFile(fileobj=f, mode='w') as g:
488 self.assertEqual(g.mode, gzip.WRITE)
489 with gzip.GzipFile(fileobj=f, mode='a') as g:
490 self.assertEqual(g.mode, gzip.WRITE)
491 with gzip.GzipFile(fileobj=f, mode='x') as g:
492 self.assertEqual(g.mode, gzip.WRITE)
493 with self.assertRaises(ValueError):
494 gzip.GzipFile(fileobj=f, mode='z')
495 for mode in "rb", "r+b":
496 with open(self.filename, mode) as f:
497 with gzip.GzipFile(fileobj=f) as g:
498 self.assertEqual(g.mode, gzip.READ)
499 for mode in "wb", "ab", "xb":
500 if "x" in mode:
Hai Shibb0424b2020-08-04 00:47:42 +0800501 os_helper.unlink(self.filename)
Serhiy Storchakabcbdd2f2017-10-22 13:18:21 +0300502 with open(self.filename, mode) as f:
Serhiy Storchakaa0652322019-11-16 18:56:57 +0200503 with self.assertWarns(FutureWarning):
504 g = gzip.GzipFile(fileobj=f)
505 with g:
Serhiy Storchakabcbdd2f2017-10-22 13:18:21 +0300506 self.assertEqual(g.mode, gzip.WRITE)
507
Nadeem Vawda103e8112012-06-20 01:35:22 +0200508 def test_bytes_filename(self):
509 str_filename = self.filename
510 try:
511 bytes_filename = str_filename.encode("ascii")
512 except UnicodeEncodeError:
513 self.skipTest("Temporary file name needs to be ASCII")
514 with gzip.GzipFile(bytes_filename, "wb") as f:
515 f.write(data1 * 50)
516 with gzip.GzipFile(bytes_filename, "rb") as f:
517 self.assertEqual(f.read(), data1 * 50)
518 # Sanity check that we are actually operating on the right file.
519 with gzip.GzipFile(str_filename, "rb") as f:
520 self.assertEqual(f.read(), data1 * 50)
521
Antoine Pitrou2dbc6e62015-04-11 00:31:01 +0200522 def test_decompress_limited(self):
523 """Decompressed data buffering should be limited"""
Serhiy Storchaka5f1a5182016-09-11 14:41:02 +0300524 bomb = gzip.compress(b'\0' * int(2e6), compresslevel=9)
Antoine Pitrou2dbc6e62015-04-11 00:31:01 +0200525 self.assertLess(len(bomb), io.DEFAULT_BUFFER_SIZE)
526
527 bomb = io.BytesIO(bomb)
528 decomp = gzip.GzipFile(fileobj=bomb)
Serhiy Storchaka5f1a5182016-09-11 14:41:02 +0300529 self.assertEqual(decomp.read(1), b'\0')
Antoine Pitrou2dbc6e62015-04-11 00:31:01 +0200530 max_decomp = 1 + io.DEFAULT_BUFFER_SIZE
531 self.assertLessEqual(decomp._buffer.raw.tell(), max_decomp,
532 "Excessive amount of data was decompressed")
533
Antoine Pitrou79c5ef12010-08-17 21:10:05 +0000534 # Testing compress/decompress shortcut functions
535
536 def test_compress(self):
537 for data in [data1, data2]:
538 for args in [(), (1,), (6,), (9,)]:
539 datac = gzip.compress(data, *args)
540 self.assertEqual(type(datac), bytes)
541 with gzip.GzipFile(fileobj=io.BytesIO(datac), mode="rb") as f:
542 self.assertEqual(f.read(), data)
543
guoci0e7497c2018-11-07 04:50:23 -0500544 def test_compress_mtime(self):
545 mtime = 123456789
546 for data in [data1, data2]:
547 for args in [(), (1,), (6,), (9,)]:
548 with self.subTest(data=data, args=args):
549 datac = gzip.compress(data, *args, mtime=mtime)
550 self.assertEqual(type(datac), bytes)
551 with gzip.GzipFile(fileobj=io.BytesIO(datac), mode="rb") as f:
552 f.read(1) # to set mtime attribute
553 self.assertEqual(f.mtime, mtime)
554
Antoine Pitrou79c5ef12010-08-17 21:10:05 +0000555 def test_decompress(self):
556 for data in (data1, data2):
557 buf = io.BytesIO()
558 with gzip.GzipFile(fileobj=buf, mode="wb") as f:
559 f.write(data)
560 self.assertEqual(gzip.decompress(buf.getvalue()), data)
561 # Roundtrip with compress
562 datac = gzip.compress(data)
563 self.assertEqual(gzip.decompress(datac), data)
564
Serhiy Storchaka7c3922f2013-01-22 17:01:59 +0200565 def test_read_truncated(self):
566 data = data1*50
567 # Drop the CRC (4 bytes) and file size (4 bytes).
568 truncated = gzip.compress(data)[:-8]
569 with gzip.GzipFile(fileobj=io.BytesIO(truncated)) as f:
570 self.assertRaises(EOFError, f.read)
571 with gzip.GzipFile(fileobj=io.BytesIO(truncated)) as f:
572 self.assertEqual(f.read(len(data)), data)
573 self.assertRaises(EOFError, f.read, 1)
574 # Incomplete 10-byte header.
575 for i in range(2, 10):
576 with gzip.GzipFile(fileobj=io.BytesIO(truncated[:i])) as f:
577 self.assertRaises(EOFError, f.read, 1)
578
Serhiy Storchaka7e69f002013-04-08 22:35:02 +0300579 def test_read_with_extra(self):
580 # Gzip data with an extra field
581 gzdata = (b'\x1f\x8b\x08\x04\xb2\x17cQ\x02\xff'
582 b'\x05\x00Extra'
583 b'\x0bI-.\x01\x002\xd1Mx\x04\x00\x00\x00')
584 with gzip.GzipFile(fileobj=io.BytesIO(gzdata)) as f:
585 self.assertEqual(f.read(), b'Test')
Nadeem Vawda7e126202012-05-06 15:04:01 +0200586
Ned Deily61207392014-03-09 14:44:34 -0700587 def test_prepend_error(self):
588 # See issue #20875
589 with gzip.open(self.filename, "wb") as f:
590 f.write(data1)
591 with gzip.open(self.filename, "rb") as f:
Antoine Pitrou2dbc6e62015-04-11 00:31:01 +0200592 f._buffer.raw._fp.prepend()
Ned Deily61207392014-03-09 14:44:34 -0700593
Miss Islington (bot)01858fb2021-06-22 06:59:53 -0700594 def test_issue44439(self):
595 q = array.array('Q', [1, 2, 3, 4, 5])
596 LENGTH = len(q) * q.itemsize
597
598 with gzip.GzipFile(fileobj=io.BytesIO(), mode='w') as f:
599 self.assertEqual(f.write(q), LENGTH)
600 self.assertEqual(f.tell(), LENGTH)
601
602
Nadeem Vawda1b8a14d2012-05-06 15:17:52 +0200603class TestOpen(BaseTest):
604 def test_binary_modes(self):
Nadeem Vawda7e126202012-05-06 15:04:01 +0200605 uncompressed = data1 * 50
Nadeem Vawdaee1be992013-10-19 00:11:13 +0200606
Nadeem Vawda7e126202012-05-06 15:04:01 +0200607 with gzip.open(self.filename, "wb") as f:
608 f.write(uncompressed)
609 with open(self.filename, "rb") as f:
610 file_data = gzip.decompress(f.read())
611 self.assertEqual(file_data, uncompressed)
Nadeem Vawdaee1be992013-10-19 00:11:13 +0200612
Nadeem Vawda7e126202012-05-06 15:04:01 +0200613 with gzip.open(self.filename, "rb") as f:
614 self.assertEqual(f.read(), uncompressed)
Nadeem Vawdaee1be992013-10-19 00:11:13 +0200615
Nadeem Vawda7e126202012-05-06 15:04:01 +0200616 with gzip.open(self.filename, "ab") as f:
617 f.write(uncompressed)
618 with open(self.filename, "rb") as f:
619 file_data = gzip.decompress(f.read())
620 self.assertEqual(file_data, uncompressed * 2)
621
Nadeem Vawdaee1be992013-10-19 00:11:13 +0200622 with self.assertRaises(FileExistsError):
623 gzip.open(self.filename, "xb")
Hai Shibb0424b2020-08-04 00:47:42 +0800624 os_helper.unlink(self.filename)
Nadeem Vawdaee1be992013-10-19 00:11:13 +0200625 with gzip.open(self.filename, "xb") as f:
626 f.write(uncompressed)
627 with open(self.filename, "rb") as f:
628 file_data = gzip.decompress(f.read())
629 self.assertEqual(file_data, uncompressed)
630
Berker Peksag03020cf2016-10-02 13:47:58 +0300631 def test_pathlike_file(self):
632 filename = pathlib.Path(self.filename)
633 with gzip.open(filename, "wb") as f:
634 f.write(data1 * 50)
635 with gzip.open(filename, "ab") as f:
636 f.write(data1)
637 with gzip.open(filename) as f:
638 self.assertEqual(f.read(), data1 * 51)
639
Nadeem Vawda1b8a14d2012-05-06 15:17:52 +0200640 def test_implicit_binary_modes(self):
Nadeem Vawda7e126202012-05-06 15:04:01 +0200641 # Test implicit binary modes (no "b" or "t" in mode string).
642 uncompressed = data1 * 50
Nadeem Vawdaee1be992013-10-19 00:11:13 +0200643
Nadeem Vawda7e126202012-05-06 15:04:01 +0200644 with gzip.open(self.filename, "w") as f:
645 f.write(uncompressed)
646 with open(self.filename, "rb") as f:
647 file_data = gzip.decompress(f.read())
648 self.assertEqual(file_data, uncompressed)
Nadeem Vawdaee1be992013-10-19 00:11:13 +0200649
Nadeem Vawda7e126202012-05-06 15:04:01 +0200650 with gzip.open(self.filename, "r") as f:
651 self.assertEqual(f.read(), uncompressed)
Nadeem Vawdaee1be992013-10-19 00:11:13 +0200652
Nadeem Vawda7e126202012-05-06 15:04:01 +0200653 with gzip.open(self.filename, "a") as f:
654 f.write(uncompressed)
655 with open(self.filename, "rb") as f:
656 file_data = gzip.decompress(f.read())
657 self.assertEqual(file_data, uncompressed * 2)
658
Nadeem Vawdaee1be992013-10-19 00:11:13 +0200659 with self.assertRaises(FileExistsError):
660 gzip.open(self.filename, "x")
Hai Shibb0424b2020-08-04 00:47:42 +0800661 os_helper.unlink(self.filename)
Nadeem Vawdaee1be992013-10-19 00:11:13 +0200662 with gzip.open(self.filename, "x") as f:
663 f.write(uncompressed)
664 with open(self.filename, "rb") as f:
665 file_data = gzip.decompress(f.read())
666 self.assertEqual(file_data, uncompressed)
667
Nadeem Vawda1b8a14d2012-05-06 15:17:52 +0200668 def test_text_modes(self):
Nadeem Vawda11328e42012-05-06 19:24:18 +0200669 uncompressed = data1.decode("ascii") * 50
670 uncompressed_raw = uncompressed.replace("\n", os.linesep)
Inada Naoki3caea9a2021-04-04 17:01:10 +0900671 with gzip.open(self.filename, "wt", encoding="ascii") as f:
Nadeem Vawda7e126202012-05-06 15:04:01 +0200672 f.write(uncompressed)
673 with open(self.filename, "rb") as f:
674 file_data = gzip.decompress(f.read()).decode("ascii")
Nadeem Vawda11328e42012-05-06 19:24:18 +0200675 self.assertEqual(file_data, uncompressed_raw)
Inada Naoki3caea9a2021-04-04 17:01:10 +0900676 with gzip.open(self.filename, "rt", encoding="ascii") as f:
Nadeem Vawda7e126202012-05-06 15:04:01 +0200677 self.assertEqual(f.read(), uncompressed)
Inada Naoki3caea9a2021-04-04 17:01:10 +0900678 with gzip.open(self.filename, "at", encoding="ascii") as f:
Nadeem Vawda7e126202012-05-06 15:04:01 +0200679 f.write(uncompressed)
680 with open(self.filename, "rb") as f:
681 file_data = gzip.decompress(f.read()).decode("ascii")
Nadeem Vawda11328e42012-05-06 19:24:18 +0200682 self.assertEqual(file_data, uncompressed_raw * 2)
Nadeem Vawda7e126202012-05-06 15:04:01 +0200683
Nadeem Vawda68721012012-06-04 23:21:38 +0200684 def test_fileobj(self):
685 uncompressed_bytes = data1 * 50
686 uncompressed_str = uncompressed_bytes.decode("ascii")
687 compressed = gzip.compress(uncompressed_bytes)
688 with gzip.open(io.BytesIO(compressed), "r") as f:
689 self.assertEqual(f.read(), uncompressed_bytes)
690 with gzip.open(io.BytesIO(compressed), "rb") as f:
691 self.assertEqual(f.read(), uncompressed_bytes)
Inada Naoki3caea9a2021-04-04 17:01:10 +0900692 with gzip.open(io.BytesIO(compressed), "rt", encoding="ascii") as f:
Nadeem Vawda68721012012-06-04 23:21:38 +0200693 self.assertEqual(f.read(), uncompressed_str)
694
Nadeem Vawda1b8a14d2012-05-06 15:17:52 +0200695 def test_bad_params(self):
Nadeem Vawda7e126202012-05-06 15:04:01 +0200696 # Test invalid parameter combinations.
Nadeem Vawda68721012012-06-04 23:21:38 +0200697 with self.assertRaises(TypeError):
698 gzip.open(123.456)
Nadeem Vawda7e126202012-05-06 15:04:01 +0200699 with self.assertRaises(ValueError):
700 gzip.open(self.filename, "wbt")
701 with self.assertRaises(ValueError):
Nadeem Vawdaee1be992013-10-19 00:11:13 +0200702 gzip.open(self.filename, "xbt")
703 with self.assertRaises(ValueError):
Nadeem Vawda7e126202012-05-06 15:04:01 +0200704 gzip.open(self.filename, "rb", encoding="utf-8")
705 with self.assertRaises(ValueError):
706 gzip.open(self.filename, "rb", errors="ignore")
707 with self.assertRaises(ValueError):
708 gzip.open(self.filename, "rb", newline="\n")
709
Nadeem Vawda1b8a14d2012-05-06 15:17:52 +0200710 def test_encoding(self):
Nadeem Vawda7e126202012-05-06 15:04:01 +0200711 # Test non-default encoding.
Nadeem Vawda11328e42012-05-06 19:24:18 +0200712 uncompressed = data1.decode("ascii") * 50
713 uncompressed_raw = uncompressed.replace("\n", os.linesep)
Nadeem Vawda7e126202012-05-06 15:04:01 +0200714 with gzip.open(self.filename, "wt", encoding="utf-16") as f:
715 f.write(uncompressed)
716 with open(self.filename, "rb") as f:
717 file_data = gzip.decompress(f.read()).decode("utf-16")
Nadeem Vawda11328e42012-05-06 19:24:18 +0200718 self.assertEqual(file_data, uncompressed_raw)
Nadeem Vawda7e126202012-05-06 15:04:01 +0200719 with gzip.open(self.filename, "rt", encoding="utf-16") as f:
720 self.assertEqual(f.read(), uncompressed)
721
Nadeem Vawda1b8a14d2012-05-06 15:17:52 +0200722 def test_encoding_error_handler(self):
Nadeem Vawda7e126202012-05-06 15:04:01 +0200723 # Test with non-default encoding error handler.
724 with gzip.open(self.filename, "wb") as f:
725 f.write(b"foo\xffbar")
726 with gzip.open(self.filename, "rt", encoding="ascii", errors="ignore") \
727 as f:
728 self.assertEqual(f.read(), "foobar")
729
Nadeem Vawda1b8a14d2012-05-06 15:17:52 +0200730 def test_newline(self):
Nadeem Vawda7e126202012-05-06 15:04:01 +0200731 # Test with explicit newline (universal newline mode disabled).
732 uncompressed = data1.decode("ascii") * 50
Inada Naoki3caea9a2021-04-04 17:01:10 +0900733 with gzip.open(self.filename, "wt", encoding="ascii", newline="\n") as f:
Nadeem Vawda7e126202012-05-06 15:04:01 +0200734 f.write(uncompressed)
Inada Naoki3caea9a2021-04-04 17:01:10 +0900735 with gzip.open(self.filename, "rt", encoding="ascii", newline="\r") as f:
Nadeem Vawda7e126202012-05-06 15:04:01 +0200736 self.assertEqual(f.readlines(), [uncompressed])
737
Stéphane Wirtel84eec112018-10-09 23:16:43 +0200738
739def create_and_remove_directory(directory):
740 def decorator(function):
741 @functools.wraps(function)
742 def wrapper(*args, **kwargs):
743 os.makedirs(directory)
744 try:
745 return function(*args, **kwargs)
746 finally:
Hai Shibb0424b2020-08-04 00:47:42 +0800747 os_helper.rmtree(directory)
Stéphane Wirtel84eec112018-10-09 23:16:43 +0200748 return wrapper
749 return decorator
750
751
752class TestCommandLine(unittest.TestCase):
753 data = b'This is a simple test with gzip'
754
755 def test_decompress_stdin_stdout(self):
756 with io.BytesIO() as bytes_io:
757 with gzip.GzipFile(fileobj=bytes_io, mode='wb') as gzip_file:
758 gzip_file.write(self.data)
759
760 args = sys.executable, '-m', 'gzip', '-d'
761 with Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE) as proc:
762 out, err = proc.communicate(bytes_io.getvalue())
763
764 self.assertEqual(err, b'')
765 self.assertEqual(out, self.data)
766
767 @create_and_remove_directory(TEMPDIR)
768 def test_decompress_infile_outfile(self):
769 gzipname = os.path.join(TEMPDIR, 'testgzip.gz')
770 self.assertFalse(os.path.exists(gzipname))
771
772 with gzip.open(gzipname, mode='wb') as fp:
773 fp.write(self.data)
774 rc, out, err = assert_python_ok('-m', 'gzip', '-d', gzipname)
775
776 with open(os.path.join(TEMPDIR, "testgzip"), "rb") as gunziped:
777 self.assertEqual(gunziped.read(), self.data)
778
779 self.assertTrue(os.path.exists(gzipname))
780 self.assertEqual(rc, 0)
781 self.assertEqual(out, b'')
782 self.assertEqual(err, b'')
783
784 def test_decompress_infile_outfile_error(self):
Ruben Vordermancc3df632021-02-25 12:30:24 +0100785 rc, out, err = assert_python_failure('-m', 'gzip', '-d', 'thisisatest.out')
Inada Naoki9525a182021-02-26 11:09:06 +0900786 self.assertEqual(b"filename doesn't end in .gz: 'thisisatest.out'", err.strip())
Ruben Vordermancc3df632021-02-25 12:30:24 +0100787 self.assertEqual(rc, 1)
788 self.assertEqual(out, b'')
Stéphane Wirtel84eec112018-10-09 23:16:43 +0200789
790 @create_and_remove_directory(TEMPDIR)
791 def test_compress_stdin_outfile(self):
792 args = sys.executable, '-m', 'gzip'
793 with Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE) as proc:
794 out, err = proc.communicate(self.data)
795
796 self.assertEqual(err, b'')
797 self.assertEqual(out[:2], b"\x1f\x8b")
798
799 @create_and_remove_directory(TEMPDIR)
Gregory P. Smithcd466552019-04-14 10:32:07 -0700800 def test_compress_infile_outfile_default(self):
Stéphane Wirtel84eec112018-10-09 23:16:43 +0200801 local_testgzip = os.path.join(TEMPDIR, 'testgzip')
802 gzipname = local_testgzip + '.gz'
803 self.assertFalse(os.path.exists(gzipname))
804
805 with open(local_testgzip, 'wb') as fp:
806 fp.write(self.data)
807
808 rc, out, err = assert_python_ok('-m', 'gzip', local_testgzip)
809
810 self.assertTrue(os.path.exists(gzipname))
Stéphane Wirtel84eec112018-10-09 23:16:43 +0200811 self.assertEqual(out, b'')
812 self.assertEqual(err, b'')
813
Stéphane Wirtel3e28eed2018-11-03 16:24:23 +0100814 @create_and_remove_directory(TEMPDIR)
815 def test_compress_infile_outfile(self):
816 for compress_level in ('--fast', '--best'):
817 with self.subTest(compress_level=compress_level):
818 local_testgzip = os.path.join(TEMPDIR, 'testgzip')
819 gzipname = local_testgzip + '.gz'
820 self.assertFalse(os.path.exists(gzipname))
821
822 with open(local_testgzip, 'wb') as fp:
823 fp.write(self.data)
824
825 rc, out, err = assert_python_ok('-m', 'gzip', compress_level, local_testgzip)
826
827 self.assertTrue(os.path.exists(gzipname))
828 self.assertEqual(out, b'')
829 self.assertEqual(err, b'')
830 os.remove(gzipname)
831 self.assertFalse(os.path.exists(gzipname))
832
833 def test_compress_fast_best_are_exclusive(self):
834 rc, out, err = assert_python_failure('-m', 'gzip', '--fast', '--best')
835 self.assertIn(b"error: argument --best: not allowed with argument --fast", err)
836 self.assertEqual(out, b'')
837
838 def test_decompress_cannot_have_flags_compression(self):
839 rc, out, err = assert_python_failure('-m', 'gzip', '--fast', '-d')
840 self.assertIn(b'error: argument -d/--decompress: not allowed with argument --fast', err)
841 self.assertEqual(out, b'')
842
Stéphane Wirtel84eec112018-10-09 23:16:43 +0200843
Andrew M. Kuchlinga6f68e12005-06-09 14:12:36 +0000844if __name__ == "__main__":
Serhiy Storchakabedce352021-09-19 22:36:03 +0300845 unittest.main()