mirror of
https://github.com/astral-sh/uv.git
synced 2025-10-01 14:31:12 +00:00
Stable sorting of requirements.txt in universal mode (#5334)
The `RequirementsTxtComparator` was written assuming there is one distribution per package name. This changed with the universal resolution, which allows multiple versions or urls for the same package name. The sorting we emitted for these new entries was incidental. With this change, we properly sort these entries by name, version and then url in universal mode. This is an output format change for `--universal` users.
This commit is contained in:
parent
43084249ee
commit
bea8bc6c61
4 changed files with 34 additions and 10 deletions
|
@ -241,6 +241,7 @@ impl ResolutionGraph {
|
|||
// Add the distribution to the graph.
|
||||
let index = petgraph.add_node(ResolutionGraphNode::Dist(AnnotatedDist {
|
||||
dist,
|
||||
version: version.clone(),
|
||||
extra: extra.clone(),
|
||||
dev: dev.clone(),
|
||||
hashes,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use std::fmt::Display;
|
||||
|
||||
use distribution_types::{DistributionMetadata, Name, ResolvedDist, VersionOrUrlRef};
|
||||
use pep440_rs::Version;
|
||||
use pypi_types::HashDigest;
|
||||
use uv_distribution::Metadata;
|
||||
use uv_normalize::{ExtraName, GroupName, PackageName};
|
||||
|
@ -20,6 +21,7 @@ mod requirements_txt;
|
|||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct AnnotatedDist {
|
||||
pub(crate) dist: ResolvedDist,
|
||||
pub(crate) version: Version,
|
||||
pub(crate) extra: Option<ExtraName>,
|
||||
pub(crate) dev: Option<GroupName>,
|
||||
pub(crate) hashes: Vec<HashDigest>,
|
||||
|
|
|
@ -5,6 +5,7 @@ use std::path::Path;
|
|||
use itertools::Itertools;
|
||||
|
||||
use distribution_types::{DistributionMetadata, Name, ResolvedDist, Verbatim, VersionOrUrlRef};
|
||||
use pep440_rs::Version;
|
||||
use pep508_rs::{split_scheme, MarkerTree, Scheme};
|
||||
use pypi_types::HashDigest;
|
||||
use uv_normalize::{ExtraName, PackageName};
|
||||
|
@ -15,6 +16,7 @@ use crate::resolution::AnnotatedDist;
|
|||
/// A pinned package with its resolved distribution and all the extras that were pinned for it.
|
||||
pub(crate) struct RequirementsTxtDist {
|
||||
pub(crate) dist: ResolvedDist,
|
||||
pub(crate) version: Version,
|
||||
pub(crate) extras: Vec<ExtraName>,
|
||||
pub(crate) hashes: Vec<HashDigest>,
|
||||
pub(crate) markers: Option<MarkerTree>,
|
||||
|
@ -133,7 +135,19 @@ impl RequirementsTxtDist {
|
|||
}
|
||||
}
|
||||
|
||||
RequirementsTxtComparator::Name(self.name())
|
||||
if let VersionOrUrlRef::Url(url) = self.version_or_url() {
|
||||
RequirementsTxtComparator::Name {
|
||||
name: self.name(),
|
||||
version: &self.version,
|
||||
url: Some(url.verbatim()),
|
||||
}
|
||||
} else {
|
||||
RequirementsTxtComparator::Name {
|
||||
name: self.name(),
|
||||
version: &self.version,
|
||||
url: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -141,6 +155,7 @@ impl From<&AnnotatedDist> for RequirementsTxtDist {
|
|||
fn from(annotated: &AnnotatedDist) -> Self {
|
||||
Self {
|
||||
dist: annotated.dist.clone(),
|
||||
version: annotated.version.clone(),
|
||||
extras: if let Some(extra) = annotated.extra.clone() {
|
||||
vec![extra]
|
||||
} else {
|
||||
|
@ -155,7 +170,13 @@ impl From<&AnnotatedDist> for RequirementsTxtDist {
|
|||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub(crate) enum RequirementsTxtComparator<'a> {
|
||||
Url(Cow<'a, str>),
|
||||
Name(&'a PackageName),
|
||||
/// In universal mode, we can have multiple versions for a package, so we track the version and
|
||||
/// the URL (for non-index packages) to have a stable sort for those, too.
|
||||
Name {
|
||||
name: &'a PackageName,
|
||||
version: &'a Version,
|
||||
url: Option<Cow<'a, str>>,
|
||||
},
|
||||
}
|
||||
|
||||
impl Name for RequirementsTxtDist {
|
||||
|
|
|
@ -7250,13 +7250,13 @@ fn universal_nested_overlapping_local_requirement() -> Result<()> {
|
|||
# via torch
|
||||
tbb==2021.11.0 ; platform_machine != 'x86_64' and platform_system == 'Windows'
|
||||
# via mkl
|
||||
torch==2.3.0 ; platform_machine != 'x86_64'
|
||||
# via -r requirements.in
|
||||
torch==2.0.0+cu118 ; platform_machine == 'x86_64'
|
||||
# via
|
||||
# -r requirements.in
|
||||
# example
|
||||
# triton
|
||||
torch==2.3.0 ; platform_machine != 'x86_64'
|
||||
# via -r requirements.in
|
||||
triton==2.0.0 ; platform_machine == 'x86_64' and platform_system == 'Linux'
|
||||
# via torch
|
||||
typing-extensions==4.10.0
|
||||
|
@ -7324,13 +7324,13 @@ fn universal_nested_overlapping_local_requirement() -> Result<()> {
|
|||
# via torch
|
||||
tbb==2021.11.0 ; platform_machine != 'x86_64' and platform_system == 'Windows'
|
||||
# via mkl
|
||||
torch==2.3.0 ; platform_machine != 'x86_64'
|
||||
# via -r requirements.in
|
||||
torch==2.0.0+cu118 ; platform_machine == 'x86_64'
|
||||
# via
|
||||
# -r requirements.in
|
||||
# example
|
||||
# triton
|
||||
torch==2.3.0 ; platform_machine != 'x86_64'
|
||||
# via -r requirements.in
|
||||
triton==2.0.0 ; platform_machine == 'x86_64' and platform_system == 'Linux'
|
||||
# via torch
|
||||
typing-extensions==4.10.0
|
||||
|
@ -7440,6 +7440,10 @@ fn universal_nested_disjoint_local_requirement() -> Result<()> {
|
|||
# via torch
|
||||
tbb==2021.11.0 ; os_name != 'Linux' and platform_system == 'Windows'
|
||||
# via mkl
|
||||
torch==2.0.0+cpu ; os_name == 'Linux'
|
||||
# via
|
||||
# -r requirements.in
|
||||
# example
|
||||
torch==2.0.0+cu118 ; os_name == 'Linux'
|
||||
# via
|
||||
# -r requirements.in
|
||||
|
@ -7447,10 +7451,6 @@ fn universal_nested_disjoint_local_requirement() -> Result<()> {
|
|||
# triton
|
||||
torch==2.3.0 ; os_name != 'Linux'
|
||||
# via -r requirements.in
|
||||
torch==2.0.0+cpu ; os_name == 'Linux'
|
||||
# via
|
||||
# -r requirements.in
|
||||
# example
|
||||
triton==2.0.0 ; os_name == 'Linux' and platform_machine == 'x86_64' and platform_system == 'Linux'
|
||||
# via torch
|
||||
typing-extensions==4.10.0
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue