Remove unnecessary optional from uv run (#5976)

## Summary

This is always `Some` now.
This commit is contained in:
Charlie Marsh 2024-08-09 16:13:47 -04:00 committed by GitHub
parent 921050d747
commit dd32087842
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -187,7 +187,7 @@ pub(crate) async fn run(
// Discover and sync the base environment. // Discover and sync the base environment.
let temp_dir; let temp_dir;
let base_interpreter = if let Some(script_interpreter) = script_interpreter { let base_interpreter = if let Some(script_interpreter) = script_interpreter {
Some(script_interpreter) script_interpreter
} else { } else {
let project = if no_project { let project = if no_project {
None None
@ -376,16 +376,14 @@ pub(crate) async fn run(
} }
}; };
Some(interpreter) interpreter
}; };
if let Some(base_interpreter) = &base_interpreter { debug!(
debug!( "Using Python {} interpreter at: {}",
"Using Python {} interpreter at: {}", base_interpreter.python_version(),
base_interpreter.python_version(), base_interpreter.sys_executable().display()
base_interpreter.sys_executable().display() );
);
}
// Read the requirements. // Read the requirements.
let spec = if requirements.is_empty() { let spec = if requirements.is_empty() {
@ -401,85 +399,20 @@ pub(crate) async fn run(
Some(spec) Some(spec)
}; };
// Determine whether the base environment satisfies the ephemeral requirements. If we don't have
// any `--with` requirements, and we already have a base environment, then there's no need to
// create an additional environment.
let skip_ephemeral = base_interpreter.as_ref().is_some_and(|base_interpreter| {
// No additional requirements.
let Some(spec) = spec.as_ref() else {
return true;
};
let Ok(site_packages) = SitePackages::from_interpreter(base_interpreter) else {
return false;
};
if !(settings.reinstall.is_none() && settings.reinstall.is_none()) {
return false;
}
match site_packages.satisfies(&spec.requirements, &spec.constraints) {
// If the requirements are already satisfied, we're done.
Ok(SatisfiesResult::Fresh {
recursive_requirements,
}) => {
debug!(
"Base environment satisfies requirements: {}",
recursive_requirements
.iter()
.map(|entry| entry.requirement.to_string())
.sorted()
.join(" | ")
);
true
}
Ok(SatisfiesResult::Unsatisfied(requirement)) => {
debug!("At least one requirement is not satisfied in the base environment: {requirement}");
false
}
Err(err) => {
debug!("Failed to check requirements against base environment: {err}");
false
}
}
});
// If necessary, create an environment for the ephemeral requirements or command. // If necessary, create an environment for the ephemeral requirements or command.
let temp_dir; let temp_dir;
let ephemeral_env = if skip_ephemeral { let ephemeral_env = if can_skip_ephemeral(spec.as_ref(), &base_interpreter, &settings) {
None None
} else { } else {
debug!("Creating ephemeral environment"); debug!("Creating ephemeral environment");
// Discover an interpreter.
let interpreter = if let Some(base_interpreter) = &base_interpreter {
base_interpreter.clone()
} else {
let client_builder = BaseClientBuilder::new()
.connectivity(connectivity)
.native_tls(native_tls);
// Note we force preview on during `uv run` for now since the entire interface is in preview
PythonInstallation::find_or_download(
python.as_deref().map(PythonRequest::parse),
EnvironmentPreference::Any,
python_preference,
python_downloads,
&client_builder,
cache,
Some(&download_reporter),
)
.await?
.into_interpreter()
};
Some(match spec.filter(|spec| !spec.is_empty()) { Some(match spec.filter(|spec| !spec.is_empty()) {
None => { None => {
// Create a virtual environment // Create a virtual environment
temp_dir = cache.environment()?; temp_dir = cache.environment()?;
uv_virtualenv::create_venv( uv_virtualenv::create_venv(
temp_dir.path(), temp_dir.path(),
interpreter, base_interpreter.clone(),
uv_virtualenv::Prompt::None, uv_virtualenv::Prompt::None,
false, false,
false, false,
@ -491,7 +424,7 @@ pub(crate) async fn run(
CachedEnvironment::get_or_create( CachedEnvironment::get_or_create(
spec, spec,
interpreter, base_interpreter.clone(),
&settings, &settings,
&state, &state,
if show_resolution { if show_resolution {
@ -521,24 +454,22 @@ pub(crate) async fn run(
// the base environment's site packages. Setting `PYTHONPATH` is insufficient, as it doesn't // the base environment's site packages. Setting `PYTHONPATH` is insufficient, as it doesn't
// resolve `.pth` files in the base environment. // resolve `.pth` files in the base environment.
if let Some(ephemeral_env) = ephemeral_env.as_ref() { if let Some(ephemeral_env) = ephemeral_env.as_ref() {
if let Some(base_interpreter) = base_interpreter.as_ref() { let ephemeral_site_packages = ephemeral_env
let ephemeral_site_packages = ephemeral_env .site_packages()
.site_packages() .next()
.next() .ok_or_else(|| anyhow!("Ephemeral environment has no site packages directory"))?;
.ok_or_else(|| anyhow!("Ephemeral environment has no site packages directory"))?; let base_site_packages = base_interpreter
let base_site_packages = base_interpreter .site_packages()
.site_packages() .next()
.next() .ok_or_else(|| anyhow!("Base environment has no site packages directory"))?;
.ok_or_else(|| anyhow!("Base environment has no site packages directory"))?;
fs_err::write( fs_err::write(
ephemeral_site_packages.join("sitecustomize.py"), ephemeral_site_packages.join("sitecustomize.py"),
format!( format!(
"import site; site.addsitedir(\"{}\")", "import site; site.addsitedir(\"{}\")",
base_site_packages.escape_for_python() base_site_packages.escape_for_python()
), ),
)?; )?;
}
} }
debug!("Running `{command}`"); debug!("Running `{command}`");
@ -550,12 +481,7 @@ pub(crate) async fn run(
.as_ref() .as_ref()
.map(PythonEnvironment::scripts) .map(PythonEnvironment::scripts)
.into_iter() .into_iter()
.chain( .chain(std::iter::once(base_interpreter.scripts()))
base_interpreter
.as_ref()
.map(Interpreter::scripts)
.into_iter(),
)
.map(PathBuf::from) .map(PathBuf::from)
.chain( .chain(
std::env::var_os("PATH") std::env::var_os("PATH")
@ -592,6 +518,53 @@ pub(crate) async fn run(
} }
} }
/// Returns `true` if we can skip creating an additional ephemeral environment in `uv run`.
fn can_skip_ephemeral(
spec: Option<&RequirementsSpecification>,
base_interpreter: &Interpreter,
settings: &ResolverInstallerSettings,
) -> bool {
// No additional requirements.
let Some(spec) = spec.as_ref() else {
return true;
};
let Ok(site_packages) = SitePackages::from_interpreter(base_interpreter) else {
return false;
};
if !(settings.reinstall.is_none() && settings.reinstall.is_none()) {
return false;
}
match site_packages.satisfies(&spec.requirements, &spec.constraints) {
// If the requirements are already satisfied, we're done.
Ok(SatisfiesResult::Fresh {
recursive_requirements,
}) => {
debug!(
"Base environment satisfies requirements: {}",
recursive_requirements
.iter()
.map(|entry| entry.requirement.to_string())
.sorted()
.join(" | ")
);
true
}
Ok(SatisfiesResult::Unsatisfied(requirement)) => {
debug!(
"At least one requirement is not satisfied in the base environment: {requirement}"
);
false
}
Err(err) => {
debug!("Failed to check requirements against base environment: {err}");
false
}
}
}
#[derive(Debug)] #[derive(Debug)]
enum RunCommand { enum RunCommand {
/// Execute a `python` script. /// Execute a `python` script.