Skip to content

Commit d7d04da

Browse files
committed
Updated zipfile library + test
1 parent 0f893ec commit d7d04da

File tree

3 files changed

+144
-63
lines changed

3 files changed

+144
-63
lines changed

Lib/test/test_zipfile/_path/test_path.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,8 @@ def test_pathlike_construction(self, alpharep):
275275
"""
276276
zipfile_ondisk = self.zipfile_ondisk(alpharep)
277277
pathlike = FakePath(str(zipfile_ondisk))
278-
zipfile.Path(pathlike)
278+
root = zipfile.Path(pathlike)
279+
root.root.close()
279280

280281
@pass_alpharep
281282
def test_traverse_pathlike(self, alpharep):
@@ -374,6 +375,7 @@ def test_root_on_disk(self, alpharep):
374375
root = zipfile.Path(self.zipfile_ondisk(alpharep))
375376
assert root.name == 'alpharep.zip' == root.filename.name
376377
assert root.stem == 'alpharep' == root.filename.stem
378+
root.root.close()
377379

378380
@pass_alpharep
379381
def test_suffix(self, alpharep):
@@ -565,7 +567,7 @@ def test_inheritance(self, alpharep):
565567
file = cls(alpharep).joinpath('some dir').parent
566568
assert isinstance(file, cls)
567569

568-
@unittest.skipIf(sys.platform == 'win32', "TODO: RUSTPYTHON, fails on Windows")
570+
@unittest.skipIf(sys.platform == 'win32', 'TODO: RUSTPYTHON; fails on Windows')
569571
@parameterize(
570572
['alpharep', 'path_type', 'subpath'],
571573
itertools.product(
@@ -576,11 +578,13 @@ def test_inheritance(self, alpharep):
576578
)
577579
def test_pickle(self, alpharep, path_type, subpath):
578580
zipfile_ondisk = path_type(str(self.zipfile_ondisk(alpharep)))
579-
580-
saved_1 = pickle.dumps(zipfile.Path(zipfile_ondisk, at=subpath))
581+
root = zipfile.Path(zipfile_ondisk, at=subpath)
582+
saved_1 = pickle.dumps(root)
583+
root.root.close()
581584
restored_1 = pickle.loads(saved_1)
582585
first, *rest = restored_1.iterdir()
583586
assert first.read_text(encoding='utf-8').startswith('content of ')
587+
restored_1.root.close()
584588

585589
@pass_alpharep
586590
def test_extract_orig_with_implied_dirs(self, alpharep):
@@ -592,6 +596,7 @@ def test_extract_orig_with_implied_dirs(self, alpharep):
592596
# wrap the zipfile for its side effect
593597
zipfile.Path(zf)
594598
zf.extractall(source_path.parent)
599+
zf.close()
595600

596601
@pass_alpharep
597602
def test_getinfo_missing(self, alpharep):

Lib/test/test_zipfile/test_core.py

Lines changed: 103 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -302,26 +302,26 @@ def test_low_compression(self):
302302
self.assertEqual(openobj.read(1), b'2')
303303

304304
def test_writestr_compression(self):
305-
zipfp = zipfile.ZipFile(TESTFN2, "w")
306-
zipfp.writestr("b.txt", "hello world", compress_type=self.compression)
307-
info = zipfp.getinfo('b.txt')
308-
self.assertEqual(info.compress_type, self.compression)
305+
with zipfile.ZipFile(TESTFN2, "w") as zipfp:
306+
zipfp.writestr("b.txt", "hello world", compress_type=self.compression)
307+
info = zipfp.getinfo('b.txt')
308+
self.assertEqual(info.compress_type, self.compression)
309309

310310
def test_writestr_compresslevel(self):
311-
zipfp = zipfile.ZipFile(TESTFN2, "w", compresslevel=1)
312-
zipfp.writestr("a.txt", "hello world", compress_type=self.compression)
313-
zipfp.writestr("b.txt", "hello world", compress_type=self.compression,
314-
compresslevel=2)
311+
with zipfile.ZipFile(TESTFN2, "w", compresslevel=1) as zipfp:
312+
zipfp.writestr("a.txt", "hello world", compress_type=self.compression)
313+
zipfp.writestr("b.txt", "hello world", compress_type=self.compression,
314+
compresslevel=2)
315315

316-
# Compression level follows the constructor.
317-
a_info = zipfp.getinfo('a.txt')
318-
self.assertEqual(a_info.compress_type, self.compression)
319-
self.assertEqual(a_info.compress_level, 1)
316+
# Compression level follows the constructor.
317+
a_info = zipfp.getinfo('a.txt')
318+
self.assertEqual(a_info.compress_type, self.compression)
319+
self.assertEqual(a_info.compress_level, 1)
320320

321-
# Compression level is overridden.
322-
b_info = zipfp.getinfo('b.txt')
323-
self.assertEqual(b_info.compress_type, self.compression)
324-
self.assertEqual(b_info._compresslevel, 2)
321+
# Compression level is overridden.
322+
b_info = zipfp.getinfo('b.txt')
323+
self.assertEqual(b_info.compress_type, self.compression)
324+
self.assertEqual(b_info._compresslevel, 2)
325325

326326
def test_read_return_size(self):
327327
# Issue #9837: ZipExtFile.read() shouldn't return more bytes
@@ -884,6 +884,8 @@ def make_zip64_file(
884884
self, file_size_64_set=False, file_size_extra=False,
885885
compress_size_64_set=False, compress_size_extra=False,
886886
header_offset_64_set=False, header_offset_extra=False,
887+
extensible_data=b'',
888+
end_of_central_dir_size=None, offset_to_end_of_central_dir=None,
887889
):
888890
"""Generate bytes sequence for a zip with (incomplete) zip64 data.
889891
@@ -937,6 +939,12 @@ def make_zip64_file(
937939

938940
central_dir_size = struct.pack('<Q', 58 + 8 * len(central_zip64_fields))
939941
offset_to_central_dir = struct.pack('<Q', 50 + 8 * len(local_zip64_fields))
942+
if end_of_central_dir_size is None:
943+
end_of_central_dir_size = 44 + len(extensible_data)
944+
if offset_to_end_of_central_dir is None:
945+
offset_to_end_of_central_dir = (108
946+
+ 8 * len(local_zip64_fields)
947+
+ 8 * len(central_zip64_fields))
940948

941949
local_extra_length = struct.pack("<H", 4 + 8 * len(local_zip64_fields))
942950
central_extra_length = struct.pack("<H", 4 + 8 * len(central_zip64_fields))
@@ -965,14 +973,17 @@ def make_zip64_file(
965973
+ filename
966974
+ central_extra
967975
# Zip64 end of central directory
968-
+ b"PK\x06\x06,\x00\x00\x00\x00\x00\x00\x00-\x00-"
969-
+ b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00"
976+
+ b"PK\x06\x06"
977+
+ struct.pack('<Q', end_of_central_dir_size)
978+
+ b"-\x00-\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00"
970979
+ b"\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00"
971980
+ central_dir_size
972981
+ offset_to_central_dir
982+
+ extensible_data
973983
# Zip64 end of central directory locator
974-
+ b"PK\x06\x07\x00\x00\x00\x00l\x00\x00\x00\x00\x00\x00\x00\x01"
975-
+ b"\x00\x00\x00"
984+
+ b"PK\x06\x07\x00\x00\x00\x00"
985+
+ struct.pack('<Q', offset_to_end_of_central_dir)
986+
+ b"\x01\x00\x00\x00"
976987
# end of central directory
977988
+ b"PK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x00:\x00\x00\x002\x00"
978989
+ b"\x00\x00\x00\x00"
@@ -1003,6 +1014,7 @@ def test_bad_zip64_extra(self):
10031014
with self.assertRaises(zipfile.BadZipFile) as e:
10041015
zipfile.ZipFile(io.BytesIO(missing_file_size_extra))
10051016
self.assertIn('file size', str(e.exception).lower())
1017+
self.assertTrue(zipfile.is_zipfile(io.BytesIO(missing_file_size_extra)))
10061018

10071019
# zip64 file size present, zip64 compress size present, one field in
10081020
# extra, expecting two, equals missing compress size.
@@ -1014,6 +1026,7 @@ def test_bad_zip64_extra(self):
10141026
with self.assertRaises(zipfile.BadZipFile) as e:
10151027
zipfile.ZipFile(io.BytesIO(missing_compress_size_extra))
10161028
self.assertIn('compress size', str(e.exception).lower())
1029+
self.assertTrue(zipfile.is_zipfile(io.BytesIO(missing_compress_size_extra)))
10171030

10181031
# zip64 compress size present, no fields in extra, expecting one,
10191032
# equals missing compress size.
@@ -1023,6 +1036,7 @@ def test_bad_zip64_extra(self):
10231036
with self.assertRaises(zipfile.BadZipFile) as e:
10241037
zipfile.ZipFile(io.BytesIO(missing_compress_size_extra))
10251038
self.assertIn('compress size', str(e.exception).lower())
1039+
self.assertTrue(zipfile.is_zipfile(io.BytesIO(missing_compress_size_extra)))
10261040

10271041
# zip64 file size present, zip64 compress size present, zip64 header
10281042
# offset present, two fields in extra, expecting three, equals missing
@@ -1037,6 +1051,7 @@ def test_bad_zip64_extra(self):
10371051
with self.assertRaises(zipfile.BadZipFile) as e:
10381052
zipfile.ZipFile(io.BytesIO(missing_header_offset_extra))
10391053
self.assertIn('header offset', str(e.exception).lower())
1054+
self.assertTrue(zipfile.is_zipfile(io.BytesIO(missing_header_offset_extra)))
10401055

10411056
# zip64 compress size present, zip64 header offset present, one field
10421057
# in extra, expecting two, equals missing header offset
@@ -1049,6 +1064,7 @@ def test_bad_zip64_extra(self):
10491064
with self.assertRaises(zipfile.BadZipFile) as e:
10501065
zipfile.ZipFile(io.BytesIO(missing_header_offset_extra))
10511066
self.assertIn('header offset', str(e.exception).lower())
1067+
self.assertTrue(zipfile.is_zipfile(io.BytesIO(missing_header_offset_extra)))
10521068

10531069
# zip64 file size present, zip64 header offset present, one field in
10541070
# extra, expecting two, equals missing header offset
@@ -1061,6 +1077,7 @@ def test_bad_zip64_extra(self):
10611077
with self.assertRaises(zipfile.BadZipFile) as e:
10621078
zipfile.ZipFile(io.BytesIO(missing_header_offset_extra))
10631079
self.assertIn('header offset', str(e.exception).lower())
1080+
self.assertTrue(zipfile.is_zipfile(io.BytesIO(missing_header_offset_extra)))
10641081

10651082
# zip64 header offset present, no fields in extra, expecting one,
10661083
# equals missing header offset
@@ -1072,6 +1089,63 @@ def test_bad_zip64_extra(self):
10721089
with self.assertRaises(zipfile.BadZipFile) as e:
10731090
zipfile.ZipFile(io.BytesIO(missing_header_offset_extra))
10741091
self.assertIn('header offset', str(e.exception).lower())
1092+
self.assertTrue(zipfile.is_zipfile(io.BytesIO(missing_header_offset_extra)))
1093+
1094+
def test_bad_zip64_end_of_central_dir(self):
1095+
zipdata = self.make_zip64_file(end_of_central_dir_size=0)
1096+
with self.assertRaisesRegex(zipfile.BadZipFile, 'Corrupt.*record'):
1097+
zipfile.ZipFile(io.BytesIO(zipdata))
1098+
self.assertFalse(zipfile.is_zipfile(io.BytesIO(zipdata)))
1099+
1100+
zipdata = self.make_zip64_file(end_of_central_dir_size=100)
1101+
with self.assertRaisesRegex(zipfile.BadZipFile, 'Corrupt.*record'):
1102+
zipfile.ZipFile(io.BytesIO(zipdata))
1103+
self.assertFalse(zipfile.is_zipfile(io.BytesIO(zipdata)))
1104+
1105+
zipdata = self.make_zip64_file(offset_to_end_of_central_dir=0)
1106+
with self.assertRaisesRegex(zipfile.BadZipFile, 'Corrupt.*record'):
1107+
zipfile.ZipFile(io.BytesIO(zipdata))
1108+
self.assertFalse(zipfile.is_zipfile(io.BytesIO(zipdata)))
1109+
1110+
zipdata = self.make_zip64_file(offset_to_end_of_central_dir=1000)
1111+
with self.assertRaisesRegex(zipfile.BadZipFile, 'Corrupt.*locator'):
1112+
zipfile.ZipFile(io.BytesIO(zipdata))
1113+
self.assertFalse(zipfile.is_zipfile(io.BytesIO(zipdata)))
1114+
1115+
def test_zip64_end_of_central_dir_record_not_found(self):
1116+
zipdata = self.make_zip64_file()
1117+
zipdata = zipdata.replace(b"PK\x06\x06", b'\x00'*4)
1118+
with self.assertRaisesRegex(zipfile.BadZipFile, 'record not found'):
1119+
zipfile.ZipFile(io.BytesIO(zipdata))
1120+
self.assertFalse(zipfile.is_zipfile(io.BytesIO(zipdata)))
1121+
1122+
zipdata = self.make_zip64_file(
1123+
extensible_data=b'\xca\xfe\x04\x00\x00\x00data')
1124+
zipdata = zipdata.replace(b"PK\x06\x06", b'\x00'*4)
1125+
with self.assertRaisesRegex(zipfile.BadZipFile, 'record not found'):
1126+
zipfile.ZipFile(io.BytesIO(zipdata))
1127+
self.assertFalse(zipfile.is_zipfile(io.BytesIO(zipdata)))
1128+
1129+
def test_zip64_extensible_data(self):
1130+
# These values are what is set in the make_zip64_file method.
1131+
expected_file_size = 8
1132+
expected_compress_size = 8
1133+
expected_header_offset = 0
1134+
expected_content = b"test1234"
1135+
1136+
zipdata = self.make_zip64_file(
1137+
extensible_data=b'\xca\xfe\x04\x00\x00\x00data')
1138+
with zipfile.ZipFile(io.BytesIO(zipdata)) as zf:
1139+
zinfo = zf.infolist()[0]
1140+
self.assertEqual(zinfo.file_size, expected_file_size)
1141+
self.assertEqual(zinfo.compress_size, expected_compress_size)
1142+
self.assertEqual(zinfo.header_offset, expected_header_offset)
1143+
self.assertEqual(zf.read(zinfo), expected_content)
1144+
self.assertTrue(zipfile.is_zipfile(io.BytesIO(zipdata)))
1145+
1146+
with self.assertRaisesRegex(zipfile.BadZipFile, 'record not found'):
1147+
zipfile.ZipFile(io.BytesIO(b'prepended' + zipdata))
1148+
self.assertFalse(zipfile.is_zipfile(io.BytesIO(b'prepended' + zipdata)))
10751149

10761150
def test_generated_valid_zip64_extra(self):
10771151
# These values are what is set in the make_zip64_file method.
@@ -1357,8 +1431,7 @@ def requiresWriteAccess(self, path):
13571431
self.skipTest('requires write access to the installed location')
13581432
unlink(filename)
13591433

1360-
# TODO: RUSTPYTHON
1361-
@unittest.expectedFailure
1434+
@unittest.expectedFailure # TODO: RUSTPYTHON
13621435
def test_write_pyfile(self):
13631436
self.requiresWriteAccess(os.path.dirname(__file__))
13641437
with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
@@ -1389,8 +1462,7 @@ def test_write_pyfile(self):
13891462
self.assertNotIn(bn, zipfp.namelist())
13901463
self.assertCompiledIn(bn, zipfp.namelist())
13911464

1392-
# TODO: RUSTPYTHON
1393-
@unittest.expectedFailure
1465+
@unittest.expectedFailure # TODO: RUSTPYTHON
13941466
def test_write_python_package(self):
13951467
import email
13961468
packagedir = os.path.dirname(email.__file__)
@@ -1405,8 +1477,7 @@ def test_write_python_package(self):
14051477
self.assertCompiledIn('email/__init__.py', names)
14061478
self.assertCompiledIn('email/mime/text.py', names)
14071479

1408-
# TODO: RUSTPYTHON - AttributeError: module 'os' has no attribute 'supports_effective_ids'
1409-
@unittest.expectedFailure
1480+
@unittest.expectedFailure # TODO: RUSTPYTHON; - AttributeError: module 'os' has no attribute 'supports_effective_ids'
14101481
def test_write_filtered_python_package(self):
14111482
import test
14121483
packagedir = os.path.dirname(test.__file__)
@@ -1437,8 +1508,7 @@ def filter(path):
14371508
print(reportStr)
14381509
self.assertTrue('SyntaxError' not in reportStr)
14391510

1440-
# TODO: RUSTPYTHON
1441-
@unittest.expectedFailure
1511+
@unittest.expectedFailure # TODO: RUSTPYTHON
14421512
def test_write_with_optimization(self):
14431513
import email
14441514
packagedir = os.path.dirname(email.__file__)
@@ -2189,13 +2259,15 @@ def test_empty_zipfile(self):
21892259
zipf = zipfile.ZipFile(TESTFN, mode="r")
21902260
except zipfile.BadZipFile:
21912261
self.fail("Unable to create empty ZIP file in 'w' mode")
2262+
zipf.close()
21922263

21932264
zipf = zipfile.ZipFile(TESTFN, mode="a")
21942265
zipf.close()
21952266
try:
21962267
zipf = zipfile.ZipFile(TESTFN, mode="r")
21972268
except:
21982269
self.fail("Unable to create empty ZIP file in 'a' mode")
2270+
zipf.close()
21992271

22002272
def test_open_empty_file(self):
22012273
# Issue 1710703: Check that opening a file with less than 22 bytes
@@ -3020,11 +3092,6 @@ def test_write_after_read(self):
30203092
self.assertEqual(data1, self.data1)
30213093
self.assertEqual(data2, self.data2)
30223094

3023-
# TODO: RUSTPYTHON other tests can impact the file descriptor incrementor
3024-
# by leaving file handles unclosed. If there are more than 100 files in
3025-
# TESTFN and references to them are left unclosed and ungarbage collected
3026-
# in another test, then fileno() will always be too high for this test to
3027-
# pass. The solution is to increase the number of files from 100 to 200
30283095
def test_many_opens(self):
30293096
# Verify that read() and open() promptly close the file descriptor,
30303097
# and don't rely on the garbage collector to free resources.
@@ -3348,8 +3415,7 @@ def test_read_zip_with_exe_prepended(self):
33483415
def test_read_zip64_with_exe_prepended(self):
33493416
self._test_zip_works(self.exe_zip64)
33503417

3351-
# TODO: RUSTPYTHON
3352-
@unittest.expectedFailure
3418+
@unittest.expectedFailure # TODO: RUSTPYTHON
33533419
@unittest.skipUnless(sys.executable, 'sys.executable required.')
33543420
@unittest.skipUnless(os.access('/bin/bash', os.X_OK),
33553421
'Test relies on #!/bin/bash working.')
@@ -3358,8 +3424,7 @@ def test_execute_zip2(self):
33583424
output = subprocess.check_output([self.exe_zip, sys.executable])
33593425
self.assertIn(b'number in executable: 5', output)
33603426

3361-
# TODO: RUSTPYTHON
3362-
@unittest.expectedFailure
3427+
@unittest.expectedFailure # TODO: RUSTPYTHON
33633428
@unittest.skipUnless(sys.executable, 'sys.executable required.')
33643429
@unittest.skipUnless(os.access('/bin/bash', os.X_OK),
33653430
'Test relies on #!/bin/bash working.')
@@ -3369,16 +3434,14 @@ def test_execute_zip64(self):
33693434
self.assertIn(b'number in executable: 5', output)
33703435

33713436

3372-
# TODO: RUSTPYTHON
3373-
@unittest.skip("TODO: RUSTPYTHON shift_jis encoding unsupported")
33743437
class EncodedMetadataTests(unittest.TestCase):
33753438
file_names = ['\u4e00', '\u4e8c', '\u4e09'] # Han 'one', 'two', 'three'
33763439
file_content = [
33773440
"This is pure ASCII.\n".encode('ascii'),
33783441
# This is modern Japanese. (UTF-8)
33793442
"\u3053\u308c\u306f\u73fe\u4ee3\u7684\u65e5\u672c\u8a9e\u3067\u3059\u3002\n".encode('utf-8'),
33803443
# This is obsolete Japanese. (Shift JIS)
3381-
# "\u3053\u308c\u306f\u53e4\u3044\u65e5\u672c\u8a9e\u3067\u3059\u3002\n".encode('shift_jis'), # TODO: RUSTPYTHON
3444+
"\u3053\u308c\u306f\u53e4\u3044\u65e5\u672c\u8a9e\u3067\u3059\u3002\n".encode('shift_jis'),
33823445
]
33833446

33843447
def setUp(self):

0 commit comments

Comments
 (0)