Skip to content

Commit

Permalink
Reinstall and recreate environments when interpreter is removed (#4935)
Browse files Browse the repository at this point in the history
## Summary

We now recreate the environment in `uv sync`, `uv tool install`, and `uv
tool run` if the underlying interpreter has been removed.

Closes #4933.
  • Loading branch information
charliermarsh committed Jul 9, 2024
1 parent 53db63f commit bb703b8
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 14 deletions.
36 changes: 25 additions & 11 deletions crates/uv-tool/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::str::FromStr;

use fs_err::File;
use thiserror::Error;
use tracing::debug;
use tracing::{debug, warn};

use install_wheel_rs::read_record_file;

Expand Down Expand Up @@ -178,6 +178,9 @@ impl InstalledTools {
}

/// Return the [`PythonEnvironment`] for a given tool, if it exists.
///
/// Returns `Ok(None)` if the environment does not exist or is linked to a non-existent
/// interpreter.
pub fn get_environment(
&self,
name: &PackageName,
Expand All @@ -186,14 +189,25 @@ impl InstalledTools {
let _lock = self.acquire_lock();
let environment_path = self.root.join(name.to_string());

if environment_path.is_dir() {
debug!(
"Using existing environment for tool `{name}` at `{}`.",
environment_path.user_display()
);
Ok(Some(PythonEnvironment::from_root(environment_path, cache)?))
} else {
Ok(None)
match PythonEnvironment::from_root(&environment_path, cache) {
Ok(venv) => {
debug!(
"Using existing environment for tool `{name}`: {}",
environment_path.user_display()
);
Ok(Some(venv))
}
Err(uv_python::Error::MissingEnvironment(_)) => Ok(None),
Err(uv_python::Error::Query(uv_python::InterpreterError::NotFound(
interpreter_path,
))) => {
warn!(
"Ignoring existing virtual environment linked to non-existent Python interpreter: {}",
interpreter_path.user_display()
);
Ok(None)
}
Err(err) => Err(err.into()),
}
}

Expand All @@ -210,7 +224,7 @@ impl InstalledTools {
match fs_err::remove_dir_all(&environment_path) {
Ok(()) => {
debug!(
"Removed existing environment for tool `{name}` at `{}`.",
"Removed existing environment for tool `{name}`: {}",
environment_path.user_display()
);
}
Expand All @@ -219,7 +233,7 @@ impl InstalledTools {
}

debug!(
"Creating environment for tool `{name}` at `{}`.",
"Creating environment for tool `{name}`: {}",
environment_path.user_display()
);

Expand Down
7 changes: 7 additions & 0 deletions crates/uv/src/commands/project/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use uv_python::{
use uv_requirements::{NamedRequirementsResolver, RequirementsSpecification};
use uv_resolver::{FlatIndex, OptionsBuilder, PythonRequirement, RequiresPython, ResolutionGraph};
use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy};
use uv_warnings::warn_user;

use crate::commands::pip::operations::Modifications;
use crate::commands::reporters::{PythonDownloadReporter, ResolverReporter};
Expand Down Expand Up @@ -174,6 +175,12 @@ impl FoundInterpreter {
}
}
Err(uv_python::Error::MissingEnvironment(_)) => {}
Err(uv_python::Error::Query(uv_python::InterpreterError::NotFound(path))) => {
warn_user!(
"Ignoring existing virtual environment linked to non-existent Python interpreter: {}",
path.user_display().cyan()
);
}
Err(err) => return Err(err.into()),
};

Expand Down
3 changes: 1 addition & 2 deletions crates/uv/src/commands/tool/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,8 @@ pub(crate) async fn install(
} else {
let _ = writeln!(
printer.stderr(),
"Existing environment for `{}` does not satisfy the requested Python interpreter (`{}`)",
"Existing environment for `{}` does not satisfy the requested Python interpreter",
from.name,
python_request
);
false
}
Expand Down
2 changes: 1 addition & 1 deletion crates/uv/tests/tool_install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1393,7 +1393,7 @@ fn tool_install_python_request() {
----- stderr -----
warning: `uv tool install` is experimental and may change without warning.
Existing environment for `black` does not satisfy the requested Python interpreter (`Python 3.11`)
Existing environment for `black` does not satisfy the requested Python interpreter
Resolved [N] packages in [TIME]
Prepared [N] packages in [TIME]
Installed [N] packages in [TIME]
Expand Down

0 comments on commit bb703b8

Please sign in to comment.