https://github.com/python/cpython/commit/c56ce5a870713b1623eb5db3f63826fc860f461e
commit: c56ce5a870713b1623eb5db3f63826fc860f461e
branch: 3.15
author: Stan Ulbrych <[email protected]>
committer: hugovk <[email protected]>
date: 2026-08-07T20:32:27+03:00
summary:
[3.15] gh-154948: Fix `test_zipfile` failure when `SOURCE_DATE_EPOCH` is set
(GH-155001) (#155347)
files:
M Doc/library/test.rst
M Lib/test/support/os_helper.py
M Lib/test/test_compileall.py
M Lib/test/test_importlib/source/test_file_loader.py
M Lib/test/test_py_compile.py
M Lib/test/test_regrtest.py
M Lib/test/test_zipfile/test_core.py
diff --git a/Doc/library/test.rst b/Doc/library/test.rst
index 660847ae3fe3c85..54839166e912493 100644
--- a/Doc/library/test.rst
+++ b/Doc/library/test.rst
@@ -1643,6 +1643,32 @@ The :mod:`!test.support.os_helper` module provides
support for os tests.
wrapped with a wait loop that checks for the existence of the file.
+.. decorator:: with_source_date_epoch(*, epoch=123456789)
+
+ A decorator for running tests with the :envvar:`SOURCE_DATE_EPOCH`
+ environment variable set to *epoch*.
+
+
+.. decorator:: without_source_date_epoch
+
+ A decorator for running tests with the :envvar:`SOURCE_DATE_EPOCH`
+ environment variable unset.
+
+
+.. class:: SourceDateEpochTestMeta
+
+ Metaclass wrapping all test methods of the class with
+ :func:`with_source_date_epoch` if the *source_date_epoch* keyword class
+ argument is true, or with :func:`without_source_date_epoch` otherwise.
+ For example::
+
+ class TestsWithSourceEpoch(Tests,
+ metaclass=SourceDateEpochTestMeta,
+ source_date_epoch=True):
+ pass
+
+
+
:mod:`!test.support.import_helper` --- Utilities for import tests
=================================================================
diff --git a/Lib/test/support/os_helper.py b/Lib/test/support/os_helper.py
index daf6060940e97f0..e1e2e69cb3d8334 100644
--- a/Lib/test/support/os_helper.py
+++ b/Lib/test/support/os_helper.py
@@ -1,6 +1,7 @@
import collections.abc
import contextlib
import errno
+import functools
import logging
import os
import re
@@ -806,6 +807,48 @@ def __exit__(self, *ignore_exc):
os.environ = self._environ
+def without_source_date_epoch(fxn):
+ """Runs function with SOURCE_DATE_EPOCH unset."""
+ @functools.wraps(fxn)
+ def wrapper(*args, **kwargs):
+ with EnvironmentVarGuard() as env:
+ env.unset('SOURCE_DATE_EPOCH')
+ return fxn(*args, **kwargs)
+ return wrapper
+
+
+_MISSING = sentinel("MISSING")
+
+def with_source_date_epoch(fxn=_MISSING, *, epoch=123456789):
+ """Runs function with SOURCE_DATE_EPOCH set to *epoch*."""
+ if fxn is _MISSING:
+ return functools.partial(with_source_date_epoch, epoch=epoch)
+
+ @functools.wraps(fxn)
+ def wrapper(*args, **kwargs):
+ with EnvironmentVarGuard() as env:
+ env['SOURCE_DATE_EPOCH'] = str(epoch)
+ return fxn(*args, **kwargs)
+ return wrapper
+
+
+# Run tests with SOURCE_DATE_EPOCH set or unset explicitly.
+class SourceDateEpochTestMeta(type(unittest.TestCase)):
+ def __new__(mcls, name, bases, dct, *, source_date_epoch):
+ cls = super().__new__(mcls, name, bases, dct)
+
+ for attr in dir(cls):
+ if attr.startswith('test_'):
+ meth = getattr(cls, attr)
+ if source_date_epoch:
+ wrapper = with_source_date_epoch(meth)
+ else:
+ wrapper = without_source_date_epoch(meth)
+ setattr(cls, attr, wrapper)
+
+ return cls
+
+
try:
if support.MS_WINDOWS:
import ctypes
diff --git a/Lib/test/test_compileall.py b/Lib/test/test_compileall.py
index 95dcb4ef9fdc202..9a6ca2be1624c6c 100644
--- a/Lib/test/test_compileall.py
+++ b/Lib/test/test_compileall.py
@@ -28,8 +28,8 @@
from test import support
from test.support import os_helper
from test.support import script_helper
-from test.test_py_compile import without_source_date_epoch
-from test.test_py_compile import SourceDateEpochTestMeta
+from test.support.os_helper import without_source_date_epoch
+from test.support.os_helper import SourceDateEpochTestMeta
from test.support.os_helper import FakePath
diff --git a/Lib/test/test_importlib/source/test_file_loader.py
b/Lib/test/test_importlib/source/test_file_loader.py
index e4bd850f3514ff1..ca2cc045fa674e1 100644
--- a/Lib/test/test_importlib/source/test_file_loader.py
+++ b/Lib/test/test_importlib/source/test_file_loader.py
@@ -5,21 +5,18 @@
machinery = util.import_importlib('importlib.machinery')
importlib_util = util.import_importlib('importlib.util')
-import errno
import marshal
import os
import py_compile
-import shutil
import stat
import sys
import types
import unittest
-import warnings
-from test.support.import_helper import make_legacy_pyc, unload
+from test.support.import_helper import make_legacy_pyc
-from test.test_py_compile import without_source_date_epoch
-from test.test_py_compile import SourceDateEpochTestMeta
+from test.support.os_helper import without_source_date_epoch
+from test.support.os_helper import SourceDateEpochTestMeta
class SimpleTest:
diff --git a/Lib/test/test_py_compile.py b/Lib/test/test_py_compile.py
index d8acd1f04356e7b..081fd0cf3945e02 100644
--- a/Lib/test/test_py_compile.py
+++ b/Lib/test/test_py_compile.py
@@ -1,4 +1,3 @@
-import functools
import importlib.util
import os
import py_compile
@@ -11,43 +10,7 @@
from test import support
from test.support import os_helper, script_helper
-
-
-def without_source_date_epoch(fxn):
- """Runs function with SOURCE_DATE_EPOCH unset."""
- @functools.wraps(fxn)
- def wrapper(*args, **kwargs):
- with os_helper.EnvironmentVarGuard() as env:
- env.unset('SOURCE_DATE_EPOCH')
- return fxn(*args, **kwargs)
- return wrapper
-
-
-def with_source_date_epoch(fxn):
- """Runs function with SOURCE_DATE_EPOCH set."""
- @functools.wraps(fxn)
- def wrapper(*args, **kwargs):
- with os_helper.EnvironmentVarGuard() as env:
- env['SOURCE_DATE_EPOCH'] = '123456789'
- return fxn(*args, **kwargs)
- return wrapper
-
-
-# Run tests with SOURCE_DATE_EPOCH set or unset explicitly.
-class SourceDateEpochTestMeta(type(unittest.TestCase)):
- def __new__(mcls, name, bases, dct, *, source_date_epoch):
- cls = super().__new__(mcls, name, bases, dct)
-
- for attr in dir(cls):
- if attr.startswith('test_'):
- meth = getattr(cls, attr)
- if source_date_epoch:
- wrapper = with_source_date_epoch(meth)
- else:
- wrapper = without_source_date_epoch(meth)
- setattr(cls, attr, wrapper)
-
- return cls
+from test.support.os_helper import SourceDateEpochTestMeta
class PyCompileTestsBase:
diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py
index 874c6bb76b1afe5..554b1a8ad2c5bb6 100644
--- a/Lib/test/test_regrtest.py
+++ b/Lib/test/test_regrtest.py
@@ -166,21 +166,20 @@ def test_randomize(self):
ns = self.parse_args([opt])
self.assertTrue(ns.randomize)
- with os_helper.EnvironmentVarGuard() as env:
- # with SOURCE_DATE_EPOCH
- env['SOURCE_DATE_EPOCH'] = '1697839080'
- ns = self.parse_args(['--randomize'])
- regrtest = main.Regrtest(ns)
- self.assertFalse(regrtest.randomize)
- self.assertIsInstance(regrtest.random_seed, str)
- self.assertEqual(regrtest.random_seed, '1697839080')
-
- # without SOURCE_DATE_EPOCH
- del env['SOURCE_DATE_EPOCH']
- ns = self.parse_args(['--randomize'])
- regrtest = main.Regrtest(ns)
- self.assertTrue(regrtest.randomize)
- self.assertIsInstance(regrtest.random_seed, int)
+ @os_helper.with_source_date_epoch(epoch=1697839080)
+ def test_randomize_with_source_date_epoch(self):
+ ns = self.parse_args(['--randomize'])
+ regrtest = main.Regrtest(ns)
+ self.assertFalse(regrtest.randomize)
+ self.assertIsInstance(regrtest.random_seed, str)
+ self.assertEqual(regrtest.random_seed, '1697839080')
+
+ @os_helper.without_source_date_epoch
+ def test_randomize_without_source_date_epoch(self):
+ ns = self.parse_args(['--randomize'])
+ regrtest = main.Regrtest(ns)
+ self.assertTrue(regrtest.randomize)
+ self.assertIsInstance(regrtest.random_seed, int)
def test_no_randomize(self):
ns = self.parse_args([])
diff --git a/Lib/test/test_zipfile/test_core.py
b/Lib/test/test_zipfile/test_core.py
index 85bc010fe007841..feec688726a8038 100644
--- a/Lib/test/test_zipfile/test_core.py
+++ b/Lib/test/test_zipfile/test_core.py
@@ -21,14 +21,15 @@
from random import randint, random, randbytes
from test import archiver_tests
-from test.support import script_helper, os_helper
+from test.support import script_helper
from test.support import (
findfile, requires_zlib, requires_bz2, requires_lzma,
requires_zstd, captured_stdout, captured_stderr, requires_subprocess,
cpython_only
)
from test.support.os_helper import (
- TESTFN, unlink, rmtree, temp_dir, temp_cwd, fd_count, FakePath
+ TESTFN, unlink, rmtree, temp_dir, temp_cwd, fd_count, FakePath,
+ with_source_date_epoch, without_source_date_epoch,
)
from test.support.import_helper import ensure_lazy_imports
@@ -1883,29 +1884,24 @@ 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)
+ @with_source_date_epoch(epoch=1735715999)
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, "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")
- expected_utc = (2025, 1, 1, 7, 19, 58)
- self.assertEqual(zip_info.date_time, expected_utc)
+ with zipfile.ZipFile(TESTFN, "r") as zf:
+ zip_info = zf.getinfo("test_source_date_epoch.txt")
+ expected_utc = (2025, 1, 1, 7, 19, 58)
+ self.assertEqual(zip_info.date_time, expected_utc)
+ @without_source_date_epoch
def test_write_without_source_date_epoch(self):
- with os_helper.EnvironmentVarGuard() as env:
- del env['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, "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")
- self.assertTimestampAlmostEqual(time.localtime(),
zip_info.date_time, tolerance=2)
+ with zipfile.ZipFile(TESTFN, "r") as zf:
+ zip_info = zf.getinfo("test_no_source_date_epoch.txt")
+ self.assertTimestampAlmostEqual(time.localtime(),
zip_info.date_time, tolerance=2)
def assertTimestampAlmostEqual(self, time1, time2, tolerance):
import datetime
_______________________________________________
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]