https://github.com/python/cpython/commit/5d57959d7da8cfcef8df072a6ad53795c60546aa
commit: 5d57959d7da8cfcef8df072a6ad53795c60546aa
branch: main
author: Wulian <[email protected]>
committer: jaraco <[email protected]>
date: 2025-01-20T13:12:29-05:00
summary:
gh-91279: ZipFile.writestr now respect SOURCE_DATE_EPOCH (#124435)
files:
A Misc/NEWS.d/next/Library/2024-12-30-19-53-14.gh-issue-91279.EeOJk1.rst
M Doc/whatsnew/3.14.rst
M Lib/test/test_zipfile/test_core.py
M Lib/zipfile/__init__.py
diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst
index 7f149d5c03dfbb..0dcecd4944f2f6 100644
--- a/Doc/whatsnew/3.14.rst
+++ b/Doc/whatsnew/3.14.rst
@@ -730,6 +730,12 @@ zipinfo
(Contributed by Bénédikt Tran in :gh:`123424`.)
+* :meth:`zipfile.ZipFile.writestr` now respect ``SOURCE_DATE_EPOCH`` that
+ distributions can set centrally and have build tools consume this in order
+ to produce reproducible output.
+
+ (Contributed by Jiahao Li in :gh:`91279`.)
+
.. Add improved modules above alphabetically, not here at the end.
Optimizations
diff --git a/Lib/test/test_zipfile/test_core.py
b/Lib/test/test_zipfile/test_core.py
index 02e28d4004c01a..ab5fb650084327 100644
--- a/Lib/test/test_zipfile/test_core.py
+++ b/Lib/test/test_zipfile/test_core.py
@@ -20,7 +20,7 @@
from random import randint, random, randbytes
from test import archiver_tests
-from test.support import script_helper
+from test.support import script_helper, os_helper
from test.support import (
findfile, requires_zlib, requires_bz2, requires_lzma,
captured_stdout, captured_stderr, requires_subprocess,
@@ -1784,6 +1784,35 @@ def test_writestr_extended_local_header_issue1202(self):
zinfo.flag_bits |= zipfile._MASK_USE_DATA_DESCRIPTOR #
Include an extended local header.
orig_zip.writestr(zinfo, data)
+ def test_write_with_source_date_epoch(self):
+ with os_helper.EnvironmentVarGuard() as env:
+ # Set the SOURCE_DATE_EPOCH environment variable to a specific
timestamp
+ env['SOURCE_DATE_EPOCH'] = "1735715999"
+
+ with zipfile.ZipFile(TESTFN, "w") as zf:
+ zf.writestr("test_source_date_epoch.txt", "Testing
SOURCE_DATE_EPOCH")
+
+ with zipfile.ZipFile(TESTFN, "r") as zf:
+ zip_info = zf.getinfo("test_source_date_epoch.txt")
+ get_time =
time.localtime(int(os.environ['SOURCE_DATE_EPOCH']))[:6]
+ # Compare each element of the date_time tuple
+ # Allow for a 1-second difference
+ for z_time, g_time in zip(zip_info.date_time, get_time):
+ self.assertAlmostEqual(z_time, g_time, delta=1)
+
+ def test_write_without_source_date_epoch(self):
+ if 'SOURCE_DATE_EPOCH' in os.environ:
+ del os.environ['SOURCE_DATE_EPOCH']
+
+ with zipfile.ZipFile(TESTFN, "w") as zf:
+ zf.writestr("test_no_source_date_epoch.txt", "Testing without
SOURCE_DATE_EPOCH")
+
+ with zipfile.ZipFile(TESTFN, "r") as zf:
+ zip_info = zf.getinfo("test_no_source_date_epoch.txt")
+ current_time = time.localtime()[:6]
+ for z_time, c_time in zip(zip_info.date_time, current_time):
+ self.assertAlmostEqual(z_time, c_time, delta=1)
+
def test_close(self):
"""Check that the zipfile is closed after the 'with' block."""
with zipfile.ZipFile(TESTFN2, "w") as zipfp:
diff --git a/Lib/zipfile/__init__.py b/Lib/zipfile/__init__.py
index 24531c1c2b7804..49c40032d848f1 100644
--- a/Lib/zipfile/__init__.py
+++ b/Lib/zipfile/__init__.py
@@ -614,7 +614,11 @@ def _for_archive(self, archive: ZipFile) -> Self:
Return self.
"""
- self.date_time = time.localtime(time.time())[:6]
+ # gh-91279: Set the SOURCE_DATE_EPOCH to a specific timestamp
+ epoch = os.environ.get('SOURCE_DATE_EPOCH')
+ get_time = int(epoch) if epoch else time.time()
+ self.date_time = time.localtime(get_time)[:6]
+
self.compress_type = archive.compression
self.compress_level = archive.compresslevel
if self.filename.endswith('/'): # pragma: no cover
diff --git
a/Misc/NEWS.d/next/Library/2024-12-30-19-53-14.gh-issue-91279.EeOJk1.rst
b/Misc/NEWS.d/next/Library/2024-12-30-19-53-14.gh-issue-91279.EeOJk1.rst
new file mode 100644
index 00000000000000..30ee2ea5efd069
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-12-30-19-53-14.gh-issue-91279.EeOJk1.rst
@@ -0,0 +1,3 @@
+:meth:`zipfile.ZipFile.writestr` now respect ``SOURCE_DATE_EPOCH`` that
+distributions can set centrally and have build tools consume this in order
+to produce reproducible output.
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]