Skip to content

Commit

Permalink
Avoid creating lockfile
Browse files Browse the repository at this point in the history
  • Loading branch information
charliermarsh committed Feb 12, 2025
1 parent d404d8f commit c480945
Show file tree
Hide file tree
Showing 10 changed files with 399 additions and 114 deletions.
17 changes: 14 additions & 3 deletions crates/uv-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3135,8 +3135,7 @@ pub struct SyncArgs {
#[arg(long, conflicts_with = "all_packages")]
pub package: Option<PackageName>,

/// Sync the virtual environment for the specified PEP 723 Python script, rather than the current
/// project.
/// Sync the environment for a Python script, rather than the current project.
///
/// If provided, uv will sync the dependencies based on the script's inline metadata table, in
/// adherence with PEP 723.
Expand All @@ -3146,7 +3145,19 @@ pub struct SyncArgs {
conflicts_with = "all_packages",
conflicts_with = "package",
conflicts_with = "no_install_project",
conflicts_with = "no_install_workspace"
conflicts_with = "no_install_workspace",
conflicts_with = "extra",
conflicts_with = "all_extras",
conflicts_with = "no_extra",
conflicts_with = "no_all_extras",
conflicts_with = "dev",
conflicts_with = "no_dev",
conflicts_with = "only_dev",
conflicts_with = "group",
conflicts_with = "no_group",
conflicts_with = "no_default_groups",
conflicts_with = "only_group",
conflicts_with = "all_groups"
)]
pub script: Option<PathBuf>,

Expand Down
4 changes: 2 additions & 2 deletions crates/uv-distribution/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ pub use download::LocalWheel;
pub use error::Error;
pub use index::{BuiltWheelIndex, RegistryWheelIndex};
pub use metadata::{
ArchiveMetadata, BuildRequires, FlatRequiresDist, LoweredRequirement, Metadata, MetadataError,
RequiresDist,
ArchiveMetadata, BuildRequires, FlatRequiresDist, LoweredRequirement, LoweringError, Metadata,
MetadataError, RequiresDist,
};
pub use reporter::Reporter;
pub use source::prune;
Expand Down
2 changes: 1 addition & 1 deletion crates/uv-distribution/src/metadata/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use uv_workspace::WorkspaceError;

pub use crate::metadata::build_requires::BuildRequires;
pub use crate::metadata::lowering::LoweredRequirement;
use crate::metadata::lowering::LoweringError;
pub use crate::metadata::lowering::LoweringError;
pub use crate::metadata::requires_dist::{FlatRequiresDist, RequiresDist};

mod build_requires;
Expand Down
121 changes: 115 additions & 6 deletions crates/uv/src/commands/project/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::borrow::Cow;
use std::collections::{BTreeMap, BTreeSet};
use std::fmt::Write;
use std::ops::Deref;
use std::path::{Path, PathBuf};
use std::sync::Arc;

Expand All @@ -14,10 +13,10 @@ use uv_cache_key::cache_digest;
use uv_client::{BaseClientBuilder, Connectivity, FlatIndexClient, RegistryClientBuilder};
use uv_configuration::{
Concurrency, Constraints, DevGroupsManifest, DevGroupsSpecification, DryRun,
ExtrasSpecification, PreviewMode, Reinstall, TrustedHost, Upgrade,
ExtrasSpecification, PreviewMode, Reinstall, SourceStrategy, TrustedHost, Upgrade,
};
use uv_dispatch::{BuildDispatch, SharedState};
use uv_distribution::DistributionDatabase;
use uv_distribution::{DistributionDatabase, LoweredRequirement};
use uv_distribution_types::{
Index, Resolution, UnresolvedRequirement, UnresolvedRequirementSpecification,
};
Expand Down Expand Up @@ -227,6 +226,9 @@ pub(crate) enum ProjectError {
#[error(transparent)]
Metadata(#[from] uv_distribution::MetadataError),

#[error(transparent)]
Lowering(#[from] uv_distribution::LoweringError),

#[error(transparent)]
PyprojectMut(#[from] uv_workspace::pyproject_mut::Error),

Expand Down Expand Up @@ -1224,7 +1226,7 @@ impl ProjectEnvironment {
}
}

impl Deref for ProjectEnvironment {
impl std::ops::Deref for ProjectEnvironment {
type Target = PythonEnvironment;

fn deref(&self) -> &Self::Target {
Expand Down Expand Up @@ -1389,7 +1391,7 @@ impl ScriptEnvironment {
}
}

impl Deref for ScriptEnvironment {
impl std::ops::Deref for ScriptEnvironment {
type Target = PythonEnvironment;

fn deref(&self) -> &Self::Target {
Expand Down Expand Up @@ -1911,6 +1913,7 @@ pub(crate) async fn update_environment(
native_tls: bool,
allow_insecure_host: &[TrustedHost],
cache: &Cache,
dry_run: DryRun,
printer: Printer,
preview: PreviewMode,
) -> Result<EnvironmentUpdate, ProjectError> {
Expand Down Expand Up @@ -2026,7 +2029,6 @@ pub(crate) async fn update_environment(
// optional on the downstream APIs.
let build_constraints = Constraints::default();
let build_hasher = HashStrategy::default();
let dry_run = DryRun::default();
let extras = ExtrasSpecification::default();
let groups = DevGroupsSpecification::default();
let hasher = HashStrategy::default();
Expand Down Expand Up @@ -2297,6 +2299,113 @@ pub(crate) fn detect_conflicts(
Ok(())
}

/// Determine the [`RequirementsSpecification`] for a script.
#[allow(clippy::result_large_err)]
pub(crate) fn script_specification(
script: Pep723ItemRef<'_>,
settings: ResolverSettingsRef,
) -> Result<Option<RequirementsSpecification>, ProjectError> {
let Some(dependencies) = script.metadata().dependencies.as_ref() else {
return Ok(None);
};

// Determine the working directory for the script.
let script_dir = match &script {
Pep723ItemRef::Script(script) => std::path::absolute(&script.path)?
.parent()
.expect("script path has no parent")
.to_owned(),
Pep723ItemRef::Stdin(..) | Pep723ItemRef::Remote(..) => std::env::current_dir()?,
};

// Collect any `tool.uv.index` from the script.
let empty = Vec::default();
let script_indexes = match settings.sources {
SourceStrategy::Enabled => script
.metadata()
.tool
.as_ref()
.and_then(|tool| tool.uv.as_ref())
.and_then(|uv| uv.top_level.index.as_deref())
.unwrap_or(&empty),
SourceStrategy::Disabled => &empty,
};

// Collect any `tool.uv.sources` from the script.
let empty = BTreeMap::default();
let script_sources = match settings.sources {
SourceStrategy::Enabled => script
.metadata()
.tool
.as_ref()
.and_then(|tool| tool.uv.as_ref())
.and_then(|uv| uv.sources.as_ref())
.unwrap_or(&empty),
SourceStrategy::Disabled => &empty,
};

let requirements = dependencies
.iter()
.cloned()
.flat_map(|requirement| {
LoweredRequirement::from_non_workspace_requirement(
requirement,
script_dir.as_ref(),
script_sources,
script_indexes,
settings.index_locations,
)
.map_ok(LoweredRequirement::into_inner)
})
.collect::<Result<_, _>>()?;
let constraints = script
.metadata()
.tool
.as_ref()
.and_then(|tool| tool.uv.as_ref())
.and_then(|uv| uv.constraint_dependencies.as_ref())
.into_iter()
.flatten()
.cloned()
.flat_map(|requirement| {
LoweredRequirement::from_non_workspace_requirement(
requirement,
script_dir.as_ref(),
script_sources,
script_indexes,
settings.index_locations,
)
.map_ok(LoweredRequirement::into_inner)
})
.collect::<Result<Vec<_>, _>>()?;
let overrides = script
.metadata()
.tool
.as_ref()
.and_then(|tool| tool.uv.as_ref())
.and_then(|uv| uv.override_dependencies.as_ref())
.into_iter()
.flatten()
.cloned()
.flat_map(|requirement| {
LoweredRequirement::from_non_workspace_requirement(
requirement,
script_dir.as_ref(),
script_sources,
script_indexes,
settings.index_locations,
)
.map_ok(LoweredRequirement::into_inner)
})
.collect::<Result<Vec<_>, _>>()?;

Ok(Some(RequirementsSpecification::from_overrides(
requirements,
constraints,
overrides,
)))
}

/// Warn if the user provides (e.g.) an `--index-url` in a requirements file.
fn warn_on_requirements_txt_setting(
spec: &RequirementsSpecification,
Expand Down
104 changes: 7 additions & 97 deletions crates/uv/src/commands/project/run.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use std::borrow::Cow;
use std::collections::BTreeMap;
use std::ffi::OsString;
use std::fmt::Write;
use std::io::Read;
Expand All @@ -18,9 +17,8 @@ use uv_cli::ExternalCommand;
use uv_client::{BaseClientBuilder, Connectivity};
use uv_configuration::{
Concurrency, DevGroupsSpecification, DryRun, EditableMode, ExtrasSpecification, InstallOptions,
PreviewMode, SourceStrategy, TrustedHost,
PreviewMode, TrustedHost,
};
use uv_distribution::LoweredRequirement;
use uv_fs::which::is_executable;
use uv_fs::{PythonExt, Simplified};
use uv_installer::{SatisfiesResult, SitePackages};
Expand All @@ -46,9 +44,10 @@ use crate::commands::project::install_target::InstallTarget;
use crate::commands::project::lock::LockMode;
use crate::commands::project::lock_target::LockTarget;
use crate::commands::project::{
default_dependency_groups, update_environment, validate_project_requires_python,
DependencyGroupsTarget, EnvironmentSpecification, ProjectEnvironment, ProjectError,
ScriptEnvironment, ScriptInterpreter, UniversalState, WorkspacePython,
default_dependency_groups, script_specification, update_environment,
validate_project_requires_python, DependencyGroupsTarget, EnvironmentSpecification,
ProjectEnvironment, ProjectError, ScriptEnvironment, ScriptInterpreter, UniversalState,
WorkspacePython,
};
use crate::commands::reporters::PythonDownloadReporter;
use crate::commands::run::run_to_completion;
Expand Down Expand Up @@ -318,98 +317,8 @@ pub(crate) async fn run(
);
}

// Determine the working directory for the script.
let script_dir = match &script {
Pep723Item::Script(script) => std::path::absolute(&script.path)?
.parent()
.expect("script path has no parent")
.to_owned(),
Pep723Item::Stdin(..) | Pep723Item::Remote(..) => std::env::current_dir()?,
};
let metadata = script.metadata();

// Install the script requirements, if necessary. Otherwise, use an isolated environment.
if let Some(dependencies) = metadata.dependencies.as_ref() {
// Collect any `tool.uv.index` from the script.
let empty = Vec::default();
let script_indexes = match settings.sources {
SourceStrategy::Enabled => metadata
.tool
.as_ref()
.and_then(|tool| tool.uv.as_ref())
.and_then(|uv| uv.top_level.index.as_deref())
.unwrap_or(&empty),
SourceStrategy::Disabled => &empty,
};

// Collect any `tool.uv.sources` from the script.
let empty = BTreeMap::default();
let script_sources = match settings.sources {
SourceStrategy::Enabled => metadata
.tool
.as_ref()
.and_then(|tool| tool.uv.as_ref())
.and_then(|uv| uv.sources.as_ref())
.unwrap_or(&empty),
SourceStrategy::Disabled => &empty,
};

let requirements = dependencies
.iter()
.cloned()
.flat_map(|requirement| {
LoweredRequirement::from_non_workspace_requirement(
requirement,
script_dir.as_ref(),
script_sources,
script_indexes,
&settings.index_locations,
)
.map_ok(LoweredRequirement::into_inner)
})
.collect::<Result<_, _>>()?;
let constraints = metadata
.tool
.as_ref()
.and_then(|tool| tool.uv.as_ref())
.and_then(|uv| uv.constraint_dependencies.as_ref())
.into_iter()
.flatten()
.cloned()
.flat_map(|requirement| {
LoweredRequirement::from_non_workspace_requirement(
requirement,
script_dir.as_ref(),
script_sources,
script_indexes,
&settings.index_locations,
)
.map_ok(LoweredRequirement::into_inner)
})
.collect::<Result<Vec<_>, _>>()?;
let overrides = metadata
.tool
.as_ref()
.and_then(|tool| tool.uv.as_ref())
.and_then(|uv| uv.override_dependencies.as_ref())
.into_iter()
.flatten()
.cloned()
.flat_map(|requirement| {
LoweredRequirement::from_non_workspace_requirement(
requirement,
script_dir.as_ref(),
script_sources,
script_indexes,
&settings.index_locations,
)
.map_ok(LoweredRequirement::into_inner)
})
.collect::<Result<Vec<_>, _>>()?;

let spec =
RequirementsSpecification::from_overrides(requirements, constraints, overrides);

if let Some(spec) = script_specification((&script).into(), settings.as_ref().into())? {
let environment = ScriptEnvironment::get_or_init(
(&script).into(),
python.as_deref().map(PythonRequest::parse),
Expand Down Expand Up @@ -449,6 +358,7 @@ pub(crate) async fn run(
native_tls,
allow_insecure_host,
cache,
DryRun::Disabled,
printer,
preview,
)
Expand Down
Loading

0 comments on commit c480945

Please sign in to comment.