Skip to content

Commit

Permalink
Add heuristic
Browse files Browse the repository at this point in the history
  • Loading branch information
charliermarsh committed Dec 16, 2024
1 parent f3e0a90 commit 1f2f366
Show file tree
Hide file tree
Showing 19 changed files with 2,544 additions and 1,758 deletions.
64 changes: 39 additions & 25 deletions crates/uv-distribution-types/src/prioritized_distribution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ struct PrioritizedDistInner {
wheels: Vec<(RegistryBuiltWheel, WheelCompatibility)>,
/// The hashes for each distribution.
hashes: Vec<HashDigest>,
/// The implied markers.
/// The set of supported platforms for the distribution, described in terms of their markers.
markers: MarkerTree,
}

Expand Down Expand Up @@ -86,6 +86,7 @@ impl CompatibleDist<'_> {
}
}

/// Return the set of supported platform the distribution, in terms of their markers.
pub fn implied_markers(&self) -> MarkerTree {
match self {
CompatibleDist::InstalledDist(_) => MarkerTree::TRUE,
Expand Down Expand Up @@ -118,6 +119,9 @@ impl IncompatibleDist {
None => format!("has {self}"),
},
IncompatibleWheel::RequiresPython(..) => format!("requires {self}"),
IncompatibleWheel::MissingPlatform(_) => {
format!("has {self}")
}
},
Self::Source(incompatibility) => match incompatibility {
IncompatibleSource::NoBuild => format!("has {self}"),
Expand Down Expand Up @@ -145,6 +149,9 @@ impl IncompatibleDist {
None => format!("have {self}"),
},
IncompatibleWheel::RequiresPython(..) => format!("require {self}"),
IncompatibleWheel::MissingPlatform(_) => {
format!("have {self}")
}
},
Self::Source(incompatibility) => match incompatibility {
IncompatibleSource::NoBuild => format!("have {self}"),
Expand Down Expand Up @@ -197,6 +204,9 @@ impl Display for IncompatibleDist {
IncompatibleWheel::RequiresPython(python, _) => {
write!(f, "Python {python}")
}
IncompatibleWheel::MissingPlatform(platform) => {
write!(f, "no {platform}-compatible wheels")
}
},
Self::Source(incompatibility) => match incompatibility {
IncompatibleSource::NoBuild => {
Expand Down Expand Up @@ -251,6 +261,8 @@ pub enum IncompatibleWheel {
Yanked(Yanked),
/// The use of binary wheels is disabled.
NoBinary,
/// The distribution is missing support for the target platform.
MissingPlatform(String),
}

#[derive(Debug, Clone, PartialEq, Eq)]
Expand Down Expand Up @@ -598,6 +610,7 @@ impl IncompatibleSource {
}

impl IncompatibleWheel {
#[allow(clippy::match_like_matches_macro)]
fn is_more_compatible(&self, other: &Self) -> bool {
match self {
Self::ExcludeNewer(timestamp_self) => match other {
Expand All @@ -609,28 +622,40 @@ impl IncompatibleWheel {
timestamp_other < timestamp_self
}
},
Self::NoBinary | Self::RequiresPython(_, _) | Self::Tag(_) | Self::Yanked(_) => {
true
}
Self::MissingPlatform(_)
| Self::NoBinary
| Self::RequiresPython(_, _)
| Self::Tag(_)
| Self::Yanked(_) => true,
},
Self::Tag(tag_self) => match other {
Self::ExcludeNewer(_) => false,
Self::Tag(tag_other) => tag_self > tag_other,
Self::NoBinary | Self::RequiresPython(_, _) | Self::Yanked(_) => true,
Self::MissingPlatform(_)
| Self::NoBinary
| Self::RequiresPython(_, _)
| Self::Yanked(_) => true,
},
Self::RequiresPython(_, _) => match other {
Self::ExcludeNewer(_) | Self::Tag(_) => false,
// Version specifiers cannot be reasonably compared
Self::RequiresPython(_, _) => false,
Self::NoBinary | Self::Yanked(_) => true,
Self::MissingPlatform(_) | Self::NoBinary | Self::Yanked(_) => true,
},
Self::Yanked(_) => match other {
Self::ExcludeNewer(_) | Self::Tag(_) | Self::RequiresPython(_, _) => false,
// Yanks with a reason are more helpful for errors
Self::Yanked(yanked_other) => matches!(yanked_other, Yanked::Reason(_)),
Self::NoBinary => true,
Self::MissingPlatform(_) | Self::NoBinary => true,
},
Self::NoBinary => match other {
Self::MissingPlatform(_) => true,
_ => false,
},
Self::MissingPlatform(platform_other) => match other {
Self::MissingPlatform(platform_self) => platform_self > platform_other,
_ => false,
},
Self::NoBinary => false,
}
}
}
Expand All @@ -648,34 +673,23 @@ pub fn implied_markers(filename: &WheelFilename) -> MarkerTree {
value: "win32".to_string(),
}));
}
tag if tag.starts_with("manylinux") => {
marker.or(MarkerTree::expression(MarkerExpression::String {
key: MarkerValueString::SysPlatform,
operator: MarkerOperator::Equal,
value: "linux".to_string(),
}));
}
tag if tag.starts_with("musllinux") => {
tag if tag.starts_with("macosx") => {
marker.or(MarkerTree::expression(MarkerExpression::String {
key: MarkerValueString::SysPlatform,
operator: MarkerOperator::Equal,
value: "linux".to_string(),
value: "darwin".to_string(),
}));
}
tag if tag.starts_with("linux") => {
tag if tag.starts_with("manylinux")
|| tag.starts_with("musllinux")
|| tag.starts_with("linux") =>
{
marker.or(MarkerTree::expression(MarkerExpression::String {
key: MarkerValueString::SysPlatform,
operator: MarkerOperator::Equal,
value: "linux".to_string(),
}));
}
tag if tag.starts_with("macosx") => {
marker.or(MarkerTree::expression(MarkerExpression::String {
key: MarkerValueString::SysPlatform,
operator: MarkerOperator::Equal,
value: "darwin".to_string(),
}));
}
_ => {}
}
}
Expand Down
52 changes: 0 additions & 52 deletions crates/uv-pep508/src/marker/algebra.rs
Original file line number Diff line number Diff line change
Expand Up @@ -984,58 +984,6 @@ impl InternerGuard<'_> {
let a_and_b = conjunction(self, a, b);
tree = disjunction(self, tree, a_and_b);
}

// These are markers that must have the same value (i.e., they must both be true or both be
// false).
for (a, b) in [
// sys_platform == 'win32' and platform_system == 'Windows'
(
MarkerExpression::String {
key: MarkerValueString::SysPlatform,
operator: MarkerOperator::Equal,
value: "win32".to_string(),
},
MarkerExpression::String {
key: MarkerValueString::PlatformSystem,
operator: MarkerOperator::Equal,
value: "Windows".to_string(),
},
),
// sys_platform == 'darwin' and platform_system == 'Darwin'
(
MarkerExpression::String {
key: MarkerValueString::SysPlatform,
operator: MarkerOperator::Equal,
value: "darwin".to_string(),
},
MarkerExpression::String {
key: MarkerValueString::PlatformSystem,
operator: MarkerOperator::Equal,
value: "Darwin".to_string(),
},
),
// sys_platform == 'linux' and platform_system == 'Linux'
(
MarkerExpression::String {
key: MarkerValueString::SysPlatform,
operator: MarkerOperator::Equal,
value: "linux".to_string(),
},
MarkerExpression::String {
key: MarkerValueString::PlatformSystem,
operator: MarkerOperator::Equal,
value: "Linux".to_string(),
},
),
] {
let a = self.expression(a);
let b = self.expression(b);
let a_and_not_b = conjunction(self, a, b.not());
let not_a_and_b = conjunction(self, a.not(), b);
tree = disjunction(self, tree, a_and_not_b);
tree = disjunction(self, tree, not_a_and_b);
}

self.state.exclusions = Some(tree);
tree
}
Expand Down
19 changes: 0 additions & 19 deletions crates/uv-pep508/src/marker/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1165,25 +1165,6 @@ impl MarkerTree {
_ => None,
}))
}

pub fn references_platform(self) -> bool {
match self.kind() {
MarkerTreeKind::True => false,
MarkerTreeKind::False => false,
MarkerTreeKind::Version(marker) => {
false
}
MarkerTreeKind::String(marker) => {
matches!(marker.key, CanonicalMarkerValueString::SysPlatform) ||
marker
.children()
.any(|(_, tree)| tree.references_platform())
}
MarkerTreeKind::In(marker) => false,
MarkerTreeKind::Contains(marker) => false,
MarkerTreeKind::Extra(marker) => false,
}
}
}

impl fmt::Debug for MarkerTree {
Expand Down
2 changes: 1 addition & 1 deletion crates/uv-resolver/src/resolver/environment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,7 @@ pub(crate) fn fork_version_by_marker(

// Attempt to split based on the marker.
//
// For example, given `python_version >= '3.10'` and the split marker `sys_platform == 'linux'`,
// For example, given `python_version >= '3.10'` and the split marker `sys_platform == 'linux'`,
// the result will be:
//
// `python_version >= '3.10' and sys_platform == 'linux'`
Expand Down
36 changes: 13 additions & 23 deletions crates/uv-resolver/src/resolver/markers.rs
Original file line number Diff line number Diff line change
@@ -1,36 +1,26 @@
use std::sync::Arc;

use rustc_hash::{FxHashMap, FxHashSet};
use rustc_hash::FxHashMap;

use uv_normalize::PackageName;
use uv_pep440::Version;
use uv_pep508::MarkerTree;
use uv_pypi_types::RequirementSource;

use crate::{DependencyMode, Manifest, ResolverEnvironment};

/// A set of package versions that are permitted, even if they're marked as yanked by the
/// relevant index.
/// The superset of markers for which a package is known to be relevant.
///
/// These markers may not represent the exact set of relevant environments, as they aren't adjusted
/// when backtracking; instead, we only _add_ to this set over the course of the resolution. As
/// such, the marker value represents a superset of the environments in which the package is known
/// to be included, but it may include environments in which the package is ultimately excluded.
#[derive(Debug, Default, Clone)]
pub(crate) struct KnownMarkers(Arc<FxHashMap<PackageName, MarkerTree>>);

impl KnownMarkers {
pub(crate) fn from_manifest(
manifest: &Manifest,
env: &ResolverEnvironment,
dependencies: DependencyMode,
) -> Self {
let mut known_markers = FxHashMap::<PackageName, MarkerTree>::default();

// Allow yanks for any pinned input requirements.
for requirement in manifest.requirements(env, dependencies) {
known_markers
.entry(requirement.name.clone())
.or_insert(MarkerTree::FALSE)
.or(requirement.marker);
}

Self(Arc::new(known_markers))
/// Inserts the given [`MarkerTree`] for the given package name.
pub(crate) fn insert(&mut self, package_name: PackageName, marker_tree: MarkerTree) {
Arc::make_mut(&mut self.0)
.entry(package_name)
.or_insert(MarkerTree::FALSE)
.or(marker_tree);
}

/// Returns the [`MarkerTree`] for the given package name, if it exists.
Expand Down
Loading

0 comments on commit 1f2f366

Please sign in to comment.