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
9 changes: 9 additions & 0 deletions Lib/site.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ class StartupState:
'_path_entries',
'_importexecs',
'_entrypoints',
'_sitedir',
)

def __init__(self, known_paths=None):
Expand Down Expand Up @@ -286,6 +287,7 @@ def __init__(self, known_paths=None):
# when an entry fails.
self._importexecs = {}
self._entrypoints = {}
self._sitedir = None

def addsitedir(self, sitedir):
"""Add a site directory and accumulate its .pth and .start startup data.
Expand Down Expand Up @@ -397,6 +399,8 @@ def _read_pth_file(self, sitedir, name):
accepted paths are added to it so that subsequent .pth files in
the same batch don't add them more than once.
"""
self._sitedir = sitedir

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If adding an attribute is a blocker issue, Petr suggested to recreate sitedir from the PTH filename: #149671 (comment).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using an attribute is problematic for two reasons:

  • Most importantly, multiple calls to StartupState.addsitedir() will overwrite the previous value so there's probably a re-entrancy problem with this approach.
  • It doesn't means when we rip out import line support we'll have to make changes in more than one place, and by that time, we may not remember why we added self._sitedir in the first place (or, clients will come to depend on it even though it's non-public).

@encukou approach is less yucky.


lines, filename = _read_pthstart_file(sitedir, name, ".pth")
if lines is None:
return
Expand Down Expand Up @@ -500,6 +504,11 @@ def _extend_syspath(self):
)

def _exec_imports(self):
# Inject 'sitedir' local variable in the current frame for
# compatibility with Python 3.14. Especially, "-nspkg.pth" files
# generated by setuptools use: sys._getframe(1).f_locals['sitedir'].
sitedir = self._sitedir

# For each `import` line we've seen in a .pth file, exec() it in
# order, unless the .pth has a matching .start file in this same
# batch. In that case, PEP 829 says the import lines are
Expand Down
15 changes: 15 additions & 0 deletions Lib/test/test_site.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,21 @@ def test_addsitedir_hidden_file_attribute(self):
self.assertNotIn(site.makepath(pth_file.good_dir_path)[0], sys.path)
self.assertIn(pth_file.base_dir, sys.path)

def test_sitedir_variable(self):
# gh-149671: Provide 'sitedir' local variable for compatibility with
# Python 3.14

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Python 3.14
# setuptools use of `-nspkg.pth` files in Python < 3.15.

And please add a link to the setuptools issue where they are going to remove these .pth files.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably a re-entrancy problem

or maybe not, but I still prefer the approach without the added attribute.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And please add a link to the setuptools issue where they are going to remove these .pth files.

I don't think there is such an issue.

code = '; '.join((
"import sys",
# Code used by "-nspkg.pth" files generated by setuptools

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Code used by "-nspkg.pth" files generated by setuptools
# Code used by "-nspkg.pth" files generated by setuptools.

Probably move this comment to just above line 239, since it applies to the whole statement.

Also, test_site.py tends to use dedented triple-quote-strings for stuff like this, but maybe that line will end up being too long anyway since this must end up on the same line in the .pth file. It just always makes me nervous to see string joins with trailing commas because missing commas leads to bugs. Use your discretion.

"sitedir = sys._getframe(1).f_locals['sitedir']",
"print(sitedir)",
))
pth_dir, pth_fn = self.make_pth(code)
with support.captured_stdout() as stdout:
known_paths = site.addpackage(pth_dir, pth_fn, set())
sitedir = stdout.getvalue().rstrip()
self.assertEqual(sitedir, pth_dir)

# This tests _getuserbase, hence the double underline
# to distinguish from a test for getuserbase
def test__getuserbase(self):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Restore compatibility with setuptools ``nspkg.pth`` files in the :mod:`site`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Restore compatibility with setuptools ``nspkg.pth`` files in the :mod:`site`
Restore compatibility with setuptools ``-nspkg.pth`` files in the :mod:`site`

module. Inject ``sitedir`` variable in the frame which executes pth code.
Patch by Victor Stinner.
Loading