From 7eaa14e5649dcac6c6b12bee32638d30155aa07c Mon Sep 17 00:00:00 2001 From: halms <7513146+halms@users.noreply.github.com> Date: Mon, 2 Mar 2026 00:45:27 +0100 Subject: [PATCH 1/2] docs(python): clarify uv_venv_auto true value deprecation The true value is considered legacy and will be deprecated in a future release (2026.7), but the setting itself is not going away. Clarify the difference between legacy `true` (exports UV_PYTHON with just the version number) and the new recommended approach (using `tools.python.path` to strictly pin uv to mise-managed Python). Co-Authored-By: Claude Sonnet 4.6 --- docs/lang/python.md | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/docs/lang/python.md b/docs/lang/python.md index 67976b1c10..cddfe8704e 100644 --- a/docs/lang/python.md +++ b/docs/lang/python.md @@ -77,8 +77,28 @@ If you have installed `uv` (for example, with `mise use -g uv@latest`), `mise` w Note that `uv` does not include `pip` by default (as `uv` provides `uv pip` instead). If you need the `pip` package, add the `uv_create_args = ['--seed']` option. -If you are still using the legacy `python.uv_venv_auto = true` value (deprecated in favor of `"source"` or `"create|source"`), mise will also export `UV_PYTHON`, -which forces `uv` to use `mise`'s selected python version. +:::warning +The `true` value for `python.uv_venv_auto` is considered legacy and will be deprecated in a +future release (planned for mise 2026.7). Prefer `"source"` or `"create|source"` instead. +Note: the `python.uv_venv_auto` **setting** itself is not going away — only the `true` value is +being phased out. +::: + +One difference between the legacy `true` value and the newer string values is that `true` also +exports `UV_PYTHON` (set to just the Python version number). This tells `uv` which Python version +to use, but does not guarantee that `uv` uses the specific interpreter managed by `mise` — `uv` +may fall back to a system or self-managed Python of the same version. + +To strictly ensure `uv` uses `mise`'s managed Python interpreter, set `UV_PYTHON` to the actual +install path instead: + +```toml +[tools] +python = "3.12" + +[env] +UV_PYTHON = { value = "{{ tools.python.path }}", tools = true } +``` See the [mise + uv Cookbook](/mise-cookbook/python.html#mise-uv) for more examples. From c6442fdf31f573aa72e21f23725779fae2137236 Mon Sep 17 00:00:00 2001 From: halms <7513146+halms@users.noreply.github.com> Date: Mon, 2 Mar 2026 00:45:55 +0100 Subject: [PATCH 2/2] fix(python): prevent uv shim recursion when creating venv via uv_venv_auto When `uv_venv_auto = "create|source"` is set and a mise shim for uv exists on PATH (from another project), `which_non_pristine("uv")` would find the shim. Running the shim invokes `mise exec`, which re-enters the same venv creation path, causing infinite subprocess recursion (printing "mise creating venv with uv at: ..." endlessly). Fix by adding `which_no_shims()` that excludes the mise shim directory from PATH searches, and using it in `create_python_venv`. Also handle the `Ok(false)` return case in `uv_venv()` so that when venv creation is skipped (e.g. uv unavailable), we correctly return None instead of falling through to `load_venv` on a non-existent path. Co-Authored-By: Claude Sonnet 4.6 --- e2e/core/test_python_uv_venv | 40 ++++++++++++++++++++++++++------ src/config/env_directive/venv.rs | 4 ++-- src/file.rs | 13 +++++++++++ src/uv.rs | 17 ++++++++------ 4 files changed, 58 insertions(+), 16 deletions(-) diff --git a/e2e/core/test_python_uv_venv b/e2e/core/test_python_uv_venv index a0cc2ca043..4760840942 100644 --- a/e2e/core/test_python_uv_venv +++ b/e2e/core/test_python_uv_venv @@ -5,7 +5,7 @@ set -euo pipefail export MISE_EXPERIMENTAL=1 # Test uv is used for manually defined venv -cat >.mise.toml <mise.toml <.mise.toml <mise.toml <.mise.toml <mise.toml <.mise.toml <mise.toml <.mise.toml <mise.toml <"$MISE_DATA_DIR/shims/uv" <<'SHIM' +#!/bin/bash +echo "ERROR: mise uv shim was invoked during venv creation" >&2 +exit 99 +SHIM +chmod +x "$MISE_DATA_DIR/shims/uv" +ORIG_PATH="$PATH" +export PATH="$MISE_DATA_DIR/shims:$PATH" +cat >mise.toml <&1 || true) +assert_not_contains "printf '%s' \"$output\"" "ERROR: mise uv shim was invoked during venv creation" +rm -f "$MISE_DATA_DIR/shims/uv" uv.lock +export PATH="$ORIG_PATH" + ## Allows opt-out uv's venv #mkdir -p subdir -#cat >subdir/.mise.toml <subdir/mise.toml <.mise.toml <mise.toml <>(name: P) -> Option { _which(name, &env::PATH_NON_PRISTINE) } +/// returns the first executable in PATH, excluding the mise shim directory +/// use this for internal tool lookups to avoid recursive shim invocations +/// (shims call `mise exec`, which would re-enter the same code path) +pub fn which_no_shims>(name: P) -> Option { + let shim_dir = &*dirs::SHIMS; + let paths: Vec = env::PATH_NON_PRISTINE + .iter() + .filter(|p| p.as_path() != *shim_dir) + .cloned() + .collect(); + _which(name, &paths) +} + fn _which>(name: P, paths: &[PathBuf]) -> Option { let name = name.as_ref(); paths.iter().find_map(|path| { diff --git a/src/uv.rs b/src/uv.rs index 6c54053590..64c6d86f01 100644 --- a/src/uv.rs +++ b/src/uv.rs @@ -26,7 +26,7 @@ pub async fn uv_venv(config: &Arc, ts: &Toolset) -> &'static Option, ts: &Toolset) -> &'static Option {} // venv created successfully, fall through to load it + Ok(false) => return None, // uv not available, venv not created + Err(err) => { + warn_once!( + "uv venv creation failed at: {p}\n\n{err}", + p = display_path(&venv_path) + ); + return None; + } } - // venv created successfully, fall through to load it } else { if !prepare_uv_enabled(config, &uv_root) { warn_once!(