Skip to content

Commit

Permalink
Improve handling of invalid virtual environments during interpreter d…
Browse files Browse the repository at this point in the history
…iscovery (#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]>
  • Loading branch information
potoo0 and zanieb authored Dec 10, 2024
1 parent 624e79a commit 459269f
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 3 deletions.
22 changes: 20 additions & 2 deletions crates/uv-python/src/discovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use crate::managed::ManagedPythonInstallations;
use crate::microsoft_store::find_microsoft_store_pythons;
#[cfg(windows)]
use crate::py_launcher::{registry_pythons, WindowsPython};
use crate::virtualenv::Error as VirtualEnvError;
use crate::virtualenv::{
conda_environment_from_env, virtualenv_from_env, virtualenv_from_working_dir,
virtualenv_python_executable, CondaEnvironmentKind,
Expand Down Expand Up @@ -729,10 +730,27 @@ impl Error {
false
}
InterpreterError::NotFound(path) => {
trace!("Skipping missing interpreter at {}", path.display());
false
// If the interpreter is from an active, valid virtual environment, we should
// fail because it's broken
if let Some(Ok(true)) = matches!(source, PythonSource::ActiveEnvironment)
.then(|| {
path.parent()
.and_then(Path::parent)
.map(|path| path.join("pyvenv.cfg").try_exists())
})
.flatten()
{
true
} else {
trace!("Skipping missing interpreter at {}", path.display());
false
}
}
},
Error::VirtualEnv(VirtualEnvError::MissingPyVenvCfg(path)) => {
trace!("Skipping broken virtualenv at {}", path.display());
false
}
_ => true,
}
}
Expand Down
56 changes: 55 additions & 1 deletion crates/uv/tests/it/python_find.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use indoc::indoc;
use uv_python::platform::{Arch, Os};
use uv_static::EnvVars;

use crate::common::{uv_snapshot, TestContext};
use crate::common::{uv_snapshot, venv_bin_path, TestContext};

#[test]
fn python_find() {
Expand Down Expand Up @@ -560,3 +560,57 @@ fn python_find_unsupported_version() {
error: Invalid version request: Python <3.13 does not support free-threading but 3.12t was requested.
"###);
}

#[test]
fn python_find_venv_invalid() {
let context: TestContext = TestContext::new("3.12")
// Enable additional filters for Windows compatibility
.with_filtered_exe_suffix()
.with_filtered_python_names()
.with_filtered_virtualenv_bin();

// We find the virtual environment
uv_snapshot!(context.filters(), context.python_find(), @r###"
success: true
exit_code: 0
----- stdout -----
[VENV]/[BIN]/python
----- stderr -----
"###);

// If the binaries are missing from a virtual environment, we fail
fs_err::remove_dir_all(venv_bin_path(&context.venv)).unwrap();

uv_snapshot!(context.filters(), context.python_find(), @r###"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: Failed to inspect Python interpreter from active virtual environment at `.venv/[BIN]/python`
Caused by: Python interpreter not found at `[VENV]/[BIN]/python`
"###);

// Unless the virtual environment is not active
uv_snapshot!(context.filters(), context.python_find().env_remove("VIRTUAL_ENV"), @r###"
success: true
exit_code: 0
----- stdout -----
[PYTHON-3.12]
----- stderr -----
"###);

// If there's not a `pyvenv.cfg` file, it's also non-fatal, we ignore the environment
fs_err::remove_file(context.venv.join("pyvenv.cfg")).unwrap();

uv_snapshot!(context.filters(), context.python_find(), @r###"
success: true
exit_code: 0
----- stdout -----
[PYTHON-3.12]
----- stderr -----
"###);
}

0 comments on commit 459269f

Please sign in to comment.