From 9decb4a530af06a6415a3565d462807be9578744 Mon Sep 17 00:00:00 2001 From: zhangli091011 Date: Mon, 20 Jul 2026 04:49:44 +0800 Subject: [PATCH 1/5] gh-154174: Fix ZipFile.mkdir with a fresh ZipInfo --- Lib/test/test_zipfile/test_core.py | 31 +++++++++++++++++-- Lib/zipfile/__init__.py | 7 +++-- ...-07-20-04-33-58.gh-issue-154174.A7mQ2x.rst | 2 ++ 3 files changed, 34 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-20-04-33-58.gh-issue-154174.A7mQ2x.rst diff --git a/Lib/test/test_zipfile/test_core.py b/Lib/test/test_zipfile/test_core.py index 4f20209927e7b3d..b23640a4a0beb5b 100644 --- a/Lib/test/test_zipfile/test_core.py +++ b/Lib/test/test_zipfile/test_core.py @@ -5463,9 +5463,6 @@ def test_mkdir(self): old_zinfo = zipfile.ZipInfo("directory4/") old_zinfo.external_attr = (0o40777 << 16) | 0x10 - old_zinfo.CRC = 0 - old_zinfo.file_size = 0 - old_zinfo.compress_size = 0 zf.mkdir(old_zinfo) new_zinfo = zf.filelist[3] self.assertEqual(old_zinfo.filename, "directory4/") @@ -5476,6 +5473,34 @@ def test_mkdir(self): zf.extractall(target) self.assertEqual(set(os.listdir(target)), {"directory", "directory2", "directory3", "directory4"}) + def test_mkdir_zipinfo_preserves_metadata(self): + zinfo = zipfile.ZipInfo("directory/", (2001, 2, 3, 4, 5, 6)) + zinfo.compress_type = zipfile.ZIP_STORED + zinfo.compress_level = 1 + zinfo.comment = b"comment" + zinfo.extra = b"\x99\x99\x00\x00" + zinfo.external_attr = (0o40700 << 16) | 0x10 + zinfo.file_size = 1 + zinfo.compress_size = 2 + + archive = io.BytesIO() + with zipfile.ZipFile( + archive, "w", zipfile.ZIP_DEFLATED, compresslevel=9 + ) as zf: + zf.mkdir(zinfo) + self.assertEqual(zinfo.compress_level, 1) + + self.assertEqual(zinfo.CRC, 0) + self.assertEqual(zinfo.file_size, 0) + self.assertEqual(zinfo.compress_size, 0) + with zipfile.ZipFile(archive) as zf: + written = zf.getinfo("directory/") + self.assertEqual(written.date_time, (2001, 2, 3, 4, 5, 6)) + self.assertEqual(written.compress_type, zipfile.ZIP_STORED) + self.assertEqual(written.comment, b"comment") + self.assertEqual(written.extra, b"\x99\x99\x00\x00") + self.assertEqual(written.external_attr, (0o40700 << 16) | 0x10) + def test_create_directory_with_write(self): with zipfile.ZipFile(TESTFN, "w") as zf: zf.writestr(zipfile.ZipInfo('directory/'), '') diff --git a/Lib/zipfile/__init__.py b/Lib/zipfile/__init__.py index 418933a2e8d9e87..0411d15dcaa45c5 100644 --- a/Lib/zipfile/__init__.py +++ b/Lib/zipfile/__init__.py @@ -2590,14 +2590,15 @@ def mkdir(self, zinfo_or_directory_name, mode=511): if not directory_name.endswith("/"): directory_name += "/" zinfo = ZipInfo(directory_name) - zinfo.compress_size = 0 - zinfo.CRC = 0 zinfo.external_attr = ((0o40000 | mode) & 0xFFFF) << 16 - zinfo.file_size = 0 zinfo.external_attr |= 0x10 else: raise TypeError("Expected type str or ZipInfo") + zinfo.compress_size = 0 + zinfo.CRC = 0 + zinfo.file_size = 0 + with self._lock: if self._seekable: self.fp.seek(self.start_dir) diff --git a/Misc/NEWS.d/next/Library/2026-07-20-04-33-58.gh-issue-154174.A7mQ2x.rst b/Misc/NEWS.d/next/Library/2026-07-20-04-33-58.gh-issue-154174.A7mQ2x.rst new file mode 100644 index 000000000000000..74054a1bc2b6075 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-20-04-33-58.gh-issue-154174.A7mQ2x.rst @@ -0,0 +1,2 @@ +Fix :meth:`zipfile.ZipFile.mkdir` failing with an :class:`zipfile.ZipInfo` +that does not already have a ``CRC`` attribute. From dda9791251938c96addef5bdb249e032a3bf6fae Mon Sep 17 00:00:00 2001 From: zhangli091011 Date: Mon, 20 Jul 2026 05:08:43 +0800 Subject: [PATCH 2/5] gh-154174: Avoid optional compression in mkdir test --- Lib/test/test_zipfile/test_core.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Lib/test/test_zipfile/test_core.py b/Lib/test/test_zipfile/test_core.py index b23640a4a0beb5b..e54f5154af542b5 100644 --- a/Lib/test/test_zipfile/test_core.py +++ b/Lib/test/test_zipfile/test_core.py @@ -5484,9 +5484,7 @@ def test_mkdir_zipinfo_preserves_metadata(self): zinfo.compress_size = 2 archive = io.BytesIO() - with zipfile.ZipFile( - archive, "w", zipfile.ZIP_DEFLATED, compresslevel=9 - ) as zf: + with zipfile.ZipFile(archive, "w") as zf: zf.mkdir(zinfo) self.assertEqual(zinfo.compress_level, 1) From fac0cbc8c23ad653cd7377ee759da2d6bd3bf188 Mon Sep 17 00:00:00 2001 From: zhangli091011 Date: Mon, 20 Jul 2026 14:07:38 +0800 Subject: [PATCH 3/5] gh-154174: Refresh PR checks From 5206b20987d6f9980511345970a5dd2cb9355538 Mon Sep 17 00:00:00 2001 From: zhangli091011 Date: Wed, 22 Jul 2026 15:51:50 +0800 Subject: [PATCH 4/5] gh-154174: Remove redundant directory metadata setup --- Lib/zipfile/__init__.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/Lib/zipfile/__init__.py b/Lib/zipfile/__init__.py index 0411d15dcaa45c5..26486a461cae3b3 100644 --- a/Lib/zipfile/__init__.py +++ b/Lib/zipfile/__init__.py @@ -2529,8 +2529,6 @@ def write(self, filename, arcname=None, strict_timestamps=self._strict_timestamps) if zinfo.is_dir(): - zinfo.compress_size = 0 - zinfo.CRC = 0 self.mkdir(zinfo) else: if compress_type is not None: From a1abe58e9c4f2011252a8e2bdef50b0609131a06 Mon Sep 17 00:00:00 2001 From: zhangli091011 Date: Wed, 22 Jul 2026 23:06:02 +0800 Subject: [PATCH 5/5] gh-154174: Normalize directory sizes consistently --- Lib/zipfile/__init__.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Lib/zipfile/__init__.py b/Lib/zipfile/__init__.py index 26486a461cae3b3..03d18cbc1fcf33a 100644 --- a/Lib/zipfile/__init__.py +++ b/Lib/zipfile/__init__.py @@ -2593,9 +2593,7 @@ def mkdir(self, zinfo_or_directory_name, mode=511): else: raise TypeError("Expected type str or ZipInfo") - zinfo.compress_size = 0 - zinfo.CRC = 0 - zinfo.file_size = 0 + zinfo.CRC = zinfo.compress_size = zinfo.file_size = 0 with self._lock: if self._seekable: