From 8de3e38b9479c49c5e80d4e3a865be5a0f488502 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Tue, 4 Jun 2024 21:03:55 -0400 Subject: [PATCH] Read all extras directly from lockfile (#4033) ## Summary We now pass `ExtrasSpecification` to the lock routine. --- crates/uv-distribution/src/workspace.rs | 50 +++++-------------------- crates/uv-resolver/src/lock.rs | 22 +++++++++-- crates/uv/src/commands/project/sync.rs | 5 --- 3 files changed, 29 insertions(+), 48 deletions(-) diff --git a/crates/uv-distribution/src/workspace.rs b/crates/uv-distribution/src/workspace.rs index cfeb016d0..3ae48ecfc 100644 --- a/crates/uv-distribution/src/workspace.rs +++ b/crates/uv-distribution/src/workspace.rs @@ -10,7 +10,7 @@ use tracing::{debug, trace}; use pep508_rs::VerbatimUrl; use pypi_types::{Requirement, RequirementSource}; use uv_fs::{absolutize_path, Simplified}; -use uv_normalize::{ExtraName, PackageName}; +use uv_normalize::PackageName; use uv_warnings::warn_user; use crate::pyproject::{PyProjectToml, Source, ToolUvWorkspace}; @@ -134,21 +134,9 @@ impl Workspace { /// Returns `None` if the package is not part of the workspace. pub fn with_current_project(self, package_name: PackageName) -> Option { let member = self.packages.get(&package_name)?; - let extras = member - .pyproject_toml - .project - .as_ref() - .and_then(|project| project.optional_dependencies.as_ref()) - .map(|optional_dependencies| { - let mut extras = optional_dependencies.keys().cloned().collect::>(); - extras.sort_unstable(); - extras - }) - .unwrap_or_default(); Some(ProjectWorkspace { project_root: member.root().clone(), project_name: package_name, - extras, workspace: self, }) } @@ -393,8 +381,6 @@ pub struct ProjectWorkspace { project_root: PathBuf, /// The name of the package. project_name: PackageName, - /// The extras available in the project. - extras: Vec, /// The workspace the project is part of. workspace: Workspace, } @@ -496,11 +482,6 @@ impl ProjectWorkspace { &self.project_name } - /// Returns the extras available in the project. - pub fn project_extras(&self) -> &[ExtraName] { - &self.extras - } - /// Returns the [`Workspace`] containing the current project. pub fn workspace(&self) -> &Workspace { &self.workspace @@ -516,7 +497,15 @@ impl ProjectWorkspace { pub fn requirements(&self) -> Vec { vec![Requirement { name: self.project_name.clone(), - extras: self.extras.clone(), + extras: self.workspace().packages[&self.project_name] + .pyproject_toml + .project + .as_ref() + .and_then(|project| project.optional_dependencies.as_ref()) + .map(|optional_dependencies| { + optional_dependencies.keys().cloned().collect::>() + }) + .unwrap_or_default(), marker: None, source: RequirementSource::Path { path: self.project_root.clone(), @@ -538,18 +527,6 @@ impl ProjectWorkspace { .map_err(WorkspaceError::Normalize)? .to_path_buf(); - // Extract the extras available in the project. - let extras = project - .project - .as_ref() - .and_then(|project| project.optional_dependencies.as_ref()) - .map(|optional_dependencies| { - let mut extras = optional_dependencies.keys().cloned().collect::>(); - extras.sort_unstable(); - extras - }) - .unwrap_or_default(); - // Check if the current project is also an explicit workspace root. let mut workspace = project .tool @@ -579,7 +556,6 @@ impl ProjectWorkspace { return Ok(Self { project_root: project_path.clone(), project_name: project_name.clone(), - extras, workspace: Workspace { root: project_path.clone(), packages: current_project_as_members, @@ -607,7 +583,6 @@ impl ProjectWorkspace { Ok(Self { project_root: project_path, project_name, - extras, workspace, }) } @@ -838,7 +813,6 @@ mod tests { { "project_root": "[ROOT]/albatross-in-example/examples/bird-feeder", "project_name": "bird-feeder", - "extras": [], "workspace": { "root": "[ROOT]/albatross-in-example/examples/bird-feeder", "packages": { @@ -869,7 +843,6 @@ mod tests { { "project_root": "[ROOT]/albatross-project-in-excluded/excluded/bird-feeder", "project_name": "bird-feeder", - "extras": [], "workspace": { "root": "[ROOT]/albatross-project-in-excluded/excluded/bird-feeder", "packages": { @@ -899,7 +872,6 @@ mod tests { { "project_root": "[ROOT]/albatross-root-workspace", "project_name": "albatross", - "extras": [], "workspace": { "root": "[ROOT]/albatross-root-workspace", "packages": { @@ -943,7 +915,6 @@ mod tests { { "project_root": "[ROOT]/albatross-virtual-workspace/packages/albatross", "project_name": "albatross", - "extras": [], "workspace": { "root": "[ROOT]/albatross-virtual-workspace", "packages": { @@ -981,7 +952,6 @@ mod tests { { "project_root": "[ROOT]/albatross-just-project", "project_name": "albatross", - "extras": [], "workspace": { "root": "[ROOT]/albatross-just-project", "packages": { diff --git a/crates/uv-resolver/src/lock.rs b/crates/uv-resolver/src/lock.rs index 3177525fd..078db6050 100644 --- a/crates/uv-resolver/src/lock.rs +++ b/crates/uv-resolver/src/lock.rs @@ -24,6 +24,7 @@ use pep440_rs::Version; use pep508_rs::{MarkerEnvironment, MarkerTree, VerbatimUrl}; use platform_tags::{TagCompatibility, TagPriority, Tags}; use pypi_types::{HashDigest, ParsedArchiveUrl, ParsedGitUrl}; +use uv_configuration::ExtrasSpecification; use uv_git::{GitReference, GitSha, RepositoryReference, ResolvedRepositoryReference}; use uv_normalize::{ExtraName, PackageName}; @@ -110,7 +111,7 @@ impl Lock { marker_env: &MarkerEnvironment, tags: &Tags, root_name: &PackageName, - extras: &[ExtraName], + extras: &ExtrasSpecification, ) -> Resolution { let mut queue: VecDeque<(&Distribution, Option<&ExtraName>)> = VecDeque::new(); @@ -119,8 +120,23 @@ impl Lock { .find_by_name(root_name) .expect("found too many distributions matching root") .expect("could not find root"); - for extra in std::iter::once(None).chain(extras.iter().map(Some)) { - queue.push_back((root, extra)); + + // Add the base package. + queue.push_back((root, None)); + + // Add any extras. + match extras { + ExtrasSpecification::None => {} + ExtrasSpecification::All => { + for extra in root.optional_dependencies.keys() { + queue.push_back((root, Some(extra))); + } + } + ExtrasSpecification::Some(extras) => { + for extra in extras { + queue.push_back((root, Some(extra))); + } + } } let mut map = BTreeMap::default(); diff --git a/crates/uv/src/commands/project/sync.rs b/crates/uv/src/commands/project/sync.rs index 06c82e1ce..dede97027 100644 --- a/crates/uv/src/commands/project/sync.rs +++ b/crates/uv/src/commands/project/sync.rs @@ -80,11 +80,6 @@ pub(super) async fn do_sync( let tags = venv.interpreter().tags()?; // Read the lockfile. - let extras = match extras { - ExtrasSpecification::None => vec![], - ExtrasSpecification::All => project.project_extras().to_vec(), - ExtrasSpecification::Some(extras) => extras, - }; let resolution = lock.to_resolution(markers, tags, project.project_name(), &extras); // Initialize the registry client.