Skip to content

Commit 459269f

Browse files
potoo0zanieb
andauthored
Improve handling of invalid virtual environments during interpreter discovery (#8086)
## Summary Fix #8075. Invalid discovered environments in the working directory should be filtered out. ## Test Plan - Test python_find --------- Co-authored-by: Zanie Blue <[email protected]>
1 parent 624e79a commit 459269f

File tree

2 files changed

+75
-3
lines changed

2 files changed

+75
-3
lines changed

crates/uv-python/src/discovery.rs

+20-2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use crate::managed::ManagedPythonInstallations;
2525
use crate::microsoft_store::find_microsoft_store_pythons;
2626
#[cfg(windows)]
2727
use crate::py_launcher::{registry_pythons, WindowsPython};
28+
use crate::virtualenv::Error as VirtualEnvError;
2829
use crate::virtualenv::{
2930
conda_environment_from_env, virtualenv_from_env, virtualenv_from_working_dir,
3031
virtualenv_python_executable, CondaEnvironmentKind,
@@ -729,10 +730,27 @@ impl Error {
729730
false
730731
}
731732
InterpreterError::NotFound(path) => {
732-
trace!("Skipping missing interpreter at {}", path.display());
733-
false
733+
// If the interpreter is from an active, valid virtual environment, we should
734+
// fail because it's broken
735+
if let Some(Ok(true)) = matches!(source, PythonSource::ActiveEnvironment)
736+
.then(|| {
737+
path.parent()
738+
.and_then(Path::parent)
739+
.map(|path| path.join("pyvenv.cfg").try_exists())
740+
})
741+
.flatten()
742+
{
743+
true
744+
} else {
745+
trace!("Skipping missing interpreter at {}", path.display());
746+
false
747+
}
734748
}
735749
},
750+
Error::VirtualEnv(VirtualEnvError::MissingPyVenvCfg(path)) => {
751+
trace!("Skipping broken virtualenv at {}", path.display());
752+
false
753+
}
736754
_ => true,
737755
}
738756
}

crates/uv/tests/it/python_find.rs

+55-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use indoc::indoc;
66
use uv_python::platform::{Arch, Os};
77
use uv_static::EnvVars;
88

9-
use crate::common::{uv_snapshot, TestContext};
9+
use crate::common::{uv_snapshot, venv_bin_path, TestContext};
1010

1111
#[test]
1212
fn python_find() {
@@ -560,3 +560,57 @@ fn python_find_unsupported_version() {
560560
error: Invalid version request: Python <3.13 does not support free-threading but 3.12t was requested.
561561
"###);
562562
}
563+
564+
#[test]
565+
fn python_find_venv_invalid() {
566+
let context: TestContext = TestContext::new("3.12")
567+
// Enable additional filters for Windows compatibility
568+
.with_filtered_exe_suffix()
569+
.with_filtered_python_names()
570+
.with_filtered_virtualenv_bin();
571+
572+
// We find the virtual environment
573+
uv_snapshot!(context.filters(), context.python_find(), @r###"
574+
success: true
575+
exit_code: 0
576+
----- stdout -----
577+
[VENV]/[BIN]/python
578+
579+
----- stderr -----
580+
"###);
581+
582+
// If the binaries are missing from a virtual environment, we fail
583+
fs_err::remove_dir_all(venv_bin_path(&context.venv)).unwrap();
584+
585+
uv_snapshot!(context.filters(), context.python_find(), @r###"
586+
success: false
587+
exit_code: 2
588+
----- stdout -----
589+
590+
----- stderr -----
591+
error: Failed to inspect Python interpreter from active virtual environment at `.venv/[BIN]/python`
592+
Caused by: Python interpreter not found at `[VENV]/[BIN]/python`
593+
"###);
594+
595+
// Unless the virtual environment is not active
596+
uv_snapshot!(context.filters(), context.python_find().env_remove("VIRTUAL_ENV"), @r###"
597+
success: true
598+
exit_code: 0
599+
----- stdout -----
600+
[PYTHON-3.12]
601+
602+
----- stderr -----
603+
"###);
604+
605+
// If there's not a `pyvenv.cfg` file, it's also non-fatal, we ignore the environment
606+
fs_err::remove_file(context.venv.join("pyvenv.cfg")).unwrap();
607+
608+
uv_snapshot!(context.filters(), context.python_find(), @r###"
609+
success: true
610+
exit_code: 0
611+
----- stdout -----
612+
[PYTHON-3.12]
613+
614+
----- stderr -----
615+
"###);
616+
}

0 commit comments

Comments
 (0)