diff --git a/crates/uv-python/src/lib.rs b/crates/uv-python/src/lib.rs index f45b901ab..f5da2caa3 100644 --- a/crates/uv-python/src/lib.rs +++ b/crates/uv-python/src/lib.rs @@ -1181,19 +1181,21 @@ mod tests { let condaenv = context.tempdir.child("condaenv"); TestContext::mock_conda_prefix(&condaenv, "3.12.0")?; - let python = context.run_with_vars( - &[(EnvVars::CONDA_PREFIX, Some(condaenv.as_os_str()))], - || { - // Note this python is not treated as a system interpreter - find_python_installation( - &PythonRequest::Default, - EnvironmentPreference::OnlyVirtual, - PythonPreference::OnlySystem, - &context.cache, - Preview::default(), - ) - }, - )??; + let python = context + .run_with_vars( + &[(EnvVars::CONDA_PREFIX, Some(condaenv.as_os_str()))], + || { + // Note this python is not treated as a system interpreter + find_python_installation( + &PythonRequest::Default, + EnvironmentPreference::OnlyVirtual, + PythonPreference::OnlySystem, + &context.cache, + Preview::default(), + ) + }, + )? + .unwrap(); assert_eq!( python.interpreter().python_full_version().to_string(), "3.12.0", @@ -1274,7 +1276,56 @@ mod tests { assert_eq!( python.interpreter().python_full_version().to_string(), "3.12.0", - "We should find the conda environment" + "We should find the conda environment when name matches" + ); + + // When CONDA_DEFAULT_ENV is "base", it should always be treated as base environment + let result = 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(), + ) + }, + )?; + + assert!( + matches!(result, Err(PythonNotFound { .. })), + "We should not allow the base environment when looking for virtual environments" + ); + + // When environment name matches directory name, it should be treated as a child environment + let myenv_dir = context.tempdir.child("myenv"); + TestContext::mock_conda_prefix(&myenv_dir, "3.12.5")?; + let python = context + .run_with_vars( + &[ + ("CONDA_PREFIX", Some(myenv_dir.as_os_str())), + ("CONDA_DEFAULT_ENV", Some(&OsString::from("myenv"))), + ], + || { + find_python_installation( + &PythonRequest::Default, + EnvironmentPreference::OnlyVirtual, + PythonPreference::OnlySystem, + &context.cache, + Preview::default(), + ) + }, + )? + .unwrap(); + + assert_eq!( + python.interpreter().python_full_version().to_string(), + "3.12.5", + "We should find the child conda environment" ); // Test _CONDA_ROOT detection of base environment @@ -1311,25 +1362,27 @@ mod tests { let other_conda_env = context.tempdir.child("other-conda"); TestContext::mock_conda_prefix(&other_conda_env, "3.12.3")?; - let python = context.run_with_vars( - &[ - (EnvVars::CONDA_PREFIX, Some(other_conda_env.as_os_str())), - (EnvVars::CONDA_ROOT, Some(conda_root_env.as_os_str())), - ( - EnvVars::CONDA_DEFAULT_ENV, - Some(&OsString::from("custom-env")), - ), - ], - || { - find_python_installation( - &PythonRequest::Default, - EnvironmentPreference::OnlyVirtual, - PythonPreference::OnlySystem, - &context.cache, - Preview::default(), - ) - }, - )??; + let python = context + .run_with_vars( + &[ + (EnvVars::CONDA_PREFIX, Some(other_conda_env.as_os_str())), + (EnvVars::CONDA_ROOT, Some(conda_root_env.as_os_str())), + ( + EnvVars::CONDA_DEFAULT_ENV, + Some(&OsString::from("other-conda")), + ), + ], + || { + 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 db3c90b48..92781f2ae 100644 --- a/crates/uv-python/src/virtualenv.rs +++ b/crates/uv-python/src/virtualenv.rs @@ -104,12 +104,15 @@ impl CondaEnvironmentKind { return Self::Child; } - // These are the expected names for the base environment; we may want to remove this - // restriction in the future as it's not strictly necessary. - if current_env != "base" && current_env != "root" { - return Self::Child; + // If the environment name is "base" or "root", treat it as a base environment + // + // These are the expected names for the base environment; and is retained for backwards + // compatibility, but in a future breaking release we should remove this special-casing. + if current_env == "base" || current_env == "root" { + return Self::Base; } + // For other environment names, use the path-based logic let Some(name) = path.file_name() else { return Self::Child; };