Merge uv-pubgrub into uv-pep440 (#8669)

This commit is contained in:
konsti 2024-10-29 20:15:18 +01:00 committed by GitHub
parent f903cd2cce
commit e5b8cdba70
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 96 additions and 106 deletions

14
Cargo.lock generated
View file

@ -4303,7 +4303,6 @@ dependencies = [
"uv-normalize", "uv-normalize",
"uv-pep440", "uv-pep440",
"uv-pep508", "uv-pep508",
"uv-pubgrub",
"uv-pypi-types", "uv-pypi-types",
"uv-warnings", "uv-warnings",
"walkdir", "walkdir",
@ -4875,6 +4874,7 @@ dependencies = [
"tracing", "tracing",
"unicode-width", "unicode-width",
"unscanny", "unscanny",
"version-ranges",
] ]
[[package]] [[package]]
@ -4900,7 +4900,6 @@ dependencies = [
"uv-fs", "uv-fs",
"uv-normalize", "uv-normalize",
"uv-pep440", "uv-pep440",
"uv-pubgrub",
"version-ranges", "version-ranges",
] ]
@ -4929,16 +4928,6 @@ dependencies = [
"thiserror", "thiserror",
] ]
[[package]]
name = "uv-pubgrub"
version = "0.0.1"
dependencies = [
"itertools 0.13.0",
"thiserror",
"uv-pep440",
"version-ranges",
]
[[package]] [[package]]
name = "uv-publish" name = "uv-publish"
version = "0.1.0" version = "0.1.0"
@ -5158,7 +5147,6 @@ dependencies = [
"uv-pep440", "uv-pep440",
"uv-pep508", "uv-pep508",
"uv-platform-tags", "uv-platform-tags",
"uv-pubgrub",
"uv-pypi-types", "uv-pypi-types",
"uv-python", "uv-python",
"uv-requirements-txt", "uv-requirements-txt",

View file

@ -46,10 +46,9 @@ uv-metadata = { path = "crates/uv-metadata" }
uv-normalize = { path = "crates/uv-normalize" } uv-normalize = { path = "crates/uv-normalize" }
uv-once-map = { path = "crates/uv-once-map" } uv-once-map = { path = "crates/uv-once-map" }
uv-options-metadata = { path = "crates/uv-options-metadata" } uv-options-metadata = { path = "crates/uv-options-metadata" }
uv-pep440 = { path = "crates/uv-pep440", features = ["tracing", "rkyv"] } uv-pep440 = { path = "crates/uv-pep440", features = ["tracing", "rkyv", "version-ranges"] }
uv-pep508 = { path = "crates/uv-pep508", features = ["non-pep508-extensions"] } uv-pep508 = { path = "crates/uv-pep508", features = ["non-pep508-extensions"] }
uv-platform-tags = { path = "crates/uv-platform-tags" } uv-platform-tags = { path = "crates/uv-platform-tags" }
uv-pubgrub = { path = "crates/uv-pubgrub" }
uv-publish = { path = "crates/uv-publish" } uv-publish = { path = "crates/uv-publish" }
uv-pypi-types = { path = "crates/uv-pypi-types" } uv-pypi-types = { path = "crates/uv-pypi-types" }
uv-python = { path = "crates/uv-python" } uv-python = { path = "crates/uv-python" }

View file

@ -18,7 +18,6 @@ uv-fs = { workspace = true }
uv-normalize = { workspace = true } uv-normalize = { workspace = true }
uv-pep440 = { workspace = true } uv-pep440 = { workspace = true }
uv-pep508 = { workspace = true } uv-pep508 = { workspace = true }
uv-pubgrub = { workspace = true }
uv-pypi-types = { workspace = true } uv-pypi-types = { workspace = true }
uv-warnings = { workspace = true } uv-warnings = { workspace = true }

View file

@ -9,9 +9,8 @@ use std::str::FromStr;
use tracing::debug; use tracing::debug;
use uv_fs::Simplified; use uv_fs::Simplified;
use uv_normalize::{ExtraName, PackageName}; use uv_normalize::{ExtraName, PackageName};
use uv_pep440::{Version, VersionSpecifiers}; use uv_pep440::{Version, VersionRangesSpecifier, VersionSpecifiers};
use uv_pep508::{Requirement, VersionOrUrl}; use uv_pep508::{Requirement, VersionOrUrl};
use uv_pubgrub::PubGrubSpecifier;
use uv_pypi_types::{Metadata23, VerbatimParsedUrl}; use uv_pypi_types::{Metadata23, VerbatimParsedUrl};
use uv_warnings::warn_user_once; use uv_warnings::warn_user_once;
@ -135,7 +134,7 @@ impl PyProjectToml {
); );
passed = false; passed = false;
} }
PubGrubSpecifier::from_pep440_specifiers(specifier) VersionRangesSpecifier::from_pep440_specifiers(specifier)
.ok() .ok()
.and_then(|specifier| Some(specifier.bounding_range()?.1 != Bound::Unbounded)) .and_then(|specifier| Some(specifier.bounding_range()?.1 != Bound::Unbounded))
.unwrap_or(false) .unwrap_or(false)

View file

@ -20,11 +20,12 @@ doctest = false
workspace = true workspace = true
[dependencies] [dependencies]
serde = { workspace = true, features = ["derive"] }
rkyv = { workspace = true, optional = true } rkyv = { workspace = true, optional = true }
serde = { workspace = true, features = ["derive"] }
tracing = { workspace = true, optional = true } tracing = { workspace = true, optional = true }
unicode-width = { workspace = true } unicode-width = { workspace = true }
unscanny = { workspace = true } unscanny = { workspace = true }
version-ranges = { workspace = true, optional = true }
[dev-dependencies] [dev-dependencies]
indoc = { version = "2.0.5" } indoc = { version = "2.0.5" }

View file

@ -23,6 +23,8 @@
//! the version matching needs to catch all sorts of special cases //! the version matching needs to catch all sorts of special cases
#![warn(missing_docs)] #![warn(missing_docs)]
#[cfg(feature = "version-ranges")]
pub use version_ranges_specifier::{VersionRangesSpecifier, VersionRangesSpecifierError};
pub use { pub use {
version::{ version::{
LocalSegment, Operator, OperatorParseError, Prerelease, PrereleaseKind, Version, LocalSegment, Operator, OperatorParseError, Prerelease, PrereleaseKind, Version,
@ -39,3 +41,5 @@ mod version_specifier;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
#[cfg(feature = "version-ranges")]
mod version_ranges_specifier;

View file

@ -1,58 +1,73 @@
use std::error::Error;
use std::fmt::{Display, Formatter};
use std::ops::Bound; use std::ops::Bound;
use itertools::Itertools;
use thiserror::Error;
use version_ranges::Ranges; use version_ranges::Ranges;
use uv_pep440::{Operator, Prerelease, Version, VersionSpecifier, VersionSpecifiers}; use crate::{Operator, Prerelease, Version, VersionSpecifier, VersionSpecifiers};
#[derive(Debug, Error)] /// The conversion between PEP 440 [`VersionSpecifier`] and version-ranges
pub enum PubGrubSpecifierError { /// [`VersionRangesSpecifier`] failed.
#[error("~= operator requires at least two release segments: `{0}`")] #[derive(Debug)]
pub enum VersionRangesSpecifierError {
/// The `~=` operator requires at least two release segments
InvalidTildeEquals(VersionSpecifier), InvalidTildeEquals(VersionSpecifier),
} }
impl Error for VersionRangesSpecifierError {}
impl Display for VersionRangesSpecifierError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::InvalidTildeEquals(specifier) => {
write!(
f,
"The `~=` operator requires at least two release segments: `{specifier}`"
)
}
}
}
}
/// A range of versions that can be used to satisfy a requirement. /// A range of versions that can be used to satisfy a requirement.
#[derive(Debug)] #[derive(Debug)]
pub struct PubGrubSpecifier(Ranges<Version>); pub struct VersionRangesSpecifier(Ranges<Version>);
impl PubGrubSpecifier { impl VersionRangesSpecifier {
/// Returns an iterator over the bounds of the [`PubGrubSpecifier`]. /// Returns an iterator over the bounds of the [`VersionRangesSpecifier`].
pub fn iter(&self) -> impl Iterator<Item = (&Bound<Version>, &Bound<Version>)> { pub fn iter(&self) -> impl Iterator<Item = (&Bound<Version>, &Bound<Version>)> {
self.0.iter() self.0.iter()
} }
/// Return the bounding [`Ranges`] of the [`PubGrubSpecifier`]. /// Return the bounding [`Ranges`] of the [`VersionRangesSpecifier`].
pub fn bounding_range(&self) -> Option<(Bound<&Version>, Bound<&Version>)> { pub fn bounding_range(&self) -> Option<(Bound<&Version>, Bound<&Version>)> {
self.0.bounding_range() self.0.bounding_range()
} }
} }
impl From<Ranges<Version>> for PubGrubSpecifier { impl From<Ranges<Version>> for VersionRangesSpecifier {
fn from(range: Ranges<Version>) -> Self { fn from(range: Ranges<Version>) -> Self {
PubGrubSpecifier(range) VersionRangesSpecifier(range)
} }
} }
impl From<PubGrubSpecifier> for Ranges<Version> { impl From<VersionRangesSpecifier> for Ranges<Version> {
/// Convert a PubGrub specifier to a range of versions. /// Convert a PubGrub specifier to a range of versions.
fn from(specifier: PubGrubSpecifier) -> Self { fn from(specifier: VersionRangesSpecifier) -> Self {
specifier.0 specifier.0
} }
} }
impl PubGrubSpecifier { impl VersionRangesSpecifier {
/// Convert [`VersionSpecifiers`] to a PubGrub-compatible version range, using PEP 440 /// Convert [`VersionSpecifiers`] to a PubGrub-compatible version range, using PEP 440
/// semantics. /// semantics.
pub fn from_pep440_specifiers( pub fn from_pep440_specifiers(
specifiers: &VersionSpecifiers, specifiers: &VersionSpecifiers,
) -> Result<Self, PubGrubSpecifierError> { ) -> Result<Self, VersionRangesSpecifierError> {
let range = specifiers let mut range = Ranges::full();
.iter() for specifier in specifiers.iter() {
.map(Self::from_pep440_specifier) range = range.intersection(&Self::from_pep440_specifier(specifier)?.into());
.fold_ok(Ranges::full(), |range, specifier| { }
range.intersection(&specifier.into())
})?;
Ok(Self(range)) Ok(Self(range))
} }
@ -60,7 +75,7 @@ impl PubGrubSpecifier {
/// semantics. /// semantics.
pub fn from_pep440_specifier( pub fn from_pep440_specifier(
specifier: &VersionSpecifier, specifier: &VersionSpecifier,
) -> Result<Self, PubGrubSpecifierError> { ) -> Result<Self, VersionRangesSpecifierError> {
let ranges = match specifier.operator() { let ranges = match specifier.operator() {
Operator::Equal => { Operator::Equal => {
let version = specifier.version().clone(); let version = specifier.version().clone();
@ -76,7 +91,9 @@ impl PubGrubSpecifier {
} }
Operator::TildeEqual => { Operator::TildeEqual => {
let [rest @ .., last, _] = specifier.version().release() else { let [rest @ .., last, _] = specifier.version().release() else {
return Err(PubGrubSpecifierError::InvalidTildeEquals(specifier.clone())); return Err(VersionRangesSpecifierError::InvalidTildeEquals(
specifier.clone(),
));
}; };
let upper = Version::new(rest.iter().chain([&(last + 1)])) let upper = Version::new(rest.iter().chain([&(last + 1)]))
.with_epoch(specifier.version().epoch()) .with_epoch(specifier.version().epoch())
@ -167,13 +184,11 @@ impl PubGrubSpecifier {
/// See: <https://github.com/pypa/pip/blob/a432c7f4170b9ef798a15f035f5dfdb4cc939f35/src/pip/_internal/resolution/resolvelib/candidates.py#L540> /// See: <https://github.com/pypa/pip/blob/a432c7f4170b9ef798a15f035f5dfdb4cc939f35/src/pip/_internal/resolution/resolvelib/candidates.py#L540>
pub fn from_release_specifiers( pub fn from_release_specifiers(
specifiers: &VersionSpecifiers, specifiers: &VersionSpecifiers,
) -> Result<Self, PubGrubSpecifierError> { ) -> Result<Self, VersionRangesSpecifierError> {
let range = specifiers let mut range = Ranges::full();
.iter() for specifier in specifiers.iter() {
.map(Self::from_release_specifier) range = range.intersection(&Self::from_release_specifier(specifier)?.into());
.fold_ok(Ranges::full(), |range, specifier| { }
range.intersection(&specifier.into())
})?;
Ok(Self(range)) Ok(Self(range))
} }
@ -190,7 +205,7 @@ impl PubGrubSpecifier {
/// See: <https://github.com/pypa/pip/blob/a432c7f4170b9ef798a15f035f5dfdb4cc939f35/src/pip/_internal/resolution/resolvelib/candidates.py#L540> /// See: <https://github.com/pypa/pip/blob/a432c7f4170b9ef798a15f035f5dfdb4cc939f35/src/pip/_internal/resolution/resolvelib/candidates.py#L540>
pub fn from_release_specifier( pub fn from_release_specifier(
specifier: &VersionSpecifier, specifier: &VersionSpecifier,
) -> Result<Self, PubGrubSpecifierError> { ) -> Result<Self, VersionRangesSpecifierError> {
let ranges = match specifier.operator() { let ranges = match specifier.operator() {
Operator::Equal => { Operator::Equal => {
let version = specifier.version().only_release(); let version = specifier.version().only_release();
@ -206,7 +221,9 @@ impl PubGrubSpecifier {
} }
Operator::TildeEqual => { Operator::TildeEqual => {
let [rest @ .., last, _] = specifier.version().release() else { let [rest @ .., last, _] = specifier.version().release() else {
return Err(PubGrubSpecifierError::InvalidTildeEquals(specifier.clone())); return Err(VersionRangesSpecifierError::InvalidTildeEquals(
specifier.clone(),
));
}; };
let upper = Version::new(rest.iter().chain([&(last + 1)])); let upper = Version::new(rest.iter().chain([&(last + 1)]));
let version = specifier.version().only_release(); let version = specifier.version().only_release();

View file

@ -24,7 +24,6 @@ workspace = true
uv-fs = { workspace = true } uv-fs = { workspace = true }
uv-normalize = { workspace = true } uv-normalize = { workspace = true }
uv-pep440 = { workspace = true } uv-pep440 = { workspace = true }
uv-pubgrub = { workspace = true }
boxcar = { workspace = true } boxcar = { workspace = true }
indexmap = { workspace = true } indexmap = { workspace = true }

View file

@ -53,9 +53,8 @@ use std::sync::MutexGuard;
use itertools::Either; use itertools::Either;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use std::sync::LazyLock; use std::sync::LazyLock;
use uv_pep440::Operator; use uv_pep440::{Operator, VersionRangesSpecifier};
use uv_pep440::{Version, VersionSpecifier}; use uv_pep440::{Version, VersionSpecifier};
use uv_pubgrub::PubGrubSpecifier;
use version_ranges::Ranges; use version_ranges::Ranges;
use crate::marker::MarkerValueExtra; use crate::marker::MarkerValueExtra;
@ -746,7 +745,8 @@ impl Edges {
/// Returns the [`Edges`] for a version specifier. /// Returns the [`Edges`] for a version specifier.
fn from_specifier(specifier: VersionSpecifier) -> Edges { fn from_specifier(specifier: VersionSpecifier) -> Edges {
let specifier = let specifier =
PubGrubSpecifier::from_release_specifier(&normalize_specifier(specifier)).unwrap(); VersionRangesSpecifier::from_release_specifier(&normalize_specifier(specifier))
.unwrap();
Edges::Version { Edges::Version {
edges: Edges::from_range(&specifier.into()), edges: Edges::from_range(&specifier.into()),
} }
@ -764,7 +764,8 @@ impl Edges {
let specifier = VersionSpecifier::equals_version(version.clone()); let specifier = VersionSpecifier::equals_version(version.clone());
let specifier = python_version_to_full_version(specifier)?; let specifier = python_version_to_full_version(specifier)?;
let pubgrub_specifier = let pubgrub_specifier =
PubGrubSpecifier::from_release_specifier(&normalize_specifier(specifier)).unwrap(); VersionRangesSpecifier::from_release_specifier(&normalize_specifier(specifier))
.unwrap();
range = range.union(&pubgrub_specifier.into()); range = range.union(&pubgrub_specifier.into());
} }

View file

@ -1,18 +0,0 @@
[package]
name = "uv-pubgrub"
version = "0.0.1"
edition = "2021"
description = "Common uv pubgrub types."
[lib]
doctest = false
[lints]
workspace = true
[dependencies]
uv-pep440 = { workspace = true }
itertools = { workspace = true }
thiserror = { workspace = true }
version-ranges = { workspace = true }

View file

@ -30,7 +30,6 @@ uv-once-map = { workspace = true }
uv-pep440 = { workspace = true } uv-pep440 = { workspace = true }
uv-pep508 = { workspace = true } uv-pep508 = { workspace = true }
uv-platform-tags = { workspace = true } uv-platform-tags = { workspace = true }
uv-pubgrub = { workspace = true }
uv-pypi-types = { workspace = true } uv-pypi-types = { workspace = true }
uv-python = { workspace = true } uv-python = { workspace = true }
uv-requirements-txt = { workspace = true } uv-requirements-txt = { workspace = true }

View file

@ -9,9 +9,7 @@ use rustc_hash::FxHashMap;
use crate::candidate_selector::CandidateSelector; use crate::candidate_selector::CandidateSelector;
use crate::dependency_provider::UvDependencyProvider; use crate::dependency_provider::UvDependencyProvider;
use crate::fork_urls::ForkUrls; use crate::fork_urls::ForkUrls;
use crate::pubgrub::{ use crate::pubgrub::{PubGrubPackage, PubGrubPackageInner, PubGrubReportFormatter};
PubGrubPackage, PubGrubPackageInner, PubGrubReportFormatter, PubGrubSpecifierError,
};
use crate::python_requirement::PythonRequirement; use crate::python_requirement::PythonRequirement;
use crate::resolution::ConflictingDistributionError; use crate::resolution::ConflictingDistributionError;
use crate::resolver::{IncompletePackage, ResolverMarkers, UnavailablePackage, UnavailableReason}; use crate::resolver::{IncompletePackage, ResolverMarkers, UnavailablePackage, UnavailableReason};
@ -21,7 +19,7 @@ use uv_distribution_types::{
BuiltDist, IndexCapabilities, IndexLocations, IndexUrl, InstalledDist, SourceDist, BuiltDist, IndexCapabilities, IndexLocations, IndexUrl, InstalledDist, SourceDist,
}; };
use uv_normalize::PackageName; use uv_normalize::PackageName;
use uv_pep440::Version; use uv_pep440::{Version, VersionRangesSpecifierError};
use uv_pep508::MarkerTree; use uv_pep508::MarkerTree;
use uv_static::EnvVars; use uv_static::EnvVars;
@ -40,7 +38,7 @@ pub enum ResolveError {
UnregisteredTask(String), UnregisteredTask(String),
#[error(transparent)] #[error(transparent)]
PubGrubSpecifier(#[from] PubGrubSpecifierError), VersionRangesSpecifier(#[from] VersionRangesSpecifierError),
#[error("Overrides contain conflicting URLs for package `{0}`:\n- {1}\n- {2}")] #[error("Overrides contain conflicting URLs for package `{0}`:\n- {1}\n- {2}")]
ConflictingOverrideUrls(PackageName, String, String), ConflictingOverrideUrls(PackageName, String, String),

View file

@ -11,7 +11,6 @@ pub use manifest::Manifest;
pub use options::{Flexibility, Options, OptionsBuilder}; pub use options::{Flexibility, Options, OptionsBuilder};
pub use preferences::{Preference, PreferenceError, Preferences}; pub use preferences::{Preference, PreferenceError, Preferences};
pub use prerelease::PrereleaseMode; pub use prerelease::PrereleaseMode;
pub use pubgrub::{PubGrubSpecifier, PubGrubSpecifierError};
pub use python_requirement::PythonRequirement; pub use python_requirement::PythonRequirement;
pub use requires_python::{RequiresPython, RequiresPythonError, RequiresPythonRange}; pub use requires_python::{RequiresPython, RequiresPythonError, RequiresPythonRange};
pub use resolution::{ pub use resolution::{

View file

@ -5,14 +5,14 @@ use pubgrub::Range;
use tracing::warn; use tracing::warn;
use uv_normalize::{ExtraName, PackageName}; use uv_normalize::{ExtraName, PackageName};
use uv_pep440::{Version, VersionSpecifiers}; use uv_pep440::{Version, VersionRangesSpecifier, VersionSpecifiers};
use uv_pypi_types::{ use uv_pypi_types::{
ParsedArchiveUrl, ParsedDirectoryUrl, ParsedGitUrl, ParsedPathUrl, ParsedUrl, Requirement, ParsedArchiveUrl, ParsedDirectoryUrl, ParsedGitUrl, ParsedPathUrl, ParsedUrl, Requirement,
RequirementSource, VerbatimParsedUrl, RequirementSource, VerbatimParsedUrl,
}; };
use crate::pubgrub::{PubGrubPackage, PubGrubPackageInner}; use crate::pubgrub::{PubGrubPackage, PubGrubPackageInner};
use crate::{PubGrubSpecifier, ResolveError}; use crate::ResolveError;
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub(crate) struct PubGrubDependency { pub(crate) struct PubGrubDependency {
@ -179,7 +179,7 @@ impl PubGrubRequirement {
extra: Option<ExtraName>, extra: Option<ExtraName>,
requirement: &Requirement, requirement: &Requirement,
) -> Result<PubGrubRequirement, ResolveError> { ) -> Result<PubGrubRequirement, ResolveError> {
let version = PubGrubSpecifier::from_pep440_specifiers(specifier)?.into(); let version = VersionRangesSpecifier::from_pep440_specifiers(specifier)?.into();
let requirement = Self { let requirement = Self {
package: PubGrubPackage::from_package( package: PubGrubPackage::from_package(

View file

@ -3,7 +3,6 @@ pub(crate) use crate::pubgrub::distribution::PubGrubDistribution;
pub(crate) use crate::pubgrub::package::{PubGrubPackage, PubGrubPackageInner, PubGrubPython}; pub(crate) use crate::pubgrub::package::{PubGrubPackage, PubGrubPackageInner, PubGrubPython};
pub(crate) use crate::pubgrub::priority::{PubGrubPriorities, PubGrubPriority}; pub(crate) use crate::pubgrub::priority::{PubGrubPriorities, PubGrubPriority};
pub(crate) use crate::pubgrub::report::PubGrubReportFormatter; pub(crate) use crate::pubgrub::report::PubGrubReportFormatter;
pub use uv_pubgrub::{PubGrubSpecifier, PubGrubSpecifierError};
mod dependencies; mod dependencies;
mod distribution; mod distribution;

View file

@ -5,14 +5,16 @@ use std::collections::Bound;
use std::ops::Deref; use std::ops::Deref;
use uv_distribution_filename::WheelFilename; use uv_distribution_filename::WheelFilename;
use uv_pep440::{Version, VersionSpecifier, VersionSpecifiers}; use uv_pep440::{
Version, VersionRangesSpecifier, VersionRangesSpecifierError, VersionSpecifier,
VersionSpecifiers,
};
use uv_pep508::{MarkerExpression, MarkerTree, MarkerValueVersion}; use uv_pep508::{MarkerExpression, MarkerTree, MarkerValueVersion};
use uv_pubgrub::PubGrubSpecifier;
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug)]
pub enum RequiresPythonError { pub enum RequiresPythonError {
#[error(transparent)] #[error(transparent)]
PubGrub(#[from] crate::pubgrub::PubGrubSpecifierError), VersionRangesSpecifier(#[from] VersionRangesSpecifierError),
} }
/// The `Requires-Python` requirement specifier. /// The `Requires-Python` requirement specifier.
@ -53,10 +55,11 @@ impl RequiresPython {
/// Returns a [`RequiresPython`] from a version specifier. /// Returns a [`RequiresPython`] from a version specifier.
pub fn from_specifiers(specifiers: &VersionSpecifiers) -> Result<Self, RequiresPythonError> { pub fn from_specifiers(specifiers: &VersionSpecifiers) -> Result<Self, RequiresPythonError> {
let (lower_bound, upper_bound) = PubGrubSpecifier::from_release_specifiers(specifiers)? let (lower_bound, upper_bound) =
.bounding_range() VersionRangesSpecifier::from_release_specifiers(specifiers)?
.map(|(lower_bound, upper_bound)| (lower_bound.cloned(), upper_bound.cloned())) .bounding_range()
.unwrap_or((Bound::Unbounded, Bound::Unbounded)); .map(|(lower_bound, upper_bound)| (lower_bound.cloned(), upper_bound.cloned()))
.unwrap_or((Bound::Unbounded, Bound::Unbounded));
Ok(Self { Ok(Self {
specifiers: specifiers.clone(), specifiers: specifiers.clone(),
range: RequiresPythonRange(LowerBound(lower_bound), UpperBound(upper_bound)), range: RequiresPythonRange(LowerBound(lower_bound), UpperBound(upper_bound)),
@ -72,7 +75,7 @@ impl RequiresPython {
// Convert to PubGrub range and perform an intersection. // Convert to PubGrub range and perform an intersection.
let range = specifiers let range = specifiers
.into_iter() .into_iter()
.map(PubGrubSpecifier::from_release_specifiers) .map(VersionRangesSpecifier::from_release_specifiers)
.fold_ok(None, |range: Option<Range<Version>>, requires_python| { .fold_ok(None, |range: Option<Range<Version>>, requires_python| {
if let Some(range) = range { if let Some(range) = range {
Some(range.intersection(&requires_python.into())) Some(range.intersection(&requires_python.into()))
@ -237,7 +240,7 @@ impl RequiresPython {
/// provided range. However, `>=3.9` would not be considered compatible, as the /// provided range. However, `>=3.9` would not be considered compatible, as the
/// `Requires-Python` includes Python 3.8, but `>=3.9` does not. /// `Requires-Python` includes Python 3.8, but `>=3.9` does not.
pub fn is_contained_by(&self, target: &VersionSpecifiers) -> bool { pub fn is_contained_by(&self, target: &VersionSpecifiers) -> bool {
let Ok(target) = PubGrubSpecifier::from_release_specifiers(target) else { let Ok(target) = VersionRangesSpecifier::from_release_specifiers(target) else {
return false; return false;
}; };
let target = target let target = target
@ -485,11 +488,12 @@ impl serde::Serialize for RequiresPython {
impl<'de> serde::Deserialize<'de> for RequiresPython { impl<'de> serde::Deserialize<'de> for RequiresPython {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> { fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let specifiers = VersionSpecifiers::deserialize(deserializer)?; let specifiers = VersionSpecifiers::deserialize(deserializer)?;
let (lower_bound, upper_bound) = PubGrubSpecifier::from_release_specifiers(&specifiers) let (lower_bound, upper_bound) =
.map_err(serde::de::Error::custom)? VersionRangesSpecifier::from_release_specifiers(&specifiers)
.bounding_range() .map_err(serde::de::Error::custom)?
.map(|(lower_bound, upper_bound)| (lower_bound.cloned(), upper_bound.cloned())) .bounding_range()
.unwrap_or((Bound::Unbounded, Bound::Unbounded)); .map(|(lower_bound, upper_bound)| (lower_bound.cloned(), upper_bound.cloned()))
.unwrap_or((Bound::Unbounded, Bound::Unbounded));
Ok(Self { Ok(Self {
specifiers, specifiers,
range: RequiresPythonRange(LowerBound(lower_bound), UpperBound(upper_bound)), range: RequiresPythonRange(LowerBound(lower_bound), UpperBound(upper_bound)),

View file

@ -34,7 +34,7 @@ use uv_distribution_types::{
}; };
use uv_git::GitResolver; use uv_git::GitResolver;
use uv_normalize::{ExtraName, GroupName, PackageName}; use uv_normalize::{ExtraName, GroupName, PackageName};
use uv_pep440::{Version, MIN_VERSION}; use uv_pep440::{Version, VersionRangesSpecifier, MIN_VERSION};
use uv_pep508::MarkerTree; use uv_pep508::MarkerTree;
use uv_platform_tags::Tags; use uv_platform_tags::Tags;
use uv_pypi_types::{Requirement, ResolutionMetadata, VerbatimParsedUrl}; use uv_pypi_types::{Requirement, ResolutionMetadata, VerbatimParsedUrl};
@ -51,7 +51,7 @@ use crate::pins::FilePins;
use crate::preferences::Preferences; use crate::preferences::Preferences;
use crate::pubgrub::{ use crate::pubgrub::{
PubGrubDependency, PubGrubDistribution, PubGrubPackage, PubGrubPackageInner, PubGrubPriorities, PubGrubDependency, PubGrubDistribution, PubGrubPackage, PubGrubPackageInner, PubGrubPriorities,
PubGrubPython, PubGrubSpecifier, PubGrubPython,
}; };
use crate::python_requirement::PythonRequirement; use crate::python_requirement::PythonRequirement;
use crate::resolution::ResolutionGraph; use crate::resolution::ResolutionGraph;
@ -2224,7 +2224,9 @@ impl ForkState {
Locals::map(local, specifier) Locals::map(local, specifier)
.map_err(ResolveError::InvalidVersion) .map_err(ResolveError::InvalidVersion)
.and_then(|specifier| { .and_then(|specifier| {
Ok(PubGrubSpecifier::from_pep440_specifier(&specifier)?) Ok(VersionRangesSpecifier::from_pep440_specifier(
&specifier,
)?)
}) })
}) })
.fold_ok(Range::full(), |range, specifier| { .fold_ok(Range::full(), |range, specifier| {
@ -2300,7 +2302,7 @@ impl ForkState {
) = reason ) = reason
{ {
let python_version: Range<Version> = let python_version: Range<Version> =
PubGrubSpecifier::from_release_specifiers(&requires_python)?.into(); VersionRangesSpecifier::from_release_specifiers(&requires_python)?.into();
let package = &self.next; let package = &self.next;
self.pubgrub self.pubgrub

View file

@ -773,5 +773,5 @@ pub(crate) enum Error {
Anyhow(#[from] anyhow::Error), Anyhow(#[from] anyhow::Error),
#[error(transparent)] #[error(transparent)]
PubGrubSpecifier(#[from] uv_resolver::PubGrubSpecifierError), VersionRangesSpecifier(#[from] uv_pep440::VersionRangesSpecifierError),
} }