Skip to content

Commit

Permalink
Respect sources in overrides and constraints
Browse files Browse the repository at this point in the history
  • Loading branch information
charliermarsh committed Nov 27, 2024
1 parent 2534156 commit e25d122
Show file tree
Hide file tree
Showing 11 changed files with 413 additions and 117 deletions.
36 changes: 15 additions & 21 deletions crates/uv-build-frontend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -465,13 +465,12 @@ impl SourceBuild {
.or(package_name)
{
let build_requires = uv_pypi_types::BuildRequires {
name: name.clone(),
name: Some(name.clone()),
requires_dist: build_system.requires,
};
let build_requires = BuildRequires::from_project_maybe_workspace(
build_requires,
install_path,
None,
locations,
source_strategy,
LowerBound::Allow,
Expand Down Expand Up @@ -905,25 +904,20 @@ async fn create_pep517_build_environment(
// If necessary, lower the requirements.
let extra_requires = match source_strategy {
SourceStrategy::Enabled => {
if let Some(package_name) = package_name {
let build_requires = uv_pypi_types::BuildRequires {
name: package_name.clone(),
requires_dist: extra_requires,
};
let build_requires = BuildRequires::from_project_maybe_workspace(
build_requires,
install_path,
None,
locations,
source_strategy,
LowerBound::Allow,
)
.await
.map_err(Error::Lowering)?;
build_requires.requires_dist
} else {
extra_requires.into_iter().map(Requirement::from).collect()
}
let build_requires = uv_pypi_types::BuildRequires {
name: package_name.cloned(),
requires_dist: extra_requires,
};
let build_requires = BuildRequires::from_project_maybe_workspace(
build_requires,
install_path,
locations,
source_strategy,
LowerBound::Allow,
)
.await
.map_err(Error::Lowering)?;
build_requires.requires_dist
}
SourceStrategy::Disabled => extra_requires.into_iter().map(Requirement::from).collect(),
};
Expand Down
108 changes: 85 additions & 23 deletions crates/uv-distribution/src/metadata/build_requires.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ use uv_configuration::{LowerBound, SourceStrategy};
use uv_distribution_types::IndexLocations;
use uv_normalize::PackageName;
use uv_workspace::pyproject::ToolUvSources;
use uv_workspace::{DiscoveryOptions, ProjectWorkspace};
use uv_workspace::{DiscoveryOptions, ProjectWorkspace, Workspace};

use crate::metadata::{GitWorkspaceMember, LoweredRequirement, MetadataError};
use crate::metadata::{LoweredRequirement, MetadataError};

/// Lowered requirements from a `[build-system.requires]` field in a `pyproject.toml` file.
#[derive(Debug, Clone)]
pub struct BuildRequires {
pub name: PackageName,
pub name: Option<PackageName>,
pub requires_dist: Vec<uv_pypi_types::Requirement>,
}

Expand All @@ -35,46 +35,31 @@ impl BuildRequires {
pub async fn from_project_maybe_workspace(
metadata: uv_pypi_types::BuildRequires,
install_path: &Path,
git_member: Option<&GitWorkspaceMember<'_>>,
locations: &IndexLocations,
sources: SourceStrategy,
lower_bound: LowerBound,
) -> Result<Self, MetadataError> {
// TODO(konsti): Cache workspace discovery.
let discovery_options = if let Some(git_member) = &git_member {
DiscoveryOptions {
stop_discovery_at: Some(
git_member
.fetch_root
.parent()
.expect("git checkout has a parent"),
),
..Default::default()
}
} else {
DiscoveryOptions::default()
};
let Some(project_workspace) =
ProjectWorkspace::from_maybe_project_root(install_path, &discovery_options).await?
ProjectWorkspace::from_maybe_project_root(install_path, &DiscoveryOptions::default())
.await?
else {
return Ok(Self::from_metadata23(metadata));
};

Self::from_project_workspace(
metadata,
&project_workspace,
git_member,
locations,
sources,
lower_bound,
)
}

/// Lower the `build-system.requires` field from a `pyproject.toml` file.
fn from_project_workspace(
pub fn from_project_workspace(
metadata: uv_pypi_types::BuildRequires,
project_workspace: &ProjectWorkspace,
git_member: Option<&GitWorkspaceMember<'_>>,
locations: &IndexLocations,
source_strategy: SourceStrategy,
lower_bound: LowerBound,
Expand Down Expand Up @@ -118,7 +103,7 @@ impl BuildRequires {
let group = None;
LoweredRequirement::from_requirement(
requirement,
&metadata.name,
metadata.name.as_ref(),
project_workspace.project_root(),
project_sources,
project_indexes,
Expand All @@ -127,7 +112,84 @@ impl BuildRequires {
locations,
project_workspace.workspace(),
lower_bound,
git_member,
None,
)
.map(move |requirement| match requirement {
Ok(requirement) => Ok(requirement.into_inner()),
Err(err) => Err(MetadataError::LoweringError(
requirement_name.clone(),
Box::new(err),
)),
})
})
.collect::<Result<Vec<_>, _>>()?,
SourceStrategy::Disabled => requires_dist
.into_iter()
.map(uv_pypi_types::Requirement::from)
.collect(),
};

Ok(Self {
name: metadata.name,
requires_dist,
})
}

/// Lower the `build-system.requires` field from a `pyproject.toml` file.
pub fn from_workspace(
metadata: uv_pypi_types::BuildRequires,
workspace: &Workspace,
locations: &IndexLocations,
source_strategy: SourceStrategy,
lower_bound: LowerBound,
) -> Result<Self, MetadataError> {
// Collect any `tool.uv.index` entries.
let empty = vec![];
let project_indexes = match source_strategy {
SourceStrategy::Enabled => workspace
.pyproject_toml()
.tool
.as_ref()
.and_then(|tool| tool.uv.as_ref())
.and_then(|uv| uv.index.as_deref())
.unwrap_or(&empty),
SourceStrategy::Disabled => &empty,
};

// Collect any `tool.uv.sources` and `tool.uv.dev_dependencies` from `pyproject.toml`.
let empty = BTreeMap::default();
let project_sources = match source_strategy {
SourceStrategy::Enabled => workspace
.pyproject_toml()
.tool
.as_ref()
.and_then(|tool| tool.uv.as_ref())
.and_then(|uv| uv.sources.as_ref())
.map(ToolUvSources::inner)
.unwrap_or(&empty),
SourceStrategy::Disabled => &empty,
};

// Lower the requirements.
let requires_dist = metadata.requires_dist.into_iter();
let requires_dist = match source_strategy {
SourceStrategy::Enabled => requires_dist
.flat_map(|requirement| {
let requirement_name = requirement.name.clone();
let extra = requirement.marker.top_level_extra_name();
let group = None;
LoweredRequirement::from_requirement(
requirement,
None,
workspace.install_path(),
project_sources,
project_indexes,
extra.as_ref(),
group,
locations,
workspace,
lower_bound,
None,
)
.map(move |requirement| match requirement {
Ok(requirement) => Ok(requirement.into_inner()),
Expand Down
20 changes: 12 additions & 8 deletions crates/uv-distribution/src/metadata/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ impl LoweredRequirement {
/// Combine `project.dependencies` or `project.optional-dependencies` with `tool.uv.sources`.
pub(crate) fn from_requirement<'data>(
requirement: uv_pep508::Requirement<VerbatimParsedUrl>,
project_name: &'data PackageName,
project_name: Option<&'data PackageName>,
project_dir: &'data Path,
project_sources: &'data BTreeMap<PackageName, Sources>,
project_indexes: &'data [Index],
Expand Down Expand Up @@ -89,7 +89,7 @@ impl LoweredRequirement {
}))
// ... except for recursive self-inclusion (extras that activate other extras), e.g.
// `framework[machine_learning]` depends on `framework[cuda]`.
|| &requirement.name == project_name;
|| project_name.is_some_and(|project_name| *project_name == requirement.name);
if !workspace_package_declared {
return Either::Left(std::iter::once(Err(
LoweringError::UndeclaredWorkspacePackage,
Expand All @@ -102,7 +102,7 @@ impl LoweredRequirement {
// Support recursive editable inclusions.
if has_sources
&& requirement.version_or_url.is_none()
&& &requirement.name != project_name
&& !project_name.is_some_and(|project_name| *project_name == requirement.name)
{
warn_user_once!(
"Missing version constraint (e.g., a lower bound) for `{}`",
Expand Down Expand Up @@ -211,11 +211,15 @@ impl LoweredRequirement {
index,
));
};
let conflict = if let Some(extra) = extra {
Some(ConflictItem::from((project_name.clone(), extra)))
} else {
group.map(|group| ConflictItem::from((project_name.clone(), group)))
};
let conflict = project_name.and_then(|project_name| {
if let Some(extra) = extra {
Some(ConflictItem::from((project_name.clone(), extra)))
} else {
group.map(|group| {
ConflictItem::from((project_name.clone(), group))
})
}
});
let source = registry_source(
&requirement,
index.into_url(),
Expand Down
9 changes: 5 additions & 4 deletions crates/uv-distribution/src/metadata/requires_dist.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
use std::collections::BTreeMap;
use std::path::Path;

use crate::metadata::{GitWorkspaceMember, LoweredRequirement, MetadataError};
use crate::Metadata;
use uv_configuration::{LowerBound, SourceStrategy};
use uv_distribution_types::IndexLocations;
use uv_normalize::{ExtraName, GroupName, PackageName, DEV_DEPENDENCIES};
use uv_workspace::dependency_groups::FlatDependencyGroups;
use uv_workspace::pyproject::{Sources, ToolUvSources};
use uv_workspace::{DiscoveryOptions, ProjectWorkspace};

use crate::metadata::{GitWorkspaceMember, LoweredRequirement, MetadataError};
use crate::Metadata;

#[derive(Debug, Clone)]
pub struct RequiresDist {
pub name: PackageName,
Expand Down Expand Up @@ -164,7 +165,7 @@ impl RequiresDist {
let extra = None;
LoweredRequirement::from_requirement(
requirement,
&metadata.name,
Some(&metadata.name),
project_workspace.project_root(),
project_sources,
project_indexes,
Expand Down Expand Up @@ -209,7 +210,7 @@ impl RequiresDist {
let group = None;
LoweredRequirement::from_requirement(
requirement,
&metadata.name,
Some(&metadata.name),
project_workspace.project_root(),
project_sources,
project_indexes,
Expand Down
2 changes: 1 addition & 1 deletion crates/uv-pypi-types/src/metadata/build_requires.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ use crate::VerbatimParsedUrl;
/// See: <https://peps.python.org/pep-0518/>
#[derive(Debug, Clone)]
pub struct BuildRequires {
pub name: PackageName,
pub name: Option<PackageName>,
pub requires_dist: Vec<Requirement<VerbatimParsedUrl>>,
}
9 changes: 9 additions & 0 deletions crates/uv-pypi-types/src/requirement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,15 @@ impl Requirement {
let fragment = url.fragment()?;
Hashes::parse_fragment(fragment).ok()
}

/// Set the source file containing the requirement.
#[must_use]
pub fn with_origin(self, origin: RequirementOrigin) -> Self {
Self {
origin: Some(origin),
..self
}
}
}

impl From<Requirement> for uv_pep508::Requirement<VerbatimUrl> {
Expand Down
Loading

0 comments on commit e25d122

Please sign in to comment.