From e3b274413d2c7fac135302bf24b1a825ae5046b6 Mon Sep 17 00:00:00 2001 From: Zanie Blue Date: Fri, 7 Jun 2024 17:56:45 -0400 Subject: [PATCH] Do not create a virtual environment when locking (#4147) Closes https://github.com/astral-sh/uv/issues/4141 --- crates/uv-distribution/src/workspace.rs | 5 +++++ crates/uv/src/commands/project/lock.rs | 27 +++++++++++++++---------- crates/uv/src/commands/project/mod.rs | 13 +++++++++--- crates/uv/src/commands/project/run.rs | 2 +- 4 files changed, 32 insertions(+), 15 deletions(-) diff --git a/crates/uv-distribution/src/workspace.rs b/crates/uv-distribution/src/workspace.rs index ad4d1d8e6..b7a17b999 100644 --- a/crates/uv-distribution/src/workspace.rs +++ b/crates/uv-distribution/src/workspace.rs @@ -200,6 +200,11 @@ impl Workspace { &self.root } + /// The path to the workspace virtual environment. + pub fn venv(&self) -> PathBuf { + self.root.join(".venv") + } + /// The members of the workspace. pub fn packages(&self) -> &BTreeMap { &self.packages diff --git a/crates/uv/src/commands/project/lock.rs b/crates/uv/src/commands/project/lock.rs index 0aa9341f8..b966313c1 100644 --- a/crates/uv/src/commands/project/lock.rs +++ b/crates/uv/src/commands/project/lock.rs @@ -14,7 +14,7 @@ use uv_git::GitResolver; use uv_normalize::PackageName; use uv_requirements::upgrade::{read_lockfile, LockedRequirements}; use uv_resolver::{ExcludeNewer, FlatIndex, InMemoryIndex, Lock, OptionsBuilder, RequiresPython}; -use uv_toolchain::PythonEnvironment; +use uv_toolchain::{Interpreter, Toolchain}; use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy, InFlight}; use uv_warnings::warn_user; @@ -39,8 +39,14 @@ pub(crate) async fn lock( // Find the project requirements. let workspace = Workspace::discover(&std::env::current_dir()?, None).await?; - // Discover or create the virtual environment. - let venv = project::init_environment(&workspace, preview, cache, printer)?; + // Find an interpreter for the project + let interpreter = match project::find_environment(&workspace, cache) { + Ok(environment) => environment.into_interpreter(), + Err(uv_toolchain::Error::NotFound(_)) => { + Toolchain::find_default(PreviewMode::Enabled, cache)?.into_interpreter() + } + Err(err) => return Err(err.into()), + }; // Perform the lock operation. let root_project_name = workspace.root_member().and_then(|member| { @@ -53,7 +59,7 @@ pub(crate) async fn lock( match do_lock( root_project_name, &workspace, - &venv, + &interpreter, &index_locations, upgrade, exclude_newer, @@ -81,7 +87,7 @@ pub(crate) async fn lock( pub(super) async fn do_lock( root_project_name: Option, workspace: &Workspace, - venv: &PythonEnvironment, + interpreter: &Interpreter, index_locations: &IndexLocations, upgrade: Upgrade, exclude_newer: Option, @@ -119,7 +125,7 @@ pub(super) async fn do_lock( requires_python } else { let requires_python = - RequiresPython::greater_than_equal_version(venv.interpreter().python_minor_version()); + RequiresPython::greater_than_equal_version(interpreter.python_minor_version()); if let Some(root_project_name) = root_project_name.as_ref() { warn_user!( "No `requires-python` field found in `{root_project_name}`. Defaulting to `{requires_python}`.", @@ -132,17 +138,16 @@ pub(super) async fn do_lock( requires_python }; - // Determine the tags, markers, and interpreter to use for resolution. - let interpreter = venv.interpreter(); - let tags = venv.interpreter().tags()?; - let markers = venv.interpreter().markers(); + // Determine the tags and markers to use for resolution. + let tags = interpreter.tags()?; + let markers = interpreter.markers(); // Initialize the registry client. // TODO(zanieb): Support client options e.g. offline, tls, etc. let client = RegistryClientBuilder::new(cache.clone()) .index_urls(index_locations.index_urls()) .markers(markers) - .platform(venv.interpreter().platform()) + .platform(interpreter.platform()) .build(); // TODO(charlie): Respect project configuration. diff --git a/crates/uv/src/commands/project/mod.rs b/crates/uv/src/commands/project/mod.rs index 224954176..5c4f1fe80 100644 --- a/crates/uv/src/commands/project/mod.rs +++ b/crates/uv/src/commands/project/mod.rs @@ -67,6 +67,14 @@ pub(crate) enum ProjectError { RequiresPython(#[from] uv_resolver::RequiresPythonError), } +/// Find the virtual environment for the current project. +pub(crate) fn find_environment( + workspace: &Workspace, + cache: &Cache, +) -> Result { + PythonEnvironment::from_root(workspace.venv(), cache) +} + /// Initialize a virtual environment for the current project. pub(crate) fn init_environment( workspace: &Workspace, @@ -74,11 +82,9 @@ pub(crate) fn init_environment( cache: &Cache, printer: Printer, ) -> Result { - let venv = workspace.root().join(".venv"); - // Discover or create the virtual environment. // TODO(charlie): If the environment isn't compatible with `--python`, recreate it. - match PythonEnvironment::from_root(&venv, cache) { + match find_environment(workspace, cache) { Ok(venv) => Ok(venv), Err(uv_toolchain::Error::NotFound(_)) => { // TODO(charlie): Respect `--python`; if unset, respect `Requires-Python`. @@ -91,6 +97,7 @@ pub(crate) fn init_environment( interpreter.sys_executable().user_display().cyan() )?; + let venv = workspace.venv(); writeln!( printer.stderr(), "Creating virtualenv at: {}", diff --git a/crates/uv/src/commands/project/run.rs b/crates/uv/src/commands/project/run.rs index d7dcb0e3a..04c263326 100644 --- a/crates/uv/src/commands/project/run.rs +++ b/crates/uv/src/commands/project/run.rs @@ -73,7 +73,7 @@ pub(crate) async fn run( let lock = project::lock::do_lock( root_project_name, project.workspace(), - &venv, + venv.interpreter(), &index_locations, upgrade, exclude_newer,