From ee5f155f7ef2cf10b87920b366e7e912f2182dc4 Mon Sep 17 00:00:00 2001 From: Zanie Blue Date: Wed, 17 Sep 2025 06:04:29 -0500 Subject: [PATCH] Invert the logic for determining if a path is a base conda environment (#15679) Closes https://github.com/astral-sh/uv/issues/15604 The previous logic does not match the discussion in the original issue about this feature, nor does it match the comment for the function. I'm confused because I know this logic is working for some people? I'm consequently a little wary of making this change. I'm following up with some additional changes that should ensure this is robust, e.g., #15680 --- crates/uv-python/src/lib.rs | 66 ++++++++++++++++-------------- crates/uv-python/src/virtualenv.rs | 15 ++++--- 2 files changed, 45 insertions(+), 36 deletions(-) diff --git a/crates/uv-python/src/lib.rs b/crates/uv-python/src/lib.rs index 7362c710d..51ecbda8c 100644 --- a/crates/uv-python/src/lib.rs +++ b/crates/uv-python/src/lib.rs @@ -1200,7 +1200,7 @@ mod tests { "We should allow the active conda python" ); - let baseenv = context.tempdir.child("base"); + let baseenv = context.tempdir.child("conda"); TestContext::mock_conda_prefix(&baseenv, "3.12.1")?; // But not if it's a base environment @@ -1226,21 +1226,23 @@ mod tests { ); // Unless, system interpreters are included... - let python = context.run_with_vars( - &[ - ("CONDA_PREFIX", Some(baseenv.as_os_str())), - ("CONDA_DEFAULT_ENV", Some(&OsString::from("base"))), - ], - || { - find_python_installation( - &PythonRequest::Default, - EnvironmentPreference::OnlySystem, - PythonPreference::OnlySystem, - &context.cache, - Preview::default(), - ) - }, - )??; + let python = context + .run_with_vars( + &[ + ("CONDA_PREFIX", Some(baseenv.as_os_str())), + ("CONDA_DEFAULT_ENV", Some(&OsString::from("base"))), + ], + || { + find_python_installation( + &PythonRequest::Default, + EnvironmentPreference::OnlySystem, + PythonPreference::OnlySystem, + &context.cache, + Preview::default(), + ) + }, + )? + .unwrap(); assert_eq!( python.interpreter().python_full_version().to_string(), @@ -1249,21 +1251,23 @@ mod tests { ); // If the environment name doesn't match the default, we should not treat it as system - let python = context.run_with_vars( - &[ - ("CONDA_PREFIX", Some(condaenv.as_os_str())), - ("CONDA_DEFAULT_ENV", Some(&OsString::from("base"))), - ], - || { - find_python_installation( - &PythonRequest::Default, - EnvironmentPreference::OnlyVirtual, - PythonPreference::OnlySystem, - &context.cache, - Preview::default(), - ) - }, - )??; + let python = context + .run_with_vars( + &[ + ("CONDA_PREFIX", Some(condaenv.as_os_str())), + ("CONDA_DEFAULT_ENV", Some(&OsString::from("condaenv"))), + ], + || { + find_python_installation( + &PythonRequest::Default, + EnvironmentPreference::OnlyVirtual, + PythonPreference::OnlySystem, + &context.cache, + Preview::default(), + ) + }, + )? + .unwrap(); assert_eq!( python.interpreter().python_full_version().to_string(), diff --git a/crates/uv-python/src/virtualenv.rs b/crates/uv-python/src/virtualenv.rs index f4314ed5f..a4e7d5509 100644 --- a/crates/uv-python/src/virtualenv.rs +++ b/crates/uv-python/src/virtualenv.rs @@ -82,14 +82,17 @@ impl CondaEnvironmentKind { /// When the base environment is used, `CONDA_DEFAULT_ENV` will be set to a name, i.e., `base` or /// `root` which does not match the prefix, e.g. `/usr/local` instead of /// `/usr/local/conda/envs/`. + /// + /// Note the name `CONDA_DEFAULT_ENV` is misleading, it's the current environment, not the base + /// environment name. fn from_prefix_path(path: &Path) -> Self { // If we cannot read `CONDA_DEFAULT_ENV`, there's no way to know if the base environment - let Ok(default_env) = env::var(EnvVars::CONDA_DEFAULT_ENV) else { + let Ok(current_env) = env::var(EnvVars::CONDA_DEFAULT_ENV) else { return Self::Child; }; // These are the expected names for the base environment - if default_env != "base" && default_env != "root" { + if current_env != "base" && current_env != "root" { return Self::Child; } @@ -97,10 +100,12 @@ impl CondaEnvironmentKind { return Self::Child; }; - if name.to_str().is_some_and(|name| name == default_env) { - Self::Base - } else { + // If the environment is in a directory matching the name of the environment, it's not + // usually a base environment. + if name.to_str().is_some_and(|name| name == current_env) { Self::Child + } else { + Self::Base } } }