Repository navigation
fix(python): honour --tool when creating a venv - #11567
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Central YAML (base), Organization UI (inherited) Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
🚧 Files skipped from review as they are similar to previous changes (4)
📝 WalkthroughWalkthroughThe change passes the active ChangesPython venv tool override
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant CLI
participant load_post_env
participant EnvResults.resolve_with_toolset
participant PythonVenv
CLI->>load_post_env: select Python tool
load_post_env->>EnvResults.resolve_with_toolset: pass current Toolset
EnvResults.resolve_with_toolset->>PythonVenv: pass active Python
PythonVenv-->>CLI: create venv with selected interpreter
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThis PR propagates the active toolset into environment resolution so Python virtual environments honor
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains; exact resolved-version matching prevents the previously reported Important Files Changed
Reviews (2): Last reviewed commit: "fix(python): honour --tool when creating..." | Re-trigger Greptile |
`_.python.venv` builds the venv from the first `[tools] python` entry even
when the run selected a different one, so
mise run --tool python@3.12 test
silently executes under 3.13. Reported in jdx#5281, where @risu729 reduced it to:
[tools]
python = ["3.13", "3.12"]
[env._.python]
venv = { path = ".venv", create = true }
[tasks]
version = "python --version"
`mise run version` and `mise run --tool python@3.12 version` both print the
3.13 patch. Without the venv directive the second prints 3.12.
The cause is not the version selection itself. `EnvResults::venv` resolves its
own python/uv-only toolset — deliberately, to avoid a circular wait when
unrelated backends re-enter `config.env()` during env resolution — and that
toolset is rebuilt from the config files. A `--tool` override only ever reaches
a `Toolset` built by `ToolsetBuilder::with_args`, never `Config`, so it cannot
be seen from there. Giving a venv a version-templated path makes the split
visible: the directory is named for the overridden version while its
`pyvenv.cfg` records the interpreter of the first `[tools]` entry.
`Toolset::env` does have the right toolset, so it now passes it down through
`EnvResults::resolve_with_toolset`, and the venv directive records the active
python version. The rebuild and its filter are unchanged, so the deadlock it
guards against is unaffected — only the selection within the rebuilt toolset
moves.
The active version is a preference, not a request: it is kept separate from the
user-facing `_.python.venv.python` option so that a `--tool` version absent from
`[tools]` falls back to the previous behaviour instead of failing. `uv.rs`
already passed the real toolset to `create_python_venv`, so `uv_venv_auto` was
never affected and is untouched.
Out of scope: an existing venv is not rebuilt (`if !venv.exists() && create`).
A venv cannot be retargeted after creation, so a matrix over interpreters still
needs one venv per version — via a templated path or `venv = { python = "..." }`.
cbcc32d to
076c667
Compare
Fixes #5281.
_.python.venvbuilds the venv from the first[tools] pythonentry even when the run selected a different one, somise run --tool python@3.12 testsilently executes under 3.13. @risu729 reduced it to this a year ago and it still reproduces on v2026.7.15:
mise run versionmise run --tool python@3.12 version_.python.venvCause
Not the version selection itself.
EnvResults::venvresolves its own python/uv-only toolset — deliberately, to avoid the circular wait when unrelated backends re-enterconfig.env()during env resolution (thego:deadlock from #7059) — and that toolset is rebuilt from the config files. A--tooloverride only ever reaches aToolsetbuilt byToolsetBuilder::with_args; it is never written back toConfig, so it cannot be seen from there.Giving the venv a version-templated path makes the split visible. Under
--tool python@3.12the directory is named for the override while itspyvenv.cfgrecords the other interpreter:Template rendering saw the override; interpreter selection did not.
Fix
Toolset::envdoes have the right toolset, so it now passes it down viaEnvResults::resolve_with_toolset, and the venv directive records the active python version.The rebuild and its filter are unchanged — this only changes which entry is selected within the rebuilt toolset, so the deadlock it guards against is untouched. Passing the full toolset through to
create_python_venvwould not be safe:which_binwalks every backend'swhich, which is the re-entrancy path the filter exists to avoid.The active version is kept in a separate field from the user-facing
_.python.venv.pythonoption, and is a preference rather than a request: if the config-derived toolset cannot offer it we fall back to the previous behaviour instead of failing. Without that, a--toolversion absent from[tools]would start erroring where it used to work.uv.rsalready passed the real toolset tocreate_python_venv, souv_venv_autowas never affected and is untouched — that path is the precedent this follows.Out of scope
An existing venv is not rebuilt (
if !venv.exists() && create). A venv cannot be retargeted after creation, so a matrix over interpreters still needs one venv per version — a templated path, orvenv = { path = "...", python = "3.12" }, which I verified works today.Verification
Built and tested on a fork before opening this, since the change touches the deadlock-sensitive path:
cargo clippy --all-targets -- -D warnings✅cargo test✅TEST_ALL=1so the_slowguard actually runs:test_python_venv_tool_override(new — the regression above) ✅test_python_venv_with_go_backend_deadlock_slow(go backends (go:...) fail to install in CI with timeouts and repeated "go may be required but was not found" warnings #7059, the deadlock this filter exists for) ✅test_exec_venv_path_order(Bug: `mise x -- python` bypasses virtualenv after v2026.2.18 #8340) ✅test_python_venv✅The two risks worth naming — reintroducing the deadlock, and changing venv PATH ordering — are both covered by existing tests that pass.
Summary by CodeRabbit
Bug Fixes
--tool python@...option.Tests