https://github.com/python/cpython/commit/7f3d09b6e8018c3710dfde9f71c63d47a047beb1 commit: 7f3d09b6e8018c3710dfde9f71c63d47a047beb1 branch: main author: Arcadiy Ivanov <[email protected]> committer: warsaw <[email protected]> date: 2026-08-26T20:45:52Z summary:
gh-156404: Restore the 'fullname' variable for .pth import lines (#156406) PEP 829 moved .pth handling from site.addpackage() into StartupState._exec_imports(), and the local holding the path of the .pth file being processed was renamed from 'fullname' to 'filename'. Import lines in .pth files generated before Python 3.15 read that local, so they now fail with NameError on every interpreter startup. Inject 'fullname' into the frame which executes pth code, next to the 'sitedir' shim added for gh-149671. Reported downstream as https://github.com/karellen/wheel-axle/issues/38 Co-authored-by: Barry Warsaw <[email protected]> files: A Misc/NEWS.d/next/Library/2026-08-26-08-20-07.gh-issue-156404.2gP33I.rst M Lib/site.py M Lib/test/test_site.py diff --git a/Lib/site.py b/Lib/site.py index 873c562d890a3b..294a4d6f641c39 100644 --- a/Lib/site.py +++ b/Lib/site.py @@ -510,6 +510,12 @@ def _exec_imports(self): # generated by setuptools use: sys._getframe(1).f_locals['sitedir']. sitedir = os.path.dirname(filename) + # Inject 'fullname' local variable in the current frame for + # compatibility with Python 3.14, where the path of the ".pth" + # file being processed was available to import lines under that + # name. + fullname = filename + # Given "/path/to/foo.pth", check whether "/path/to/foo.start" was # registered in this same batch. name, dot, pth = filename.rpartition(".") diff --git a/Lib/test/test_site.py b/Lib/test/test_site.py index bcb51ed7d8476a..fc5e6369eacaad 100644 --- a/Lib/test/test_site.py +++ b/Lib/test/test_site.py @@ -247,6 +247,23 @@ def test_sitedir_variable(self): sitedir = stdout.getvalue().rstrip() self.assertEqual(sitedir, pth_dir) + def test_fullname_variable(self): + # gh-156404: ".pth" files generated before Python 3.15 read the path + # of the file being processed from the frame executing the import + # line, under the name "fullname". For example, "wheel-axle" + # generates: "import wheel_axle.runtime; + # wheel_axle.runtime.finalize(fullname);" + code = '; '.join(( + "import sys", + "print(fullname)", + "print(filename)", + )) + pth_dir, pth_fn = self.make_pth(code) + with support.captured_stdout() as stdout: + site.addpackage(pth_dir, pth_fn, set()) + expected = os.path.join(pth_dir, pth_fn) + self.assertEqual(stdout.getvalue().splitlines(), [expected, expected]) + # This tests _getuserbase, hence the double underline # to distinguish from a test for getuserbase def test__getuserbase(self): diff --git a/Misc/NEWS.d/next/Library/2026-08-26-08-20-07.gh-issue-156404.2gP33I.rst b/Misc/NEWS.d/next/Library/2026-08-26-08-20-07.gh-issue-156404.2gP33I.rst new file mode 100644 index 00000000000000..475d09c764aa3b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-08-26-08-20-07.gh-issue-156404.2gP33I.rst @@ -0,0 +1,3 @@ +Restore compatibility with :file:`.pth` files generated before Python 3.15 in +the :mod:`site` module. Inject the ``fullname`` variable in the frame which +executes pth code. _______________________________________________ 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]
