Always treat conda environments named `base` and `root` as base environments (#15682)

Extends https://github.com/astral-sh/uv/pull/15679

I'm not sure if we want to do this. It is probably _generally_ true, but
I think I'd rather remove the special casing entirely? I think the main
case for this is that it could help prevent regressions from #15679 and
we can remove it in a breaking release?
This commit is contained in:
Zanie Blue 2025-09-17 12:32:14 -05:00 committed by GitHub
parent 759eab837a
commit fa53a62f0b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 93 additions and 37 deletions

View File

@ -1181,19 +1181,21 @@ mod tests {
let condaenv = context.tempdir.child("condaenv"); let condaenv = context.tempdir.child("condaenv");
TestContext::mock_conda_prefix(&condaenv, "3.12.0")?; TestContext::mock_conda_prefix(&condaenv, "3.12.0")?;
let python = context.run_with_vars( let python = context
&[(EnvVars::CONDA_PREFIX, Some(condaenv.as_os_str()))], .run_with_vars(
|| { &[(EnvVars::CONDA_PREFIX, Some(condaenv.as_os_str()))],
// Note this python is not treated as a system interpreter || {
find_python_installation( // Note this python is not treated as a system interpreter
&PythonRequest::Default, find_python_installation(
EnvironmentPreference::OnlyVirtual, &PythonRequest::Default,
PythonPreference::OnlySystem, EnvironmentPreference::OnlyVirtual,
&context.cache, PythonPreference::OnlySystem,
Preview::default(), &context.cache,
) Preview::default(),
}, )
)??; },
)?
.unwrap();
assert_eq!( assert_eq!(
python.interpreter().python_full_version().to_string(), python.interpreter().python_full_version().to_string(),
"3.12.0", "3.12.0",
@ -1274,7 +1276,56 @@ mod tests {
assert_eq!( assert_eq!(
python.interpreter().python_full_version().to_string(), python.interpreter().python_full_version().to_string(),
"3.12.0", "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 // Test _CONDA_ROOT detection of base environment
@ -1311,25 +1362,27 @@ mod tests {
let other_conda_env = context.tempdir.child("other-conda"); let other_conda_env = context.tempdir.child("other-conda");
TestContext::mock_conda_prefix(&other_conda_env, "3.12.3")?; TestContext::mock_conda_prefix(&other_conda_env, "3.12.3")?;
let python = context.run_with_vars( 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_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")), EnvVars::CONDA_DEFAULT_ENV,
), Some(&OsString::from("other-conda")),
], ),
|| { ],
find_python_installation( || {
&PythonRequest::Default, find_python_installation(
EnvironmentPreference::OnlyVirtual, &PythonRequest::Default,
PythonPreference::OnlySystem, EnvironmentPreference::OnlyVirtual,
&context.cache, PythonPreference::OnlySystem,
Preview::default(), &context.cache,
) Preview::default(),
}, )
)??; },
)?
.unwrap();
assert_eq!( assert_eq!(
python.interpreter().python_full_version().to_string(), python.interpreter().python_full_version().to_string(),

View File

@ -104,12 +104,15 @@ impl CondaEnvironmentKind {
return Self::Child; return Self::Child;
} }
// These are the expected names for the base environment; we may want to remove this // If the environment name is "base" or "root", treat it as a base environment
// restriction in the future as it's not strictly necessary. //
if current_env != "base" && current_env != "root" { // These are the expected names for the base environment; and is retained for backwards
return Self::Child; // 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 { let Some(name) = path.file_name() else {
return Self::Child; return Self::Child;
}; };