Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/uv-client/src/flat_index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ pub enum FlatIndexError {

impl FlatIndexError {
/// Return whether this is an expected user-facing failure.
pub(crate) fn is_user_failure(&self) -> bool {
pub fn is_user_failure(&self) -> bool {
match self {
Self::NonFileUrl(_) => true,
Self::FindLinksFile(_, error) | Self::FindLinksUrl(_, error) => error.is_user_failure(),
Expand Down
2 changes: 1 addition & 1 deletion crates/uv-distribution-types/src/requirement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ impl Requirement {

/// Convert to a [`Requirement`] with an absolute path based on the given root.
#[must_use]
pub fn to_absolute(self, path: &Path) -> Self {
pub(crate) fn into_absolute(self, path: &Path) -> Self {
Self {
source: self.source.into_absolute(path),
..self
Expand Down
30 changes: 27 additions & 3 deletions crates/uv-distribution-types/src/specified_requirement.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::borrow::Cow;
use std::fmt::{Display, Formatter};
use std::io;
use std::path::Path;

use uv_git_types::{GitLfs, GitReference};
use uv_normalize::ExtraName;
Expand All @@ -8,16 +10,38 @@ use uv_pypi_types::{Hashes, ParsedUrl};

use crate::{Requirement, RequirementSource, VerbatimParsedUrl};

/// An [`UnresolvedRequirement`] with additional metadata from `requirements.txt`, currently only
/// hashes but in the future also editable and similar information.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
/// A named requirement with hashes from `requirements.txt` or `pyproject.toml`.
#[derive(
Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, serde::Serialize, serde::Deserialize,
)]
pub struct NameRequirementSpecification {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason it's named NameRequirementSpecification? It looks more like RequirmentWithHashes.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree but this was preexisting and didn't want to change it in this PR. I can followup

/// The actual requirement.
#[serde(flatten)]
pub requirement: Requirement,
Comment thread
zsol marked this conversation as resolved.
/// Hashes of the downloadable packages.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub hashes: Vec<String>,
}

impl NameRequirementSpecification {
/// Make the requirement's path relative to the given root.
pub fn relative_to(self, root: &Path) -> Result<Self, io::Error> {
Ok(Self {
requirement: self.requirement.relative_to(root)?,
hashes: self.hashes,
})
}

/// Make the requirement's path absolute based on the given root.
#[must_use]
pub fn into_absolute(self, root: &Path) -> Self {
Self {
requirement: self.requirement.into_absolute(root),
hashes: self.hashes,
}
}
}

/// An [`UnresolvedRequirement`] with additional metadata from `requirements.txt`, currently only
/// hashes but in the future also editable and similar information.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
Expand Down
4 changes: 4 additions & 0 deletions crates/uv-requirements/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ pub enum Error {
#[error(transparent)]
HashStrategy(#[from] uv_types::HashStrategyError),

#[error(transparent)]
FlatIndex(#[from] Box<uv_client::FlatIndexError>),

#[error(transparent)]
WheelFilename(#[from] uv_distribution_filename::WheelFilenameError),

Expand All @@ -49,6 +52,7 @@ impl Error {
pub fn is_user_failure(&self) -> bool {
match self {
Self::Dist(_, _, error) | Self::Distribution(error) => error.is_user_failure(),
Self::FlatIndex(error) => error.is_user_failure(),
Self::DistributionTypes(_) | Self::HashStrategy(_) | Self::WheelFilename(_) => true,
Self::Io(error) => matches!(
error.kind(),
Expand Down
39 changes: 26 additions & 13 deletions crates/uv-resolver/src/lock/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ use uv_distribution_types::{
ArchiveHashPolicy, BuiltDist, DependencyMetadata, DirectUrlBuiltDist, DirectUrlSourceDist,
DirectorySourceDist, Dist, FileLocation, FirstParty, GitDirectorySourceDist, GitPathBuiltDist,
GitPathSourceDist, HashValidation, Identifier, IndexLocations, IndexMetadata, IndexUrl,
MetadataHashPolicy, Name, PYPI_URL, PathBuiltDist, PathSourceDist, RegistryBuiltDist,
RegistryBuiltWheel, RegistrySourceDist, RemoteSource, Requirement, RequirementSource,
RequiresPython, ResolvedDist, SimplifiedMarkerTree, StaticMetadata, ToUrlError, UrlString,
VersionId,
MetadataHashPolicy, Name, NameRequirementSpecification, PYPI_URL, PathBuiltDist,
PathSourceDist, RegistryBuiltDist, RegistryBuiltWheel, RegistrySourceDist, RemoteSource,
Requirement, RequirementSource, RequiresPython, ResolvedDist, SimplifiedMarkerTree,
StaticMetadata, ToUrlError, UrlString, VersionId,
};
use uv_fs::{PortablePath, PortablePathBuf, Simplified, normalize_path, try_relative_to_if};
use uv_git::{RepositoryReference, ResolvedRepositoryReference};
Expand Down Expand Up @@ -1741,12 +1741,12 @@ impl Lock {

/// Returns the build constraints that were used to generate this lock.
pub fn build_constraints(&self, root: &Path) -> Constraints {
Constraints::from_requirements(
Constraints::from_specifications(
self.manifest
.build_constraints
.iter()
.cloned()
.map(|requirement| requirement.to_absolute(root)),
.map(|requirement| requirement.into_absolute(root)),
)
}

Expand Down Expand Up @@ -2422,7 +2422,7 @@ impl Lock {
constraints: &[Requirement],
overrides: &[Override<Requirement>],
excludes: &[ExcludeDependency],
build_constraints: &[Requirement],
build_constraints: &Constraints,
dependency_groups: &BTreeMap<GroupName, Vec<Requirement>>,
dependency_metadata: &DependencyMetadata,
indexes: Option<&IndexLocations>,
Expand Down Expand Up @@ -2611,17 +2611,27 @@ impl Lock {

// Validate that the lockfile was generated with the same build constraints.
{
let normalize_build_constraint = |constraint: NameRequirementSpecification| {
Ok::<_, LockError>(NameRequirementSpecification {
requirement: normalize_requirement(
constraint.requirement,
root,
&self.requires_python,
)?,
hashes: constraint.hashes,
})
};
let expected: BTreeSet<_> = build_constraints
.iter()
.specifications()
.cloned()
.map(|requirement| normalize_requirement(requirement, root, &self.requires_python))
.map(normalize_build_constraint)
.collect::<Result<_, _>>()?;
let actual: BTreeSet<_> = self
.manifest
.build_constraints
.iter()
.cloned()
.map(|requirement| normalize_requirement(requirement, root, &self.requires_python))
.map(normalize_build_constraint)
.collect::<Result<_, _>>()?;
if expected != actual {
return Ok(SatisfiesResult::MismatchedBuildConstraints(
Expand Down Expand Up @@ -3492,7 +3502,10 @@ pub enum SatisfiesResult<'lock> {
/// The lockfile uses a different set of excludes.
MismatchedExcludes(BTreeSet<ExcludeDependency>, BTreeSet<ExcludeDependency>),
/// The lockfile uses a different set of build constraints.
MismatchedBuildConstraints(BTreeSet<Requirement>, BTreeSet<Requirement>),
MismatchedBuildConstraints(
BTreeSet<NameRequirementSpecification>,
BTreeSet<NameRequirementSpecification>,
),
/// The lockfile uses a different set of dependency groups.
MismatchedDependencyGroups(
BTreeMap<GroupName, BTreeSet<Requirement>>,
Expand Down Expand Up @@ -3661,7 +3674,7 @@ pub struct ResolverManifest {
excludes: BTreeSet<ExcludeDependency>,
/// The build constraints provided to the resolver.
#[serde(default)]
build_constraints: BTreeSet<Requirement>,
build_constraints: BTreeSet<NameRequirementSpecification>,
/// The static metadata provided to the resolver.
#[serde(default)]
dependency_metadata: BTreeSet<StaticMetadata>,
Expand All @@ -3676,7 +3689,7 @@ impl ResolverManifest {
constraints: impl IntoIterator<Item = Requirement>,
overrides: impl IntoIterator<Item = Override<Requirement>>,
excludes: impl IntoIterator<Item = ExcludeDependency>,
build_constraints: impl IntoIterator<Item = Requirement>,
build_constraints: impl IntoIterator<Item = NameRequirementSpecification>,
dependency_groups: impl IntoIterator<Item = (GroupName, Vec<Requirement>)>,
dependency_metadata: impl IntoIterator<Item = StaticMetadata>,
) -> Self {
Expand Down
4 changes: 2 additions & 2 deletions crates/uv-scripts/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use uv_pypi_types::VerbatimParsedUrl;
use uv_redacted::DisplaySafeUrl;
use uv_settings::{GlobalOptions, ResolverInstallerSchema};
use uv_warnings::warn_user;
use uv_workspace::pyproject::{ExtraBuildDependency, Sources};
use uv_workspace::pyproject::{BuildConstraintDependency, ExtraBuildDependency, Sources};

pub use uv_configuration::ExcludeDependency;
pub use uv_workspace::pyproject::OverrideDependency;
Expand Down Expand Up @@ -428,7 +428,7 @@ pub struct ToolUv {
pub override_dependencies: Option<Vec<OverrideDependency>>,
pub exclude_dependencies: Option<Vec<ExcludeDependency>>,
pub constraint_dependencies: Option<Vec<uv_pep508::Requirement<VerbatimParsedUrl>>>,
pub build_constraint_dependencies: Option<Vec<uv_pep508::Requirement<VerbatimParsedUrl>>>,
pub build_constraint_dependencies: Option<Vec<BuildConstraintDependency>>,
pub extra_build_dependencies: Option<BTreeMap<PackageName, Vec<ExtraBuildDependency>>>,
pub sources: Option<BTreeMap<PackageName, Sources>>,
}
Expand Down
8 changes: 5 additions & 3 deletions crates/uv-settings/src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ use uv_resolver::{
serialize_exclude_newer_package_with_spans,
};
use uv_torch::TorchMode;
use uv_workspace::pyproject::{ExtraBuildDependencies, OverrideDependency};
use uv_workspace::pyproject::{
BuildConstraintDependency, ExtraBuildDependencies, OverrideDependency,
};
use uv_workspace::pyproject_mut::AddBoundsKind;

use crate::{EnvironmentOptions, FilesystemOptions};
Expand Down Expand Up @@ -157,7 +159,7 @@ pub struct Options {
pub constraint_dependencies: Option<Vec<Requirement<VerbatimParsedUrl>>>,

#[cfg_attr(feature = "schemars", schemars(skip))]
pub build_constraint_dependencies: Option<Vec<Requirement<VerbatimParsedUrl>>>,
pub build_constraint_dependencies: Option<Vec<BuildConstraintDependency>>,

#[cfg_attr(feature = "schemars", schemars(skip))]
pub environments: Option<SupportedEnvironments>,
Expand Down Expand Up @@ -2635,7 +2637,7 @@ struct OptionsWire {
override_dependencies: Option<Vec<OverrideDependency>>,
exclude_dependencies: Option<Vec<ExcludeDependency>>,
constraint_dependencies: Option<Vec<Requirement<VerbatimParsedUrl>>>,
build_constraint_dependencies: Option<Vec<Requirement<VerbatimParsedUrl>>>,
build_constraint_dependencies: Option<Vec<BuildConstraintDependency>>,
environments: Option<SupportedEnvironments>,
required_environments: Option<SupportedEnvironments>,

Expand Down
10 changes: 5 additions & 5 deletions crates/uv-tool/src/tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use serde::Deserialize;
use toml_edit::{Array, Item, Table, Value, value};

use uv_configuration::ExcludeDependency;
use uv_distribution_types::Requirement;
use uv_distribution_types::{NameRequirementSpecification, Requirement};
use uv_fs::{PortablePath, Simplified};
use uv_pypi_types::VerbatimParsedUrl;
use uv_python::PythonRequest;
Expand All @@ -27,7 +27,7 @@ pub struct Tool {
/// The excludes requested by the user during installation.
excludes: Vec<ExcludeDependency>,
/// The build constraints requested by the user during installation.
build_constraints: Vec<Requirement>,
build_constraints: Vec<NameRequirementSpecification>,
/// The Python requested by the user during installation.
python: Option<PythonRequest>,
/// A mapping of entry point names to their metadata.
Expand All @@ -48,7 +48,7 @@ struct ToolWire {
#[serde(default)]
excludes: Vec<ExcludeDependency>,
#[serde(default)]
build_constraint_dependencies: Vec<Requirement>,
build_constraint_dependencies: Vec<NameRequirementSpecification>,
python: Option<PythonRequest>,
entrypoints: Vec<ToolEntrypoint>,
#[serde(default)]
Expand Down Expand Up @@ -176,7 +176,7 @@ impl Tool {
constraints: Vec<Requirement>,
overrides: Vec<Requirement>,
excludes: Vec<ExcludeDependency>,
build_constraints: Vec<Requirement>,
build_constraints: Vec<NameRequirementSpecification>,
python: Option<PythonRequest>,
entrypoints: impl IntoIterator<Item = ToolEntrypoint>,
options: ToolOptions,
Expand Down Expand Up @@ -371,7 +371,7 @@ impl Tool {
&self.excludes
}

pub fn build_constraints(&self) -> &[Requirement] {
pub fn build_constraints(&self) -> &[NameRequirementSpecification] {
&self.build_constraints
}

Expand Down
Loading
Loading