Skip to content

🐛 fix(discovery): resolve base interpreter executable-only symlinks#3166

Merged
gaborbernat merged 1 commit into
pypa:mainfrom
gaborbernat:fix/resolve-exe-symlink
Jun 11, 2026
Merged

🐛 fix(discovery): resolve base interpreter executable-only symlinks#3166
gaborbernat merged 1 commit into
pypa:mainfrom
gaborbernat:fix/resolve-exe-symlink

Conversation

@gaborbernat

@gaborbernat gaborbernat commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Creating an environment with -p pointing at a symlink to just the interpreter binary recorded the symlink in pyvenv.cfg: home ended up as the symlink's directory, which contains no lib/, and base-executable kept the unresolved link. 🐛 Standard CPython survives because getpath re-resolves the link when reading home, but layouts where home must directly locate the base stdlib, such as python-build-standalone, produce a broken environment (#3157).

The resolution lives in python-discovery (tox-dev/python-discovery#85, refined by tox-dev/python-discovery#87): system_executable follows the symlink chain of the executable's final path component only, stopping as soon as the stdlib landmark is reachable and never touching macOS framework builds, the same semantics CPython's getpath uses and its venv adopts in python/cpython#115237. A barren-directory symlink resolves to the real interpreter while stable aliases like Homebrew's opt paths, Debian's /usr/bin/python3, or a fully symlinked interpreter tree keep their recorded form. This PR raises the dependency floor to python-discovery>=1.4.2 and bumps the app-data py_info cache key from 4 to 5 so interpreter records probed by older virtualenv versions are not shared with the corrected ones.

CI needs python-discovery 1.4.2 on PyPI (tox-dev/python-discovery#87 merge + release) to go green.

Fixes #3157.

@gaborbernat gaborbernat marked this pull request as draft June 11, 2026 07:19
gaborbernat added a commit to tox-dev/python-discovery that referenced this pull request Jun 11, 2026
Creating a virtual environment through a symlink that points at just the
interpreter binary left `PythonInfo.system_executable` set to the
unresolved symlink. virtualenv derives the `home` and `base-executable`
keys of `pyvenv.cfg` from this value, so the symlink directory got
recorded as the interpreter home even though it contains no `lib/`. 🐛
Layouts where `home` must locate the base interpreter's stdlib, such as
python-build-standalone, end up with a broken environment
(pypa/virtualenv#3157).

The fix ports the `getpath.realpath` semantics that CPython's `venv`
adopts in python/cpython#115237: only the symlink chain of the final
path component gets followed, one `readlink` hop at a time, and every
hop must `samefile` the fully resolved path so that a `normpath` across
a symlinked directory stops the walk. A symlink to the binary alone now
resolves to the real interpreter, while a fully symlinked interpreter
tree keeps its symlinked `home`. The walk runs on POSIX only, matching
CPython's `HAVE_READLINK` gate, and applies to both the non-venv
`original_executable` branch and the venv `sys._base_executable` branch
of `_fast_get_system_executable`.

Cached interpreter records refresh on upgrade because the cache stores
the `_py_info.py` content hash. The companion virtualenv PR
pypa/virtualenv#3166 bumps the dependency floor and its app-data
`py_info` cache key. Fixes #84.
@gaborbernat gaborbernat force-pushed the fix/resolve-exe-symlink branch 2 times, most recently from 83a688d to bffde63 Compare June 11, 2026 16:08
pyvenv.cfg recorded the unresolved symlink in home / base-executable
when the target interpreter was reached through a symlink to just the
binary, breaking layouts where home must locate the stdlib
(python-build-standalone).

python-discovery 1.4.2 resolves such symlinks for system_executable,
mirroring CPython getpath (python/cpython#115237) including its
stdlib-landmark stop, so stable aliases like Homebrew's opt paths or
Debian's /usr/bin/python3 stay untouched. Bump the dependency floor
and the app-data py_info cache key so records probed with older
versions are not shared.

Fixes pypa#3157.
@gaborbernat gaborbernat force-pushed the fix/resolve-exe-symlink branch from bffde63 to 0040723 Compare June 11, 2026 16:11
@gaborbernat gaborbernat marked this pull request as ready for review June 11, 2026 16:43
@gaborbernat gaborbernat merged commit 2a36128 into pypa:main Jun 11, 2026
57 of 58 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Base interpreter symlink not resolved in pyvenv.cfg (home / base-executable record the symlink)

1 participant