diff --git a/crates/uv-python/src/lib.rs b/crates/uv-python/src/lib.rs index f45b901ab8e2b..f5da2caa359c9 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,22 +1276,14 @@ 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" ); - // Test _CONDA_ROOT detection of base environment - let conda_root_env = context.tempdir.child("conda-root"); - TestContext::mock_conda_prefix(&conda_root_env, "3.12.2")?; - - // When _CONDA_ROOT matches CONDA_PREFIX, it should be treated as a base environment + // When CONDA_DEFAULT_ENV is "base", it should always be treated as base environment let result = context.run_with_vars( &[ - (EnvVars::CONDA_PREFIX, Some(conda_root_env.as_os_str())), - (EnvVars::CONDA_ROOT, Some(conda_root_env.as_os_str())), - ( - EnvVars::CONDA_DEFAULT_ENV, - Some(&OsString::from("custom-name")), - ), + ("CONDA_PREFIX", Some(condaenv.as_os_str())), + ("CONDA_DEFAULT_ENV", Some(&OsString::from("base"))), ], || { find_python_installation( @@ -1304,20 +1298,48 @@ mod tests { assert!( matches!(result, Err(PythonNotFound { .. })), - "Base environment detected via _CONDA_ROOT should be excluded from virtual environments; got {result:?}" + "We should not allow the base environment when looking for virtual environments" ); - // When _CONDA_ROOT doesn't match CONDA_PREFIX, it should be treated as a regular conda environment - let other_conda_env = context.tempdir.child("other-conda"); - TestContext::mock_conda_prefix(&other_conda_env, "3.12.3")?; + // 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(); - let python = context.run_with_vars( + 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 + let conda_root_env = context.tempdir.child("conda-root"); + TestContext::mock_conda_prefix(&conda_root_env, "3.12.2")?; + + // When _CONDA_ROOT matches CONDA_PREFIX, it should be treated as a base environment + let result = context.run_with_vars( &[ - (EnvVars::CONDA_PREFIX, Some(other_conda_env.as_os_str())), + (EnvVars::CONDA_PREFIX, Some(conda_root_env.as_os_str())), (EnvVars::CONDA_ROOT, Some(conda_root_env.as_os_str())), ( EnvVars::CONDA_DEFAULT_ENV, - Some(&OsString::from("custom-env")), + Some(&OsString::from("custom-name")), ), ], || { @@ -1329,7 +1351,38 @@ mod tests { Preview::default(), ) }, - )??; + )?; + + assert!( + matches!(result, Err(PythonNotFound { .. })), + "Base environment detected via _CONDA_ROOT should be excluded from virtual environments; got {result:?}" + ); + + // When _CONDA_ROOT doesn't match CONDA_PREFIX, it should be treated as a regular conda environment + 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("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 db3c90b48e6ff..92781f2ae5035 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; };