🐛 fix(discovery): resolve version-manager shims to real binaries#3067
Merged
Conversation
When pyenv/mise/asdf shims are found on PATH and interrogated as subprocesses, they may resolve to the system Python instead of the version-manager-managed binary. This happens because the shim's delegation mechanism can behave differently in subprocess contexts than in an interactive shell. Bypass shims entirely by reading .python-version files (a convention shared across pyenv, mise, and asdf) and locating the real binary directly under the version manager's install directory. The resolution checks PYENV_VERSION env var, .python-version files searching up from cwd, and the global version file, matching the same priority order these tools use natively. Closes pypa#3049
for more information, see https://pre-commit.ci
Cover shim resolution across all four Diataxis dimensions: explain the problem and resolution mechanism, add a how-to for pyenv/mise/asdf users, list version managers in compatibility reference, and mention them in the tutorial prerequisites. Add a changelog fragment for the feature.
for more information, see https://pre-commit.ci
Shim tests using python3.x specs failed on CI runners where the system Python matched the spec, causing get_interpreter to return early via PythonInfo.current_system() before reaching PATH/shim scanning. Using python2.7 as the spec avoids this entirely since no CI runner has Python 2.7 installed, so discovery always falls through to PATH scanning where the shim resolution logic is exercised. This replaces the previous approach of mocking PythonInfo.current_system() which was fragile and didn't replicate real version manager behavior.
This was referenced Mar 16, 2026
This was referenced Mar 18, 2026
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.
Version managers like pyenv, mise, and asdf place shim scripts on
PATHthat delegate to the real Python binary. When virtualenv interrogates these shims as subprocesses during discovery, they can resolve to the system Python instead of the version-manager-managed binary. This happens because the shim's delegation mechanism may behave differently in a subprocess context than in an interactive shell — resulting in users getting the wrong Python version in their virtualenv. 🐛The fix bypasses shims entirely during PATH discovery by reading
.python-versionfiles (a convention shared across pyenv, mise, and asdf) and locating the real binary directly under the version manager's install directory. Resolution follows the same priority order these tools use natively:PYENV_VERSIONenv var, then.python-versionfile searching parent directories from cwd, then the global version file. The version-manager layouts are defined in a data-driven table (PYENV_ROOT/versions/,MISE_DATA_DIR/installs/python/,ASDF_DATA_DIR/installs/python/) making it straightforward to extend for other managers. No subprocess calls to version-manager CLIs are made — only file reads and env var checks.When no version-manager environment is detected (no
PYENV_ROOT,MISE_DATA_DIR, orASDF_DATA_DIRset), the resolution is skipped entirely with no overhead. If the shim can't be resolved (version not installed, binary missing), discovery falls through to the normal subprocess interrogation path.Closes #3049