From 6099a54dddbfbc7fb912d53b6adad5ff6b8d1745 Mon Sep 17 00:00:00 2001 From: Richard Si Date: Fri, 5 Jun 2026 15:03:38 -0400 Subject: [PATCH] Fix sitecustomize.py used for build isolation on Python 3.15+ The sitecustomize.py file pip uses to isolate build subprocesses from the parent environment discovers system related paths by calling site.addsitedir() for every system site-packages path and observing what new entries are appended to sys.path. This breaks since Python 3.15b2 due to two changes: - site.addsitedir() won't add a path if it already exists in sys.path - site.addsitedir() won't re-execute .pth files if called for a known directory (which includes the system sites because known_path is mutated by addsitedir before it checks for .pth files) To cope with this, temporarily clear sys.path before using site.addsitedir() to discover all system paths for exclusion. --- news/14033.bugfix.rst | 1 + src/pip/_internal/build_env.py | 14 +++++++++----- 2 files changed, 10 insertions(+), 5 deletions(-) create mode 100644 news/14033.bugfix.rst diff --git a/news/14033.bugfix.rst b/news/14033.bugfix.rst new file mode 100644 index 0000000000..404196a2f0 --- /dev/null +++ b/news/14033.bugfix.rst @@ -0,0 +1 @@ +Prevent system packages from leaking into isolated build environments on Python 3.15 diff --git a/src/pip/_internal/build_env.py b/src/pip/_internal/build_env.py index 1a42a9d411..7639dabcad 100644 --- a/src/pip/_internal/build_env.py +++ b/src/pip/_internal/build_env.py @@ -468,15 +468,19 @@ def __init__(self, installer: BuildEnvironmentInstaller) -> None: """ import os, site, sys - # First, drop system-sites related paths. + # First, discover all system-sites related paths. original_sys_path = sys.path[:] + # Clear sys.path so addsitedir() will add system site paths and paths + # added by contained .pth files to sys.path reliably. This is necessary + # since Python 3.15, which notably no longer re-executes .pth files for + # known paths. + sys.path = [] known_paths = set() for path in {system_sites!r}: site.addsitedir(path, known_paths=known_paths) - system_paths = set( - os.path.normcase(path) - for path in sys.path[len(original_sys_path):] - ) + system_paths = set(os.path.normcase(path) for path in sys.path) + + # Drop discovered system-sites related paths. original_sys_path = [ path for path in original_sys_path if os.path.normcase(path) not in system_paths