Use structured wheel tags everywhere (#10542)
## Summary This PR extends the thinking in #10525 to platform tags, and then uses the structured tag enums everywhere, rather than passing around strings. I think this is a big improvement! It means we're no longer doing ad hoc tag parsing all over the place.
This commit is contained in:
@@ -7,7 +7,7 @@ use pubgrub::Range;
|
||||
use uv_distribution_filename::WheelFilename;
|
||||
use uv_pep440::{release_specifiers_to_ranges, Version, VersionSpecifier, VersionSpecifiers};
|
||||
use uv_pep508::{MarkerExpression, MarkerTree, MarkerValueVersion};
|
||||
use uv_platform_tags::AbiTag;
|
||||
use uv_platform_tags::{AbiTag, LanguageTag};
|
||||
|
||||
/// The `Requires-Python` requirement specifier.
|
||||
///
|
||||
@@ -381,53 +381,73 @@ impl RequiresPython {
|
||||
/// sensitivity, we return `true` if the tags are unknown.
|
||||
pub fn matches_wheel_tag(&self, wheel: &WheelFilename) -> bool {
|
||||
wheel.abi_tag.iter().any(|abi_tag| {
|
||||
if abi_tag == "abi3" {
|
||||
if *abi_tag == AbiTag::Abi3 {
|
||||
// Universal tags are allowed.
|
||||
true
|
||||
} else if abi_tag == "none" {
|
||||
} else if *abi_tag == AbiTag::None {
|
||||
wheel.python_tag.iter().any(|python_tag| {
|
||||
// Remove `py2-none-any` and `py27-none-any` and analogous `cp` and `pp` tags.
|
||||
if python_tag.starts_with("py2")
|
||||
|| python_tag.starts_with("cp2")
|
||||
|| python_tag.starts_with("pp2")
|
||||
{
|
||||
if matches!(
|
||||
python_tag,
|
||||
LanguageTag::Python { major: 2, .. }
|
||||
| LanguageTag::CPython {
|
||||
python_version: (2, ..)
|
||||
}
|
||||
| LanguageTag::PyPy {
|
||||
python_version: (2, ..)
|
||||
}
|
||||
| LanguageTag::GraalPy {
|
||||
python_version: (2, ..)
|
||||
}
|
||||
| LanguageTag::Pyston {
|
||||
python_version: (2, ..)
|
||||
}
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove (e.g.) `py312-none-any` if the specifier is `==3.10.*`. However,
|
||||
// `py37-none-any` would be fine, since the `3.7` represents a lower bound.
|
||||
if let Some(minor) = python_tag.strip_prefix("py3") {
|
||||
let Ok(minor) = minor.parse::<u64>() else {
|
||||
return true;
|
||||
};
|
||||
|
||||
if let LanguageTag::Python {
|
||||
major: 3,
|
||||
minor: Some(minor),
|
||||
} = python_tag
|
||||
{
|
||||
// Ex) If the wheel bound is `3.12`, then it doesn't match `<=3.10.`.
|
||||
let wheel_bound = UpperBound(Bound::Included(Version::new([3, minor])));
|
||||
let wheel_bound =
|
||||
UpperBound(Bound::Included(Version::new([3, u64::from(*minor)])));
|
||||
if wheel_bound > self.range.upper().major_minor() {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
// Remove (e.g.) `cp36-none-any` or `cp312-none-any` if the specifier is
|
||||
// `==3.10.*`, since these tags require an exact match.
|
||||
if let Some(minor) = python_tag
|
||||
.strip_prefix("cp3")
|
||||
.or_else(|| python_tag.strip_prefix("pp3"))
|
||||
if let LanguageTag::CPython {
|
||||
python_version: (3, minor),
|
||||
}
|
||||
| LanguageTag::PyPy {
|
||||
python_version: (3, minor),
|
||||
}
|
||||
| LanguageTag::GraalPy {
|
||||
python_version: (3, minor),
|
||||
}
|
||||
| LanguageTag::Pyston {
|
||||
python_version: (3, minor),
|
||||
} = python_tag
|
||||
{
|
||||
let Ok(minor) = minor.parse::<u64>() else {
|
||||
return true;
|
||||
};
|
||||
|
||||
// Ex) If the wheel bound is `3.6`, then it doesn't match `>=3.10`.
|
||||
let wheel_bound = LowerBound(Bound::Included(Version::new([3, minor])));
|
||||
let wheel_bound =
|
||||
LowerBound(Bound::Included(Version::new([3, u64::from(*minor)])));
|
||||
if wheel_bound < self.range.lower().major_minor() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ex) If the wheel bound is `3.12`, then it doesn't match `<=3.10.`.
|
||||
let wheel_bound = UpperBound(Bound::Included(Version::new([3, minor])));
|
||||
let wheel_bound =
|
||||
UpperBound(Bound::Included(Version::new([3, u64::from(*minor)])));
|
||||
if wheel_bound > self.range.upper().major_minor() {
|
||||
return false;
|
||||
}
|
||||
@@ -438,50 +458,49 @@ impl RequiresPython {
|
||||
// Unknown tags are allowed.
|
||||
true
|
||||
})
|
||||
} else if abi_tag.starts_with("cp2") || abi_tag.starts_with("pypy2") {
|
||||
} else if matches!(
|
||||
abi_tag,
|
||||
AbiTag::CPython {
|
||||
python_version: (2, ..),
|
||||
..
|
||||
} | AbiTag::PyPy {
|
||||
python_version: (2, ..),
|
||||
..
|
||||
} | AbiTag::GraalPy {
|
||||
python_version: (2, ..),
|
||||
..
|
||||
} | AbiTag::Pyston {
|
||||
python_version: (2, ..),
|
||||
..
|
||||
}
|
||||
) {
|
||||
// Python 2 is never allowed.
|
||||
false
|
||||
} else if let Some(minor_no_dot_abi) = abi_tag.strip_prefix("cp3") {
|
||||
// Remove ABI tags, both old (dmu) and future (t, and all other letters).
|
||||
let minor_not_dot = minor_no_dot_abi.trim_matches(char::is_alphabetic);
|
||||
let Ok(minor) = minor_not_dot.parse::<u64>() else {
|
||||
// Unknown version pattern are allowed.
|
||||
return true;
|
||||
};
|
||||
|
||||
} else if let AbiTag::CPython {
|
||||
python_version: (3, minor),
|
||||
..
|
||||
}
|
||||
| AbiTag::PyPy {
|
||||
python_version: (3, minor),
|
||||
..
|
||||
}
|
||||
| AbiTag::GraalPy {
|
||||
python_version: (3, minor),
|
||||
..
|
||||
}
|
||||
| AbiTag::Pyston {
|
||||
python_version: (3, minor),
|
||||
..
|
||||
} = abi_tag
|
||||
{
|
||||
// Ex) If the wheel bound is `3.6`, then it doesn't match `>=3.10`.
|
||||
let wheel_bound = LowerBound(Bound::Included(Version::new([3, minor])));
|
||||
let wheel_bound = LowerBound(Bound::Included(Version::new([3, u64::from(*minor)])));
|
||||
if wheel_bound < self.range.lower().major_minor() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ex) If the wheel bound is `3.12`, then it doesn't match `<=3.10.`.
|
||||
let wheel_bound = UpperBound(Bound::Included(Version::new([3, minor])));
|
||||
if wheel_bound > self.range.upper().major_minor() {
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
} else if let Some(minor_no_dot_abi) = abi_tag.strip_prefix("pypy3") {
|
||||
// Given `pypy39_pp73`, we just removed `pypy3`, now we remove `_pp73` ...
|
||||
let Some((minor_not_dot, _)) = minor_no_dot_abi.split_once('_') else {
|
||||
// Unknown version pattern are allowed.
|
||||
return true;
|
||||
};
|
||||
// ... and get `9`.
|
||||
let Ok(minor) = minor_not_dot.parse::<u64>() else {
|
||||
// Unknown version pattern are allowed.
|
||||
return true;
|
||||
};
|
||||
|
||||
// Ex) If the wheel bound is `3.6`, then it doesn't match `>=3.10`.
|
||||
let wheel_bound = LowerBound(Bound::Included(Version::new([3, minor])));
|
||||
if wheel_bound < self.range.lower().major_minor() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ex) If the wheel bound is `3.12`, then it doesn't match `<=3.10.`.
|
||||
let wheel_bound = UpperBound(Bound::Included(Version::new([3, minor])));
|
||||
let wheel_bound = UpperBound(Bound::Included(Version::new([3, u64::from(*minor)])));
|
||||
if wheel_bound > self.range.upper().major_minor() {
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user