diff --git a/crates/uv-resolver/src/pubgrub/dependencies.rs b/crates/uv-resolver/src/pubgrub/dependencies.rs index e3a795d4f..72a0a5932 100644 --- a/crates/uv-resolver/src/pubgrub/dependencies.rs +++ b/crates/uv-resolver/src/pubgrub/dependencies.rs @@ -14,7 +14,7 @@ use uv_normalize::{ExtraName, PackageName}; use crate::pubgrub::{PubGrubPackage, PubGrubPackageInner}; use crate::{PubGrubSpecifier, ResolveError}; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Eq, PartialEq)] pub(crate) struct PubGrubDependency { pub(crate) package: PubGrubPackage, pub(crate) version: Range, diff --git a/crates/uv-resolver/src/requires_python.rs b/crates/uv-resolver/src/requires_python.rs index 19f40f454..952917340 100644 --- a/crates/uv-resolver/src/requires_python.rs +++ b/crates/uv-resolver/src/requires_python.rs @@ -350,6 +350,12 @@ impl<'de> serde::Deserialize<'de> for RequiresPython { #[derive(Debug, Clone, Eq, PartialEq, Hash)] pub struct RequiresPythonBound(Bound); +impl Default for RequiresPythonBound { + fn default() -> Self { + Self(Bound::Unbounded) + } +} + impl RequiresPythonBound { pub fn new(bound: Bound) -> Self { Self(match bound { diff --git a/crates/uv-resolver/src/resolver/mod.rs b/crates/uv-resolver/src/resolver/mod.rs index de41fceda..904193d19 100644 --- a/crates/uv-resolver/src/resolver/mod.rs +++ b/crates/uv-resolver/src/resolver/mod.rs @@ -1,6 +1,7 @@ //! Given a set of requirements, find a set of compatible packages. use std::borrow::Cow; +use std::cmp::Ordering; use std::collections::hash_map::Entry; use std::collections::{BTreeMap, BTreeSet, VecDeque}; use std::fmt::{Display, Formatter, Write}; @@ -576,6 +577,7 @@ impl ResolverState=2`, while /// the other fork will contain `a>=2` but not `a<2`. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Eq, PartialEq)] struct Fork { /// The list of dependencies for this fork, guaranteed to be conflict /// free. (i.e., There are no two packages with the same name with @@ -2829,6 +2837,23 @@ struct Fork { markers: MarkerTree, } +impl Ord for Fork { + fn cmp(&self, other: &Self) -> Ordering { + // A higher `requires-python` requirement indicates a _lower-priority_ fork. We'd prefer + // to solve `<3.7` before solving `>=3.7`, since the resolution produced by the former might + // work for the latter, but the inverse is unlikely to be true. + let self_bound = requires_python_marker(&self.markers).unwrap_or_default(); + let other_bound = requires_python_marker(&other.markers).unwrap_or_default(); + other_bound.cmp(&self_bound) + } +} + +impl PartialOrd for Fork { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + impl Fork { /// Add the given dependency to this fork. /// diff --git a/crates/uv/tests/pip_compile.rs b/crates/uv/tests/pip_compile.rs index 63857b255..56530d9d5 100644 --- a/crates/uv/tests/pip_compile.rs +++ b/crates/uv/tests/pip_compile.rs @@ -7867,9 +7867,7 @@ fn universal_no_repeated_unconditional_distributions() -> Result<()> { ----- stdout ----- # This file was autogenerated by uv via the following command: # uv pip compile --cache-dir [CACHE_DIR] requirements.in -p 3.8 --universal - alabaster==0.7.13 ; python_version < '3.11' - # via sphinx - alabaster==0.7.16 ; python_version >= '3.11' + alabaster==0.7.13 # via sphinx astroid==3.1.0 # via pylint @@ -7915,31 +7913,19 @@ fn universal_no_repeated_unconditional_distributions() -> Result<()> { # via sphinx snowballstemmer==2.2.0 # via sphinx - sphinx==7.1.2 ; python_version < '3.11' + sphinx==7.1.2 # via -r requirements.in - sphinx==7.2.6 ; python_version >= '3.11' - # via -r requirements.in - sphinxcontrib-applehelp==1.0.4 ; python_version < '3.11' + sphinxcontrib-applehelp==1.0.4 # via sphinx - sphinxcontrib-applehelp==1.0.8 ; python_version >= '3.11' + sphinxcontrib-devhelp==1.0.2 # via sphinx - sphinxcontrib-devhelp==1.0.2 ; python_version < '3.11' - # via sphinx - sphinxcontrib-devhelp==1.0.6 ; python_version >= '3.11' - # via sphinx - sphinxcontrib-htmlhelp==2.0.1 ; python_version < '3.11' - # via sphinx - sphinxcontrib-htmlhelp==2.0.5 ; python_version >= '3.11' + sphinxcontrib-htmlhelp==2.0.1 # via sphinx sphinxcontrib-jsmath==1.0.1 # via sphinx - sphinxcontrib-qthelp==1.0.3 ; python_version < '3.11' + sphinxcontrib-qthelp==1.0.3 # via sphinx - sphinxcontrib-qthelp==1.0.7 ; python_version >= '3.11' - # via sphinx - sphinxcontrib-serializinghtml==1.1.5 ; python_version < '3.11' - # via sphinx - sphinxcontrib-serializinghtml==1.1.10 ; python_version >= '3.11' + sphinxcontrib-serializinghtml==1.1.5 # via sphinx tomli==2.0.1 ; python_version < '3.11' # via pylint @@ -7956,7 +7942,7 @@ fn universal_no_repeated_unconditional_distributions() -> Result<()> { ----- stderr ----- warning: The requested Python version 3.8 is not available; 3.12.[X] will be used to build dependencies instead. - Resolved 41 packages in [TIME] + Resolved 34 packages in [TIME] "### );