Improve error message when a virtual environment Python symlink is broken (#12168)
When removing a Python interpreter underneath an existing venv, uv currently shows a not found error: ``` error: Failed to inspect Python interpreter from active virtual environment at `.venv/bin/python3` Caused by: Python interpreter not found at `/home/konsti/projects/uv/.venv/bin/python3` ``` This is unintuitive, as the file for the Python interpreter does exist, it is a broken symlink that needs to be replaced with `uv venv`. I've been encountering those occasionally, and I expect users that switch between versions a lot will, too, especially when they also use pyenv or a similar Python manager. The new error hints at this solution: ``` error: Failed to inspect Python interpreter from active virtual environment at `.venv/bin/python3` Caused by: Broken symlink at `.venv/bin/python3`, was the underlying Python interpreter removed? hint: To recreate the virtual environment, run `uv venv` ```
This commit is contained in:
@@ -35,7 +35,7 @@ use crate::virtualenv::{
|
||||
};
|
||||
#[cfg(windows)]
|
||||
use crate::windows_registry::{registry_pythons, WindowsPython};
|
||||
use crate::{Interpreter, PythonVersion};
|
||||
use crate::{BrokenSymlink, Interpreter, PythonVersion};
|
||||
|
||||
/// A request to find a Python installation.
|
||||
///
|
||||
@@ -815,7 +815,8 @@ impl Error {
|
||||
);
|
||||
false
|
||||
}
|
||||
InterpreterError::NotFound(path) => {
|
||||
InterpreterError::NotFound(path)
|
||||
| InterpreterError::BrokenSymlink(BrokenSymlink { path, .. }) => {
|
||||
// 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)
|
||||
@@ -894,11 +895,13 @@ pub fn find_python_installations<'a>(
|
||||
debug!("Checking for Python interpreter at {request}");
|
||||
match python_installation_from_executable(path, cache) {
|
||||
Ok(installation) => Ok(Ok(installation)),
|
||||
Err(InterpreterError::NotFound(_)) => Ok(Err(PythonNotFound {
|
||||
request: request.clone(),
|
||||
python_preference: preference,
|
||||
environment_preference: environments,
|
||||
})),
|
||||
Err(InterpreterError::NotFound(_) | InterpreterError::BrokenSymlink(_)) => {
|
||||
Ok(Err(PythonNotFound {
|
||||
request: request.clone(),
|
||||
python_preference: preference,
|
||||
environment_preference: environments,
|
||||
}))
|
||||
}
|
||||
Err(err) => Err(Error::Query(
|
||||
Box::new(err),
|
||||
path.clone(),
|
||||
@@ -918,11 +921,13 @@ pub fn find_python_installations<'a>(
|
||||
debug!("Checking for Python interpreter in {request}");
|
||||
match python_installation_from_directory(path, cache) {
|
||||
Ok(installation) => Ok(Ok(installation)),
|
||||
Err(InterpreterError::NotFound(_)) => Ok(Err(PythonNotFound {
|
||||
request: request.clone(),
|
||||
python_preference: preference,
|
||||
environment_preference: environments,
|
||||
})),
|
||||
Err(InterpreterError::NotFound(_) | InterpreterError::BrokenSymlink(_)) => {
|
||||
Ok(Err(PythonNotFound {
|
||||
request: request.clone(),
|
||||
python_preference: preference,
|
||||
environment_preference: environments,
|
||||
}))
|
||||
}
|
||||
Err(err) => Err(Error::Query(
|
||||
Box::new(err),
|
||||
path.clone(),
|
||||
|
||||
Reference in New Issue
Block a user