mirror of https://github.com/astral-sh/uv
Use comparable representation for `PackageId` (#1543)
## Summary By using the display representation of `Version` to form a `PackageId`, we run the risk (as seen in the linked issue) of thinking that versions like `2021.1` and `2021.1.0` are not equivalent. Closes https://github.com/astral-sh/uv/issues/1536
This commit is contained in:
parent
7c08e61b73
commit
b4ea48955b
|
|
@ -1,18 +1,35 @@
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
|
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
use pep440_rs::Version;
|
||||||
|
use uv_normalize::PackageName;
|
||||||
|
|
||||||
/// A unique identifier for a package (e.g., `black==23.10.0`).
|
/// A unique identifier for a package (e.g., `black==23.10.0`).
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
pub struct PackageId(String);
|
pub enum PackageId {
|
||||||
|
NameVersion(PackageName, Version),
|
||||||
|
Url(String),
|
||||||
|
}
|
||||||
|
|
||||||
impl PackageId {
|
impl PackageId {
|
||||||
pub fn new(id: impl Into<String>) -> Self {
|
/// Create a new [`PackageId`] from a package name and version.
|
||||||
Self(id.into())
|
pub fn from_registry(name: PackageName, version: Version) -> Self {
|
||||||
|
Self::NameVersion(name, version)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new [`PackageId`] from a URL.
|
||||||
|
pub fn from_url(url: &Url) -> Self {
|
||||||
|
Self::Url(cache_key::digest(&cache_key::CanonicalUrl::new(url)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for PackageId {
|
impl Display for PackageId {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
f.write_str(&self.0)
|
match self {
|
||||||
|
PackageId::NameVersion(name, version) => write!(f, "{name}-{version}"),
|
||||||
|
PackageId::Url(url) => write!(f, "{url}"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,14 +31,12 @@ pub trait DistributionMetadata: Name {
|
||||||
/// registry-based distributions (e.g., different wheels for the same package and version)
|
/// registry-based distributions (e.g., different wheels for the same package and version)
|
||||||
/// will return the same package ID, but different distribution IDs.
|
/// will return the same package ID, but different distribution IDs.
|
||||||
fn package_id(&self) -> PackageId {
|
fn package_id(&self) -> PackageId {
|
||||||
PackageId::new(match self.version_or_url() {
|
match self.version_or_url() {
|
||||||
VersionOrUrl::Version(version) => {
|
VersionOrUrl::Version(version) => {
|
||||||
// https://packaging.python.org/en/latest/specifications/recording-installed-packages/#the-dist-info-directory
|
PackageId::from_registry(self.name().clone(), version.clone())
|
||||||
// `version` is normalized by its `ToString` impl
|
|
||||||
format!("{}-{}", self.name(), version)
|
|
||||||
}
|
}
|
||||||
VersionOrUrl::Url(url) => cache_key::digest(&cache_key::CanonicalUrl::new(url)),
|
VersionOrUrl::Url(url) => PackageId::from_url(url),
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3376,3 +3376,31 @@ fn compile_none_extra() -> Result<()> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resolve a package (`pytz`) with a preference that omits a trailing zero.
|
||||||
|
///
|
||||||
|
/// See: <https://github.com/astral-sh/uv/issues/1536>
|
||||||
|
#[test]
|
||||||
|
fn compile_types_pytz() -> Result<()> {
|
||||||
|
let context = TestContext::new("3.12");
|
||||||
|
let requirements_in = context.temp_dir.child("requirements.in");
|
||||||
|
requirements_in.write_str("types-pytz")?;
|
||||||
|
|
||||||
|
let requirements_txt = context.temp_dir.child("requirements.txt");
|
||||||
|
requirements_txt.write_str("types-pytz==2021.1")?;
|
||||||
|
|
||||||
|
uv_snapshot!(context
|
||||||
|
.compile()
|
||||||
|
.arg("requirements.in")
|
||||||
|
.arg("-o")
|
||||||
|
.arg("requirements.txt"), @r###"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Resolved 1 package in [TIME]
|
||||||
|
"###);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue