Skip to content

Commit

Permalink
Merge uv-pubgrub into uv-pep440 (astral-sh#8669)
Browse files Browse the repository at this point in the history
  • Loading branch information
konstin authored Oct 29, 2024
1 parent f903cd2 commit e5b8cdb
Show file tree
Hide file tree
Showing 18 changed files with 96 additions and 106 deletions.
14 changes: 1 addition & 13 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,9 @@ uv-metadata = { path = "crates/uv-metadata" }
uv-normalize = { path = "crates/uv-normalize" }
uv-once-map = { path = "crates/uv-once-map" }
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-platform-tags = { path = "crates/uv-platform-tags" }
uv-pubgrub = { path = "crates/uv-pubgrub" }
uv-publish = { path = "crates/uv-publish" }
uv-pypi-types = { path = "crates/uv-pypi-types" }
uv-python = { path = "crates/uv-python" }
Expand Down
1 change: 0 additions & 1 deletion crates/uv-build-backend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ uv-fs = { workspace = true }
uv-normalize = { workspace = true }
uv-pep440 = { workspace = true }
uv-pep508 = { workspace = true }
uv-pubgrub = { workspace = true }
uv-pypi-types = { workspace = true }
uv-warnings = { workspace = true }

Expand Down
5 changes: 2 additions & 3 deletions crates/uv-build-backend/src/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@ use std::str::FromStr;
use tracing::debug;
use uv_fs::Simplified;
use uv_normalize::{ExtraName, PackageName};
use uv_pep440::{Version, VersionSpecifiers};
use uv_pep440::{Version, VersionRangesSpecifier, VersionSpecifiers};
use uv_pep508::{Requirement, VersionOrUrl};
use uv_pubgrub::PubGrubSpecifier;
use uv_pypi_types::{Metadata23, VerbatimParsedUrl};
use uv_warnings::warn_user_once;

Expand Down Expand Up @@ -135,7 +134,7 @@ impl PyProjectToml {
);
passed = false;
}
PubGrubSpecifier::from_pep440_specifiers(specifier)
VersionRangesSpecifier::from_pep440_specifiers(specifier)
.ok()
.and_then(|specifier| Some(specifier.bounding_range()?.1 != Bound::Unbounded))
.unwrap_or(false)
Expand Down
3 changes: 2 additions & 1 deletion crates/uv-pep440/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@ doctest = false
workspace = true

[dependencies]
serde = { workspace = true, features = ["derive"] }
rkyv = { workspace = true, optional = true }
serde = { workspace = true, features = ["derive"] }
tracing = { workspace = true, optional = true }
unicode-width = { workspace = true }
unscanny = { workspace = true }
version-ranges = { workspace = true, optional = true }

[dev-dependencies]
indoc = { version = "2.0.5" }
Expand Down
4 changes: 4 additions & 0 deletions crates/uv-pep440/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
//! the version matching needs to catch all sorts of special cases
#![warn(missing_docs)]

#[cfg(feature = "version-ranges")]
pub use version_ranges_specifier::{VersionRangesSpecifier, VersionRangesSpecifierError};
pub use {
version::{
LocalSegment, Operator, OperatorParseError, Prerelease, PrereleaseKind, Version,
Expand All @@ -39,3 +41,5 @@ mod version_specifier;

#[cfg(test)]
mod tests;
#[cfg(feature = "version-ranges")]
mod version_ranges_specifier;
Original file line number Diff line number Diff line change
@@ -1,66 +1,81 @@
use std::error::Error;
use std::fmt::{Display, Formatter};
use std::ops::Bound;

use itertools::Itertools;
use thiserror::Error;
use version_ranges::Ranges;

use uv_pep440::{Operator, Prerelease, Version, VersionSpecifier, VersionSpecifiers};
use crate::{Operator, Prerelease, Version, VersionSpecifier, VersionSpecifiers};

#[derive(Debug, Error)]
pub enum PubGrubSpecifierError {
#[error("~= operator requires at least two release segments: `{0}`")]
/// The conversion between PEP 440 [`VersionSpecifier`] and version-ranges
/// [`VersionRangesSpecifier`] failed.
#[derive(Debug)]
pub enum VersionRangesSpecifierError {
/// The `~=` operator requires at least two release segments
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.
#[derive(Debug)]
pub struct PubGrubSpecifier(Ranges<Version>);
pub struct VersionRangesSpecifier(Ranges<Version>);

impl PubGrubSpecifier {
/// Returns an iterator over the bounds of the [`PubGrubSpecifier`].
impl VersionRangesSpecifier {
/// Returns an iterator over the bounds of the [`VersionRangesSpecifier`].
pub fn iter(&self) -> impl Iterator<Item = (&Bound<Version>, &Bound<Version>)> {
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>)> {
self.0.bounding_range()
}
}

impl From<Ranges<Version>> for PubGrubSpecifier {
impl From<Ranges<Version>> for VersionRangesSpecifier {
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.
fn from(specifier: PubGrubSpecifier) -> Self {
fn from(specifier: VersionRangesSpecifier) -> Self {
specifier.0
}
}

impl PubGrubSpecifier {
impl VersionRangesSpecifier {
/// Convert [`VersionSpecifiers`] to a PubGrub-compatible version range, using PEP 440
/// semantics.
pub fn from_pep440_specifiers(
specifiers: &VersionSpecifiers,
) -> Result<Self, PubGrubSpecifierError> {
let range = specifiers
.iter()
.map(Self::from_pep440_specifier)
.fold_ok(Ranges::full(), |range, specifier| {
range.intersection(&specifier.into())
})?;
) -> Result<Self, VersionRangesSpecifierError> {
let mut range = Ranges::full();
for specifier in specifiers.iter() {
range = range.intersection(&Self::from_pep440_specifier(specifier)?.into());
}
Ok(Self(range))
}

/// Convert the [`VersionSpecifier`] to a PubGrub-compatible version range, using PEP 440
/// semantics.
pub fn from_pep440_specifier(
specifier: &VersionSpecifier,
) -> Result<Self, PubGrubSpecifierError> {
) -> Result<Self, VersionRangesSpecifierError> {
let ranges = match specifier.operator() {
Operator::Equal => {
let version = specifier.version().clone();
Expand All @@ -76,7 +91,9 @@ impl PubGrubSpecifier {
}
Operator::TildeEqual => {
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)]))
.with_epoch(specifier.version().epoch())
Expand Down Expand Up @@ -167,13 +184,11 @@ impl PubGrubSpecifier {
/// See: <https://github.com/pypa/pip/blob/a432c7f4170b9ef798a15f035f5dfdb4cc939f35/src/pip/_internal/resolution/resolvelib/candidates.py#L540>
pub fn from_release_specifiers(
specifiers: &VersionSpecifiers,
) -> Result<Self, PubGrubSpecifierError> {
let range = specifiers
.iter()
.map(Self::from_release_specifier)
.fold_ok(Ranges::full(), |range, specifier| {
range.intersection(&specifier.into())
})?;
) -> Result<Self, VersionRangesSpecifierError> {
let mut range = Ranges::full();
for specifier in specifiers.iter() {
range = range.intersection(&Self::from_release_specifier(specifier)?.into());
}
Ok(Self(range))
}

Expand All @@ -190,7 +205,7 @@ impl PubGrubSpecifier {
/// See: <https://github.com/pypa/pip/blob/a432c7f4170b9ef798a15f035f5dfdb4cc939f35/src/pip/_internal/resolution/resolvelib/candidates.py#L540>
pub fn from_release_specifier(
specifier: &VersionSpecifier,
) -> Result<Self, PubGrubSpecifierError> {
) -> Result<Self, VersionRangesSpecifierError> {
let ranges = match specifier.operator() {
Operator::Equal => {
let version = specifier.version().only_release();
Expand All @@ -206,7 +221,9 @@ impl PubGrubSpecifier {
}
Operator::TildeEqual => {
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 version = specifier.version().only_release();
Expand Down
1 change: 0 additions & 1 deletion crates/uv-pep508/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ workspace = true
uv-fs = { workspace = true }
uv-normalize = { workspace = true }
uv-pep440 = { workspace = true }
uv-pubgrub = { workspace = true }

boxcar = { workspace = true }
indexmap = { workspace = true }
Expand Down
9 changes: 5 additions & 4 deletions crates/uv-pep508/src/marker/algebra.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,8 @@ use std::sync::MutexGuard;
use itertools::Either;
use rustc_hash::FxHashMap;
use std::sync::LazyLock;
use uv_pep440::Operator;
use uv_pep440::{Operator, VersionRangesSpecifier};
use uv_pep440::{Version, VersionSpecifier};
use uv_pubgrub::PubGrubSpecifier;
use version_ranges::Ranges;

use crate::marker::MarkerValueExtra;
Expand Down Expand Up @@ -746,7 +745,8 @@ impl Edges {
/// Returns the [`Edges`] for a version specifier.
fn from_specifier(specifier: VersionSpecifier) -> Edges {
let specifier =
PubGrubSpecifier::from_release_specifier(&normalize_specifier(specifier)).unwrap();
VersionRangesSpecifier::from_release_specifier(&normalize_specifier(specifier))
.unwrap();
Edges::Version {
edges: Edges::from_range(&specifier.into()),
}
Expand All @@ -764,7 +764,8 @@ impl Edges {
let specifier = VersionSpecifier::equals_version(version.clone());
let specifier = python_version_to_full_version(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());
}

Expand Down
18 changes: 0 additions & 18 deletions crates/uv-pubgrub/Cargo.toml

This file was deleted.

1 change: 0 additions & 1 deletion crates/uv-resolver/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ uv-once-map = { workspace = true }
uv-pep440 = { workspace = true }
uv-pep508 = { workspace = true }
uv-platform-tags = { workspace = true }
uv-pubgrub = { workspace = true }
uv-pypi-types = { workspace = true }
uv-python = { workspace = true }
uv-requirements-txt = { workspace = true }
Expand Down
8 changes: 3 additions & 5 deletions crates/uv-resolver/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ use rustc_hash::FxHashMap;
use crate::candidate_selector::CandidateSelector;
use crate::dependency_provider::UvDependencyProvider;
use crate::fork_urls::ForkUrls;
use crate::pubgrub::{
PubGrubPackage, PubGrubPackageInner, PubGrubReportFormatter, PubGrubSpecifierError,
};
use crate::pubgrub::{PubGrubPackage, PubGrubPackageInner, PubGrubReportFormatter};
use crate::python_requirement::PythonRequirement;
use crate::resolution::ConflictingDistributionError;
use crate::resolver::{IncompletePackage, ResolverMarkers, UnavailablePackage, UnavailableReason};
Expand All @@ -21,7 +19,7 @@ use uv_distribution_types::{
BuiltDist, IndexCapabilities, IndexLocations, IndexUrl, InstalledDist, SourceDist,
};
use uv_normalize::PackageName;
use uv_pep440::Version;
use uv_pep440::{Version, VersionRangesSpecifierError};
use uv_pep508::MarkerTree;
use uv_static::EnvVars;

Expand All @@ -40,7 +38,7 @@ pub enum ResolveError {
UnregisteredTask(String),

#[error(transparent)]
PubGrubSpecifier(#[from] PubGrubSpecifierError),
VersionRangesSpecifier(#[from] VersionRangesSpecifierError),

#[error("Overrides contain conflicting URLs for package `{0}`:\n- {1}\n- {2}")]
ConflictingOverrideUrls(PackageName, String, String),
Expand Down
1 change: 0 additions & 1 deletion crates/uv-resolver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ pub use manifest::Manifest;
pub use options::{Flexibility, Options, OptionsBuilder};
pub use preferences::{Preference, PreferenceError, Preferences};
pub use prerelease::PrereleaseMode;
pub use pubgrub::{PubGrubSpecifier, PubGrubSpecifierError};
pub use python_requirement::PythonRequirement;
pub use requires_python::{RequiresPython, RequiresPythonError, RequiresPythonRange};
pub use resolution::{
Expand Down
Loading

0 comments on commit e5b8cdb

Please sign in to comment.