Skip to content

site: .pth import lines can no longer read the 'fullname' local variable #156404

Description

@arcivanov

Bug report

Python 3.15 implements PEP 829 and moved .pth handling out of site.addpackage() into site.StartupState._exec_imports(). import lines in .pth files are still exec()'d, but now from a different frame, and the local variable holding the path of the .pth file being processed was renamed from fullname to filename. Any .pth file generated before 3.15 that reads fullname now raises NameError on every interpreter startup.

Reproducer

import os, site, tempfile

with tempfile.TemporaryDirectory() as d:
    with open(os.path.join(d, "foo.pth"), "w") as f:
        f.write("import sys; print(fullname)\n")
    site.addpackage(d, "foo.pth", set())

On 3.14 this prints the path of the .pth file. On 3.15 and on main:

Error in import line from /tmp/tmp3kbbbxtg/foo.pth: import sys; print(fullname)
  Traceback (most recent call last):
    File "Lib/site.py", line 533, in _exec_imports
      exec(line)
      ~~~~^^^^^^
    File "<string>", line 1, in <module>
  NameError: name 'fullname' is not defined. Did you mean: 'filename'?

Real-world impact

Every wheel built by wheel-axle before 0.0.13 installs a .pth file containing import wheel_axle.runtime; wheel_axle.runtime.finalize(fullname);, and there are published wheels in the wild carrying that line. The interpreter still starts, because site prints the traceback and continues, but the post-install hook never runs, so the symlinks the wheel declares are never created, and the error is printed again on every single startup because the .pth is never consumed. Downstream tracking issue: karellen/wheel-axle#38

PEP 829 keeps executing .pth import lines through 3.17, so this is not a case where the old mechanism has been retired. The lines still run; they just run against a frame that no longer exposes the name they were written against.

Suggested fix

This is the same class of regression as gh-149671, fixed in f7ab7c4 by injecting the sitedir local into _exec_imports() for compatibility with the -nspkg.pth files generated by setuptools. fullname needs identical treatment, immediately below the existing sitedir shim:

# 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

I have this working locally against 3.15 with a regression test alongside test_sitedir_variable, and will open a PR.

Your environment

  • CPython versions tested on: 3.15 (v3.15.0rc1-86-gd0484ab51a7), main
  • Operating system and architecture: Linux x86-64

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.15pre-release feature fixes, bugs and security fixesstdlibStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions