Skip to content

Commit

Permalink
Use cached environments in PEP 723 execution (#4789)
Browse files Browse the repository at this point in the history
## Summary

This seems like another good candidate for environment caching. If you
run a script repeatedly, we can just use the existing cached
environment.
  • Loading branch information
charliermarsh committed Jul 4, 2024
1 parent 892106f commit 6a27135
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 22 deletions.
5 changes: 5 additions & 0 deletions crates/uv/src/commands/project/environment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,4 +126,9 @@ impl CachedEnvironment {

Ok(Self(venv))
}

/// Convert the [`EphemeralEnvironment`] into an [`Interpreter`].
pub(crate) fn into_interpreter(self) -> Interpreter {
self.0.into_interpreter()
}
}
31 changes: 9 additions & 22 deletions crates/uv/src/commands/project/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use uv_requirements::{RequirementsSource, RequirementsSpecification};
use uv_warnings::warn_user_once;

use crate::commands::pip::operations::Modifications;
use crate::commands::project::environment::CachedEnvironment;
use crate::commands::{project, ExitStatus, SharedState};
use crate::printer::Printer;
use crate::settings::ResolverInstallerSettings;
Expand Down Expand Up @@ -55,19 +56,10 @@ pub(crate) async fn run(
let state = SharedState::default();

// Determine whether the command to execute is a PEP 723 script.
let temp_dir;
let script_interpreter = if let RunCommand::Python(target, _) = &command {
if let Some(metadata) = uv_scripts::read_pep723_metadata(&target).await? {
debug!("Found PEP 723 script at: {}", target.display());

let spec = RequirementsSpecification::from_requirements(
metadata
.dependencies
.into_iter()
.map(Requirement::from)
.collect(),
);

// (1) Explicit request from user
let python_request = if let Some(request) = python.as_deref() {
Some(PythonRequest::parse(request))
Expand Down Expand Up @@ -96,20 +88,15 @@ pub(crate) async fn run(
.await?
.into_interpreter();

// Create a virtual environment
temp_dir = cache.environment()?;
let venv = uv_virtualenv::create_venv(
temp_dir.path(),
interpreter,
uv_virtualenv::Prompt::None,
false,
false,
)?;

// Install the script requirements.
let environment = project::update_environment(
venv,
spec,
let requirements = metadata
.dependencies
.into_iter()
.map(Requirement::from)
.collect();
let environment = CachedEnvironment::get_or_create(
requirements,
interpreter,
&settings,
&state,
preview,
Expand Down
11 changes: 11 additions & 0 deletions crates/uv/tests/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ fn run_script() -> Result<()> {
"#
})?;

// Running the script should install the requirements.
uv_snapshot!(context.filters(), context.run().arg("--preview").arg("main.py"), @r###"
success: true
exit_code: 0
Expand All @@ -235,6 +236,16 @@ fn run_script() -> Result<()> {
+ iniconfig==2.0.0
"###);

// Running again should use the existing environment.
uv_snapshot!(context.filters(), context.run().arg("--preview").arg("main.py"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 1 package in [TIME]
"###);

// Otherwise, the script requirements should _not_ be available, but the project requirements
// should.
let test_non_script = context.temp_dir.child("main.py");
Expand Down

0 comments on commit 6a27135

Please sign in to comment.