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");
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(),

View File

@ -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;
};