diff --git a/Cargo.lock b/Cargo.lock index 2b201444a..4ea2888ef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4786,6 +4786,7 @@ version = "0.0.1" dependencies = [ "anyhow", "distribution-types", + "itertools 0.12.1", "once-map", "pep508_rs", "rustc-hash", diff --git a/crates/uv-resolver/src/lib.rs b/crates/uv-resolver/src/lib.rs index bf2cd8aa8..129bbac3e 100644 --- a/crates/uv-resolver/src/lib.rs +++ b/crates/uv-resolver/src/lib.rs @@ -18,7 +18,7 @@ pub use yanks::AllowedYanks; mod bare; mod candidate_selector; -mod constraints; + mod dependency_mode; mod dependency_provider; mod editables; @@ -26,7 +26,6 @@ mod error; mod exclusions; mod manifest; mod options; -mod overrides; mod pins; mod preferences; mod prerelease_mode; diff --git a/crates/uv-resolver/src/manifest.rs b/crates/uv-resolver/src/manifest.rs index 9ef09b1eb..b319682c7 100644 --- a/crates/uv-resolver/src/manifest.rs +++ b/crates/uv-resolver/src/manifest.rs @@ -2,7 +2,7 @@ use distribution_types::LocalEditable; use pep508_rs::{MarkerEnvironment, Requirement}; use pypi_types::Metadata23; use uv_normalize::PackageName; -use uv_types::RequestedRequirements; +use uv_types::{Constraints, Overrides, RequestedRequirements}; use crate::{preferences::Preference, Exclusions}; @@ -13,10 +13,10 @@ pub struct Manifest { pub(crate) requirements: Vec, /// The constraints for the project. - pub(crate) constraints: Vec, + pub(crate) constraints: Constraints, /// The overrides for the project. - pub(crate) overrides: Vec, + pub(crate) overrides: Overrides, /// The preferences for the project. /// @@ -52,8 +52,8 @@ impl Manifest { #[allow(clippy::too_many_arguments)] pub fn new( requirements: Vec, - constraints: Vec, - overrides: Vec, + constraints: Constraints, + overrides: Overrides, preferences: Vec, project: Option, editables: Vec<(LocalEditable, Metadata23)>, @@ -75,8 +75,8 @@ impl Manifest { pub fn simple(requirements: Vec) -> Self { Self { requirements, - constraints: Vec::new(), - overrides: Vec::new(), + constraints: Constraints::default(), + overrides: Overrides::default(), preferences: Vec::new(), project: None, editables: Vec::new(), @@ -118,12 +118,12 @@ impl Manifest { ) .chain( self.constraints - .iter() + .requirements() .filter(|requirement| requirement.evaluate_markers(markers, &[])), ) .chain( self.overrides - .iter() + .requirements() .filter(|requirement| requirement.evaluate_markers(markers, &[])), ) } diff --git a/crates/uv-resolver/src/pubgrub/dependencies.rs b/crates/uv-resolver/src/pubgrub/dependencies.rs index 97de05b40..8960dea9c 100644 --- a/crates/uv-resolver/src/pubgrub/dependencies.rs +++ b/crates/uv-resolver/src/pubgrub/dependencies.rs @@ -6,9 +6,8 @@ use distribution_types::Verbatim; use pep440_rs::Version; use pep508_rs::{MarkerEnvironment, Requirement, VersionOrUrl}; use uv_normalize::{ExtraName, PackageName}; +use uv_types::{Constraints, Overrides}; -use crate::constraints::Constraints; -use crate::overrides::Overrides; use crate::pubgrub::specifier::PubGrubSpecifier; use crate::pubgrub::PubGrubPackage; use crate::resolver::{Locals, Urls}; diff --git a/crates/uv-resolver/src/resolution.rs b/crates/uv-resolver/src/resolution.rs index 6d2870c1e..9c4e93f00 100644 --- a/crates/uv-resolver/src/resolution.rs +++ b/crates/uv-resolver/src/resolution.rs @@ -431,8 +431,8 @@ impl ResolutionGraph { let direct_reqs = manifest .requirements .iter() - .chain(&manifest.constraints) - .chain(&manifest.overrides); + .chain(manifest.constraints.requirements()) + .chain(manifest.overrides.requirements()); for direct_req in direct_reqs { let Some(ref marker_tree) = direct_req.marker else { continue; diff --git a/crates/uv-resolver/src/resolver/mod.rs b/crates/uv-resolver/src/resolver/mod.rs index b5e2d1cd8..d128dca0a 100644 --- a/crates/uv-resolver/src/resolver/mod.rs +++ b/crates/uv-resolver/src/resolver/mod.rs @@ -31,14 +31,13 @@ use uv_client::{FlatIndex, RegistryClient}; use uv_distribution::DistributionDatabase; use uv_interpreter::Interpreter; use uv_normalize::PackageName; -use uv_types::{BuildContext, InstalledPackagesProvider}; +use uv_types::{BuildContext, Constraints, InstalledPackagesProvider, Overrides}; use crate::candidate_selector::{CandidateDist, CandidateSelector}; -use crate::constraints::Constraints; + use crate::editables::Editables; use crate::error::ResolveError; use crate::manifest::Manifest; -use crate::overrides::Overrides; use crate::pins::FilePins; use crate::preferences::Preferences; use crate::pubgrub::{ @@ -188,8 +187,8 @@ impl< locals: Locals::from_manifest(&manifest, markers), project: manifest.project, requirements: manifest.requirements, - constraints: Constraints::from_requirements(manifest.constraints), - overrides: Overrides::from_requirements(manifest.overrides), + constraints: manifest.constraints, + overrides: manifest.overrides, preferences: Preferences::from_iter(manifest.preferences, markers), exclusions: manifest.exclusions, editables: Editables::from_requirements(manifest.editables), diff --git a/crates/uv-resolver/src/resolver/urls.rs b/crates/uv-resolver/src/resolver/urls.rs index fa7f8e6a0..a046dc558 100644 --- a/crates/uv-resolver/src/resolver/urls.rs +++ b/crates/uv-resolver/src/resolver/urls.rs @@ -53,7 +53,7 @@ impl Urls { for requirement in manifest .requirements .iter() - .chain(manifest.constraints.iter()) + .chain(manifest.constraints.requirements()) .filter(|requirement| requirement.evaluate_markers(markers, &[])) { if let Some(pep508_rs::VersionOrUrl::Url(url)) = &requirement.version_or_url { @@ -125,7 +125,7 @@ impl Urls { // authoritative. for requirement in manifest .overrides - .iter() + .requirements() .filter(|requirement| requirement.evaluate_markers(markers, &[])) { if let Some(pep508_rs::VersionOrUrl::Url(url)) = &requirement.version_or_url { diff --git a/crates/uv-resolver/src/yanks.rs b/crates/uv-resolver/src/yanks.rs index 2ebb6f125..f8e12317d 100644 --- a/crates/uv-resolver/src/yanks.rs +++ b/crates/uv-resolver/src/yanks.rs @@ -14,6 +14,7 @@ pub struct AllowedYanks(FxHashMap>); impl AllowedYanks { pub fn from_manifest(manifest: &Manifest, markers: &MarkerEnvironment) -> Self { let mut allowed_yanks = FxHashMap::>::default(); + for requirement in manifest .requirements(markers) .chain(manifest.preferences.iter().map(Preference::requirement)) diff --git a/crates/uv-resolver/tests/resolver.rs b/crates/uv-resolver/tests/resolver.rs index b053cc4e1..3fc94d237 100644 --- a/crates/uv-resolver/tests/resolver.rs +++ b/crates/uv-resolver/tests/resolver.rs @@ -21,8 +21,8 @@ use uv_resolver::{ PreReleaseMode, Preference, ResolutionGraph, ResolutionMode, Resolver, }; use uv_types::{ - BuildContext, BuildIsolation, BuildKind, EmptyInstalledPackages, NoBinary, NoBuild, - SetupPyStrategy, SourceBuildTrait, + BuildContext, BuildIsolation, BuildKind, Constraints, EmptyInstalledPackages, NoBinary, + NoBuild, Overrides, SetupPyStrategy, SourceBuildTrait, }; // Exclude any packages uploaded after this date. @@ -269,8 +269,10 @@ async fn black_python_310() -> Result<()> { async fn black_mypy_extensions() -> Result<()> { let manifest = Manifest::new( vec![Requirement::from_str("black<=23.9.1").unwrap()], - vec![Requirement::from_str("mypy-extensions<0.4.4").unwrap()], - vec![], + Constraints::from_requirements(vec![ + Requirement::from_str("mypy-extensions<0.4.4").unwrap() + ]), + Overrides::default(), vec![], None, vec![], @@ -306,8 +308,10 @@ async fn black_mypy_extensions() -> Result<()> { async fn black_mypy_extensions_extra() -> Result<()> { let manifest = Manifest::new( vec![Requirement::from_str("black<=23.9.1").unwrap()], - vec![Requirement::from_str("mypy-extensions[extra]<0.4.4").unwrap()], - vec![], + Constraints::from_requirements(vec![ + Requirement::from_str("mypy-extensions[extra]<0.4.4").unwrap() + ]), + Overrides::default(), vec![], None, vec![], @@ -343,8 +347,8 @@ async fn black_mypy_extensions_extra() -> Result<()> { async fn black_flake8() -> Result<()> { let manifest = Manifest::new( vec![Requirement::from_str("black<=23.9.1").unwrap()], - vec![Requirement::from_str("flake8<1").unwrap()], - vec![], + Constraints::from_requirements(vec![Requirement::from_str("flake8<1").unwrap()]), + Overrides::default(), vec![], None, vec![], @@ -432,8 +436,8 @@ async fn black_lowest_direct() -> Result<()> { async fn black_respect_preference() -> Result<()> { let manifest = Manifest::new( vec![Requirement::from_str("black<=23.9.1")?], - vec![], - vec![], + Constraints::default(), + Overrides::default(), vec![Preference::from_requirement(Requirement::from_str( "black==23.9.0", )?)], @@ -470,8 +474,8 @@ async fn black_respect_preference() -> Result<()> { async fn black_ignore_preference() -> Result<()> { let manifest = Manifest::new( vec![Requirement::from_str("black<=23.9.1")?], - vec![], - vec![], + Constraints::default(), + Overrides::default(), vec![Preference::from_requirement(Requirement::from_str( "black==23.9.2", )?)], diff --git a/crates/uv-types/Cargo.toml b/crates/uv-types/Cargo.toml index 7822cc1f6..e6210fb49 100644 --- a/crates/uv-types/Cargo.toml +++ b/crates/uv-types/Cargo.toml @@ -21,6 +21,7 @@ uv-interpreter = { workspace = true } uv-normalize = { workspace = true } anyhow = { workspace = true } +itertools = { workspace = true } rustc-hash = { workspace = true } serde = { workspace = true, optional = true } serde_json = { workspace = true, optional = true } diff --git a/crates/uv-resolver/src/constraints.rs b/crates/uv-types/src/constraints.rs similarity index 63% rename from crates/uv-resolver/src/constraints.rs rename to crates/uv-types/src/constraints.rs index 6076f17fb..76e89816e 100644 --- a/crates/uv-resolver/src/constraints.rs +++ b/crates/uv-types/src/constraints.rs @@ -7,11 +7,11 @@ use uv_normalize::PackageName; /// A set of constraints for a set of requirements. #[derive(Debug, Default, Clone)] -pub(crate) struct Constraints(FxHashMap>); +pub struct Constraints(FxHashMap>); impl Constraints { /// Create a new set of constraints from a set of requirements. - pub(crate) fn from_requirements(requirements: Vec) -> Self { + pub fn from_requirements(requirements: Vec) -> Self { let mut constraints: FxHashMap> = FxHashMap::with_capacity_and_hasher(requirements.len(), BuildHasherDefault::default()); for requirement in requirements { @@ -23,8 +23,13 @@ impl Constraints { Self(constraints) } + /// Return an iterator over all [`Requirement`]s in the constraint set. + pub fn requirements(&self) -> impl Iterator { + self.0.values().flat_map(|requirements| requirements.iter()) + } + /// Get the constraints for a package. - pub(crate) fn get(&self, name: &PackageName) -> Option<&Vec> { + pub fn get(&self, name: &PackageName) -> Option<&Vec> { self.0.get(name) } } diff --git a/crates/uv-types/src/lib.rs b/crates/uv-types/src/lib.rs index c729393c4..40a0edc0a 100644 --- a/crates/uv-types/src/lib.rs +++ b/crates/uv-types/src/lib.rs @@ -1,16 +1,20 @@ //! Fundamental types shared across `uv` crates. pub use build_options::*; pub use config_settings::*; +pub use constraints::*; pub use downloads::*; pub use name_specifiers::*; +pub use overrides::*; pub use package_options::*; pub use requirements::*; pub use traits::*; mod build_options; mod config_settings; +mod constraints; mod downloads; mod name_specifiers; +mod overrides; mod package_options; mod requirements; mod traits; diff --git a/crates/uv-resolver/src/overrides.rs b/crates/uv-types/src/overrides.rs similarity index 72% rename from crates/uv-resolver/src/overrides.rs rename to crates/uv-types/src/overrides.rs index e018d5069..07d93b133 100644 --- a/crates/uv-resolver/src/overrides.rs +++ b/crates/uv-types/src/overrides.rs @@ -8,11 +8,11 @@ use uv_normalize::PackageName; /// A set of overrides for a set of requirements. #[derive(Debug, Default, Clone)] -pub(crate) struct Overrides(FxHashMap>); +pub struct Overrides(FxHashMap>); impl Overrides { /// Create a new set of overrides from a set of requirements. - pub(crate) fn from_requirements(requirements: Vec) -> Self { + pub fn from_requirements(requirements: Vec) -> Self { let mut overrides: FxHashMap> = FxHashMap::with_capacity_and_hasher(requirements.len(), BuildHasherDefault::default()); for requirement in requirements { @@ -24,13 +24,18 @@ impl Overrides { Self(overrides) } + /// Return an iterator over all [`Requirement`]s in the override set. + pub fn requirements(&self) -> impl Iterator { + self.0.values().flat_map(|requirements| requirements.iter()) + } + /// Get the overrides for a package. - pub(crate) fn get(&self, name: &PackageName) -> Option<&Vec> { + pub fn get(&self, name: &PackageName) -> Option<&Vec> { self.0.get(name) } /// Apply the overrides to a set of requirements. - pub(crate) fn apply<'a>( + pub fn apply<'a>( &'a self, requirements: &'a [Requirement], ) -> impl Iterator { diff --git a/crates/uv/src/commands/pip_compile.rs b/crates/uv/src/commands/pip_compile.rs index 320addcd8..0b2a57db2 100644 --- a/crates/uv/src/commands/pip_compile.rs +++ b/crates/uv/src/commands/pip_compile.rs @@ -36,8 +36,8 @@ use uv_resolver::{ OptionsBuilder, PreReleaseMode, PythonRequirement, ResolutionMode, Resolver, }; use uv_types::{ - BuildIsolation, ConfigSettings, EmptyInstalledPackages, InFlight, NoBinary, NoBuild, - SetupPyStrategy, Upgrade, + BuildIsolation, ConfigSettings, Constraints, EmptyInstalledPackages, InFlight, NoBinary, + NoBuild, Overrides, SetupPyStrategy, Upgrade, }; use uv_warnings::warn_user; @@ -218,6 +218,10 @@ pub(crate) async fn pip_compile( // Read the lockfile, if present. let preferences = read_lockfile(output_file, upgrade).await?; + // Collect constraints and overrides. + let constraints = Constraints::from_requirements(constraints); + let overrides = Overrides::from_requirements(overrides); + // Resolve the flat indexes from `--find-links`. let flat_index = { let client = FlatIndexClient::new(&client, &cache); diff --git a/crates/uv/src/commands/pip_install.rs b/crates/uv/src/commands/pip_install.rs index 135933a0a..0eb81d1cd 100644 --- a/crates/uv/src/commands/pip_install.rs +++ b/crates/uv/src/commands/pip_install.rs @@ -38,8 +38,8 @@ use uv_resolver::{ Preference, ResolutionGraph, ResolutionMode, Resolver, }; use uv_types::{ - BuildIsolation, ConfigSettings, InFlight, NoBinary, NoBuild, Reinstall, SetupPyStrategy, - Upgrade, + BuildIsolation, ConfigSettings, Constraints, InFlight, NoBinary, NoBuild, Overrides, Reinstall, + SetupPyStrategy, Upgrade, }; use uv_warnings::warn_user; @@ -523,6 +523,10 @@ async fn resolve( .map(Preference::from_requirement) .collect(); + // Collect constraints and overrides. + let constraints = Constraints::from_requirements(constraints); + let overrides = Overrides::from_requirements(overrides); + // Map the editables to their metadata. let editables: Vec<(LocalEditable, Metadata23)> = editables .iter()