🐛 fix(discovery): resolve base interpreter executable-only symlinks#3166
Merged
Conversation
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.
83a688d to
bffde63
Compare
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.
bffde63 to
0040723
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Creating an environment with
-ppointing at a symlink to just the interpreter binary recorded the symlink inpyvenv.cfg:homeended up as the symlink's directory, which contains nolib/, andbase-executablekept the unresolved link. 🐛 Standard CPython survives becausegetpathre-resolves the link when readinghome, but layouts wherehomemust 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_executablefollows 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'sgetpathuses and itsvenvadopts in python/cpython#115237. A barren-directory symlink resolves to the real interpreter while stable aliases like Homebrew'soptpaths, Debian's/usr/bin/python3, or a fully symlinked interpreter tree keep their recorded form. This PR raises the dependency floor topython-discovery>=1.4.2and bumps the app-datapy_infocache key from4to5so interpreter records probed by older virtualenv versions are not shared with the corrected ones.CI needs python-discovery
1.4.2on PyPI (tox-dev/python-discovery#87 merge + release) to go green.Fixes #3157.