Use separate types to represent raw vs. resolver markers (#6646)

## Summary

This is similar to https://github.com/astral-sh/uv/pull/6171 but more
expansive... _Anywhere_ that we test requirements for platform
compatibility, we _need_ to respect the resolver-friendly markers. In
fixing the motivating issue (#6621), I also realized that we had a bunch
of bugs here around `pip install` with `--python-platform` and
`--python-version`, because we always performed our `satisfy` and `Plan`
operations on the interpreter's markers, not the adjusted markers!

Closes https://github.com/astral-sh/uv/issues/6621.
This commit is contained in:
Charlie Marsh 2024-08-26 14:00:21 -04:00 committed by GitHub
parent 6220532373
commit a7850d2a1c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
37 changed files with 422 additions and 247 deletions

View file

@ -1,6 +1,7 @@
pub use base_url::*;
pub use direct_url::*;
pub use lenient_requirement::*;
pub use marker_environment::*;
pub use metadata::*;
pub use parsed_url::*;
pub use requirement::*;
@ -10,6 +11,7 @@ pub use simple_json::*;
mod base_url;
mod direct_url;
mod lenient_requirement;
mod marker_environment;
mod metadata;
mod parsed_url;
mod requirement;

View file

@ -0,0 +1,53 @@
use tracing::debug;
use pep508_rs::MarkerEnvironment;
/// A wrapper type around [`MarkerEnvironment`] that ensures the Python version markers are
/// release-only, to match the resolver's semantics.
#[derive(Debug, Clone)]
pub struct ResolverMarkerEnvironment(MarkerEnvironment);
impl ResolverMarkerEnvironment {
/// Returns the underlying [`MarkerEnvironment`].
pub fn markers(&self) -> &MarkerEnvironment {
&self.0
}
}
impl From<MarkerEnvironment> for ResolverMarkerEnvironment {
fn from(value: MarkerEnvironment) -> Self {
// Strip `python_version`.
let python_version = value.python_version().only_release();
let value = if python_version == **value.python_version() {
value
} else {
debug!(
"Stripping pre-release from `python_version`: {}",
value.python_version()
);
value.with_python_version(python_version)
};
// Strip `python_full_version`.
let python_full_version = value.python_full_version().only_release();
let value = if python_full_version == **value.python_full_version() {
value
} else {
debug!(
"Stripping pre-release from `python_full_version`: {}",
value.python_full_version()
);
value.with_python_full_version(python_full_version)
};
Self(value)
}
}
impl std::ops::Deref for ResolverMarkerEnvironment {
type Target = MarkerEnvironment;
fn deref(&self) -> &Self::Target {
&self.0
}
}