From c826f2b042c78af0b58e1a27c43b8a5603a0f2b3 Mon Sep 17 00:00:00 2001 From: liam Date: Sun, 9 Nov 2025 23:16:17 -0500 Subject: [PATCH] Fix pixi environment detection by recognizing Conda prefixes with `conda-meta/pixi` (#16585) Resolves https://github.com/astral-sh/uv/issues/16295 This PR updates the Conda base-environment heuristic to recognize Pixi-managed environments by checking for the `conda-meta/pixi` marker file. Pixi default environments now resolve as isolated child environments instead of system installations, restoring the expected uv pip behavior without the `--system` flag. --- crates/uv-python/src/virtualenv.rs | 38 ++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/crates/uv-python/src/virtualenv.rs b/crates/uv-python/src/virtualenv.rs index 92781f2ae..b21b3f77c 100644 --- a/crates/uv-python/src/virtualenv.rs +++ b/crates/uv-python/src/virtualenv.rs @@ -86,6 +86,12 @@ impl CondaEnvironmentKind { /// `/usr/local/conda/envs/`. Note the name `CONDA_DEFAULT_ENV` is misleading, it's the /// active environment name, not a constant base environment name. fn from_prefix_path(path: &Path) -> Self { + // Pixi never creates true "base" envs and names project envs "default", confusing our + // heuristics, so treat Pixi prefixes as child envs outright. + if is_pixi_environment(path) { + return Self::Child; + } + // If `_CONDA_ROOT` is set and matches `CONDA_PREFIX`, it's the base environment. if let Ok(conda_root) = env::var(EnvVars::CONDA_ROOT) { if path == Path::new(&conda_root) { @@ -127,6 +133,11 @@ impl CondaEnvironmentKind { } } +/// Detect whether the current `CONDA_PREFIX` belongs to a Pixi-managed environment. +fn is_pixi_environment(path: &Path) -> bool { + path.join("conda-meta").join("pixi").is_file() +} + /// Locate an active conda environment by inspecting environment variables. /// /// If `base` is true, the active environment must be the base environment or `None` is returned, @@ -317,10 +328,37 @@ impl PyVenvConfiguration { #[cfg(test)] mod tests { + use std::ffi::OsStr; + use indoc::indoc; + use temp_env::with_vars; + use tempfile::tempdir; use super::*; + #[test] + fn pixi_environment_is_treated_as_child() { + let tempdir = tempdir().unwrap(); + let prefix = tempdir.path(); + let conda_meta = prefix.join("conda-meta"); + + fs::create_dir_all(&conda_meta).unwrap(); + fs::write(conda_meta.join("pixi"), []).unwrap(); + + let vars = [ + (EnvVars::CONDA_ROOT, None), + (EnvVars::CONDA_PREFIX, Some(prefix.as_os_str())), + (EnvVars::CONDA_DEFAULT_ENV, Some(OsStr::new("example"))), + ]; + + with_vars(vars, || { + assert_eq!( + CondaEnvironmentKind::from_prefix_path(prefix), + CondaEnvironmentKind::Child + ); + }); + } + #[test] fn test_set_existing_key() { let content = indoc! {"