Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions _distutils_hack/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,12 @@ def frame_file_is_setup(frame):
"""
Return True if the indicated frame suggests a setup.py file.
"""
# some frames may not have __file__ (#2940)
return frame.f_globals.get('__file__', '').endswith('setup.py')
# some frames may not have __file__ (#2940);
# on Python 3.14+ __file__ may also be present but None, which would
# crash on the default-value fallback. Treat None and non-strings the
# same as missing. #5263
filename = frame.f_globals.get('__file__')
return isinstance(filename, str) and filename.endswith('setup.py')

def spec_for_sensitive_tests(self):
"""
Expand Down
1 change: 1 addition & 0 deletions newsfragments/5263.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Guard against __file__ being None in _distutils_hack's frame detector so pip startup no longer crashes on Python 3.14 when a frame's globals carry a None __file__.
26 changes: 26 additions & 0 deletions setuptools/tests/test_distutils_adoption.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,32 @@ def test_pip_import(venv):
venv.run(cmd, **_TEXT_KWARGS)


def test_frame_file_is_setup_handles_missing_file():
"""
_distutils_hack.DistutilsMetaFinder.frame_file_is_setup should tolerate
frames whose f_globals does not have __file__ (#2940) or has __file__ set
to None, which can happen on Python 3.14+ during pip startup. #5263
"""
from _distutils_hack import DistutilsMetaFinder

class Frame:
def __init__(self, filename):
self._globals = {"__file__": filename}

@property
def f_globals(self):
return self._globals

# Missing __file__: treated as not a setup.py
assert not DistutilsMetaFinder.frame_file_is_setup(Frame("MISSING"))
# __file__ is None (Python 3.14+ can land here): no crash, treated as not setup.py
assert not DistutilsMetaFinder.frame_file_is_setup(Frame(None))
# __file__ ends with setup.py: still detected
assert DistutilsMetaFinder.frame_file_is_setup(Frame("/some/dir/setup.py"))
# __file__ is something else: not a setup.py
assert not DistutilsMetaFinder.frame_file_is_setup(Frame("/some/dir/main.py"))


def test_distutils_has_origin():
"""
Distutils module spec should have an origin. #2990.
Expand Down