Skip to content

Commit fbebdb7

Browse files
committed
bpo-29708: allow to force hash-based pycs
using the well-established SOURCE_DATE_EPOCH environment variable to allow for reproducible builds of python packages. See https://reproducible-builds.org/ for why this is good.
1 parent 94e1696 commit fbebdb7

File tree

4 files changed

+20
-1
lines changed

4 files changed

+20
-1
lines changed

Doc/library/py_compile.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ byte-code cache files in the directory containing the source code.
5555

5656
*invalidation_mode* should be a member of the :class:`PycInvalidationMode`
5757
enum and controls how the generated ``.pyc`` files are invalidated at
58-
runtime.
58+
runtime. If the :envvar:`SOURCE_DATE_EPOCH` environment variable is set,
59+
*invalidation_mode* will be forced to `CHECKED_HASH`.
5960

6061
.. versionchanged:: 3.2
6162
Changed default value of *cfile* to be :PEP:`3147`-compliant. Previous
@@ -71,6 +72,8 @@ byte-code cache files in the directory containing the source code.
7172

7273
.. versionchanged:: 3.7
7374
The *invalidation_mode* parameter was added as specified in :pep:`552`.
75+
If the :envvar:`SOURCE_DATE_EPOCH` environment variable is set, this will
76+
be forced to `CHECKED_HASH`.
7477

7578

7679
.. class:: PycInvalidationMode

Lib/py_compile.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ def compile(file, cfile=None, dfile=None, doraise=False, optimize=-1,
112112
the resulting file would be regular and thus not the same type of file as
113113
it was previously.
114114
"""
115+
if os.environ.get('SOURCE_DATE_EPOCH'):
116+
invalidation_mode = PycInvalidationMode.CHECKED_HASH
115117
if cfile is None:
116118
if optimize >= 0:
117119
optimization = optimize if optimize >= 1 else ''

Lib/test/test_py_compile.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,18 @@ def test_bad_coding(self):
9898
self.assertFalse(os.path.exists(
9999
importlib.util.cache_from_source(bad_coding)))
100100

101+
def test_source_date_epoch(self):
102+
testtime = 123456789
103+
with support.EnvironmentVarGuard() as env:
104+
env["SOURCE_DATE_EPOCH"] = str(testtime)
105+
py_compile.compile(self.source_path, self.pyc_path)
106+
self.assertTrue(os.path.exists(self.pyc_path))
107+
self.assertFalse(os.path.exists(self.cache_path))
108+
with open(self.pyc_path, 'rb') as fp:
109+
flags = importlib._bootstrap_external._classify_pyc(
110+
fp.read(), 'test', {})
111+
self.assertEqual(flags, 0b11)
112+
101113
@unittest.skipIf(sys.flags.optimize > 0, 'test does not work with -O')
102114
def test_double_dot_no_clobber(self):
103115
# http://bugs.python.org/issue22966
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
If the :envvar:`SOURCE_DATE_EPOCH` environment variable is set,
2+
py_compile will always create hash-based .pyc files.

0 commit comments

Comments
 (0)