mirror of https://github.com/astral-sh/uv
Use generic marker variant mechanism
This commit is contained in:
parent
1fcf0ebe52
commit
c406b70965
|
|
@ -11,7 +11,8 @@ use uv_git_types::{GitOid, GitReference, GitUrl, GitUrlParseError, OidParseError
|
|||
use uv_normalize::{ExtraName, GroupName, PackageName};
|
||||
use uv_pep440::VersionSpecifiers;
|
||||
use uv_pep508::{
|
||||
MarkerEnvironment, MarkerTree, RequirementOrigin, VerbatimUrl, VersionOrUrl, marker,
|
||||
MarkerEnvironment, MarkerTree, MarkerVariantsEnvironment, RequirementOrigin, VerbatimUrl,
|
||||
VersionOrUrl, marker,
|
||||
};
|
||||
use uv_redacted::DisplaySafeUrl;
|
||||
|
||||
|
|
@ -72,7 +73,7 @@ impl Requirement {
|
|||
pub fn evaluate_markers(
|
||||
&self,
|
||||
env: Option<&MarkerEnvironment>,
|
||||
variants: Option<&[(String, String, String)]>,
|
||||
variants: impl MarkerVariantsEnvironment,
|
||||
extras: &[ExtraName],
|
||||
) -> bool {
|
||||
self.marker
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::borrow::Cow;
|
|||
use std::fmt::{Display, Formatter};
|
||||
|
||||
use uv_normalize::ExtraName;
|
||||
use uv_pep508::{MarkerEnvironment, UnnamedRequirement};
|
||||
use uv_pep508::{MarkerEnvironment, MarkerVariantsEnvironment, UnnamedRequirement};
|
||||
use uv_pypi_types::Hashes;
|
||||
|
||||
use crate::{Requirement, RequirementSource, VerbatimParsedUrl};
|
||||
|
|
@ -62,7 +62,7 @@ impl UnresolvedRequirement {
|
|||
pub fn evaluate_markers(
|
||||
&self,
|
||||
env: Option<&MarkerEnvironment>,
|
||||
variants: Option<&[(String, String, String)]>,
|
||||
variants: impl MarkerVariantsEnvironment,
|
||||
extras: &[ExtraName],
|
||||
) -> bool {
|
||||
match self {
|
||||
|
|
|
|||
|
|
@ -641,7 +641,7 @@ impl<'a, Context: BuildContext> DistributionDatabase<'a, Context> {
|
|||
// TODO(konsti): We shouldn't need to do this conversion.
|
||||
let mut known_properties = BTreeSet::default();
|
||||
for variant in variants_json.variants.values() {
|
||||
for (namespace, features) in variant {
|
||||
for (namespace, features) in &**variant {
|
||||
for (feature, value) in features {
|
||||
for value in value {
|
||||
known_properties.insert(VariantPropertyType {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use uv_distribution_types::{
|
|||
use uv_fs::Simplified;
|
||||
use uv_normalize::PackageName;
|
||||
use uv_pep440::{Version, VersionSpecifiers};
|
||||
use uv_pep508::VersionOrUrl;
|
||||
use uv_pep508::{MarkerVariantsUniversal, VersionOrUrl};
|
||||
use uv_pypi_types::{ResolverMarkerEnvironment, VerbatimParsedUrl};
|
||||
use uv_python::{Interpreter, PythonEnvironment};
|
||||
use uv_redacted::DisplaySafeUrl;
|
||||
|
|
@ -243,7 +243,7 @@ impl SitePackages {
|
|||
|
||||
// Verify that the dependencies are installed.
|
||||
for dependency in &metadata.requires_dist {
|
||||
if !dependency.evaluate_markers(markers, None, &[]) {
|
||||
if !dependency.evaluate_markers(markers, MarkerVariantsUniversal, &[]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -416,7 +416,7 @@ impl SitePackages {
|
|||
for requirement in requirements {
|
||||
if let Some(r#overrides) = overrides.get(&requirement.name) {
|
||||
for dependency in r#overrides {
|
||||
if dependency.evaluate_markers(Some(markers), None, &[]) {
|
||||
if dependency.evaluate_markers(Some(markers), MarkerVariantsUniversal, &[]) {
|
||||
if seen.insert((*dependency).clone()) {
|
||||
stack.push(Cow::Borrowed(*dependency));
|
||||
}
|
||||
|
|
@ -424,7 +424,7 @@ impl SitePackages {
|
|||
}
|
||||
} else {
|
||||
// TODO(konsti): Evaluate variants
|
||||
if requirement.evaluate_markers(Some(markers), None, &[]) {
|
||||
if requirement.evaluate_markers(Some(markers), MarkerVariantsUniversal, &[]) {
|
||||
if seen.insert(requirement.clone()) {
|
||||
stack.push(Cow::Borrowed(requirement));
|
||||
}
|
||||
|
|
@ -443,7 +443,7 @@ impl SitePackages {
|
|||
}
|
||||
[distribution] => {
|
||||
// Validate that the requirement is satisfied.
|
||||
if requirement.evaluate_markers(Some(markers), None, &[]) {
|
||||
if requirement.evaluate_markers(Some(markers), MarkerVariantsUniversal, &[]) {
|
||||
match RequirementSatisfaction::check(distribution, &requirement.source) {
|
||||
RequirementSatisfaction::Mismatch
|
||||
| RequirementSatisfaction::OutOfDate
|
||||
|
|
@ -456,7 +456,8 @@ impl SitePackages {
|
|||
|
||||
// Validate that the installed version satisfies the constraints.
|
||||
for constraint in constraints.get(name).into_iter().flatten() {
|
||||
if constraint.evaluate_markers(Some(markers), None, &[]) {
|
||||
if constraint.evaluate_markers(Some(markers), MarkerVariantsUniversal, &[])
|
||||
{
|
||||
match RequirementSatisfaction::check(distribution, &constraint.source) {
|
||||
RequirementSatisfaction::Mismatch
|
||||
| RequirementSatisfaction::OutOfDate
|
||||
|
|
@ -482,7 +483,7 @@ impl SitePackages {
|
|||
for dependency in r#overrides {
|
||||
if dependency.evaluate_markers(
|
||||
Some(markers),
|
||||
None,
|
||||
MarkerVariantsUniversal,
|
||||
&requirement.extras,
|
||||
) {
|
||||
if seen.insert((*dependency).clone()) {
|
||||
|
|
@ -491,8 +492,11 @@ impl SitePackages {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
if dependency.evaluate_markers(Some(markers), None, &requirement.extras)
|
||||
{
|
||||
if dependency.evaluate_markers(
|
||||
Some(markers),
|
||||
MarkerVariantsUniversal,
|
||||
&requirement.extras,
|
||||
) {
|
||||
if seen.insert(dependency.clone()) {
|
||||
stack.push(Cow::Owned(dependency));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,8 @@ pub use marker::{
|
|||
ContainsMarkerTree, ExtraMarkerTree, ExtraOperator, InMarkerTree, MarkerEnvironment,
|
||||
MarkerEnvironmentBuilder, MarkerExpression, MarkerOperator, MarkerTree, MarkerTreeContents,
|
||||
MarkerTreeKind, MarkerValue, MarkerValueExtra, MarkerValueList, MarkerValueString,
|
||||
MarkerValueVersion, MarkerWarningKind, StringMarkerTree, StringVersion, VersionMarkerTree,
|
||||
MarkerValueVersion, MarkerVariantsEnvironment, MarkerVariantsUniversal, MarkerWarningKind,
|
||||
StringMarkerTree, StringVersion, VersionMarkerTree,
|
||||
};
|
||||
pub use origin::RequirementOrigin;
|
||||
#[cfg(feature = "non-pep508-extensions")]
|
||||
|
|
@ -267,7 +268,7 @@ impl<T: Pep508Url> Requirement<T> {
|
|||
pub fn evaluate_markers(
|
||||
&self,
|
||||
env: &MarkerEnvironment,
|
||||
variants: Option<&[(String, String, String)]>,
|
||||
variants: impl MarkerVariantsEnvironment,
|
||||
extras: &[ExtraName],
|
||||
) -> bool {
|
||||
self.marker.evaluate(env, variants, extras)
|
||||
|
|
|
|||
|
|
@ -24,7 +24,8 @@ pub use tree::{
|
|||
ContainsMarkerTree, ExtraMarkerTree, ExtraOperator, InMarkerTree, MarkerExpression,
|
||||
MarkerOperator, MarkerTree, MarkerTreeContents, MarkerTreeDebugGraph, MarkerTreeKind,
|
||||
MarkerValue, MarkerValueExtra, MarkerValueList, MarkerValueString, MarkerValueVersion,
|
||||
MarkerWarningKind, StringMarkerTree, StringVersion, VersionMarkerTree,
|
||||
MarkerVariantsEnvironment, MarkerVariantsUniversal, MarkerWarningKind, StringMarkerTree,
|
||||
StringVersion, VersionMarkerTree,
|
||||
};
|
||||
|
||||
/// `serde` helpers for [`MarkerTree`].
|
||||
|
|
|
|||
|
|
@ -773,6 +773,73 @@ impl<'a> ExtrasEnvironment<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// The environment to use for evaluating `variant_namespaces`, `variant_features` and
|
||||
/// `variant_properties`
|
||||
pub trait MarkerVariantsEnvironment {
|
||||
/// Whether there is a property with the given namespace, for evaluating `variant_namespaces`.
|
||||
fn has_namespace(&self, namespace: &str) -> bool;
|
||||
|
||||
/// Whether there is a property with the given feature, for evaluating `variant_features`.
|
||||
fn has_feature(&self, namespace: &str, feature: &str) -> bool;
|
||||
|
||||
/// Whether there is the given property, for evaluating `variant_properties`.
|
||||
fn has_property(&self, namespace: &str, feature: &str, property: &str) -> bool;
|
||||
}
|
||||
|
||||
// Useful for tests
|
||||
impl<S: AsRef<str>> MarkerVariantsEnvironment for &[(S, S, S)] {
|
||||
fn has_namespace(&self, namespace: &str) -> bool {
|
||||
self.iter()
|
||||
.any(|(namespace_, _feature, _property)| namespace == namespace_.as_ref())
|
||||
}
|
||||
|
||||
fn has_feature(&self, namespace: &str, feature: &str) -> bool {
|
||||
self.iter().any(|(namespace_, feature_, _property)| {
|
||||
namespace == namespace_.as_ref() && feature == feature_.as_ref()
|
||||
})
|
||||
}
|
||||
|
||||
fn has_property(&self, namespace: &str, feature: &str, property: &str) -> bool {
|
||||
self.iter().any(|(namespace_, feature_, property_)| {
|
||||
namespace == namespace_.as_ref()
|
||||
&& feature == feature_.as_ref()
|
||||
&& property == property_.as_ref()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(konsti): Use `AsRef` instead?
|
||||
impl<T: MarkerVariantsEnvironment> MarkerVariantsEnvironment for &T {
|
||||
fn has_namespace(&self, namespace: &str) -> bool {
|
||||
T::has_namespace(self, namespace)
|
||||
}
|
||||
|
||||
fn has_feature(&self, namespace: &str, feature: &str) -> bool {
|
||||
T::has_feature(self, namespace, feature)
|
||||
}
|
||||
|
||||
fn has_property(&self, namespace: &str, feature: &str, property: &str) -> bool {
|
||||
T::has_property(self, namespace, feature, property)
|
||||
}
|
||||
}
|
||||
|
||||
/// A marker variants environment that always evaluates to `true`.
|
||||
pub struct MarkerVariantsUniversal;
|
||||
|
||||
impl MarkerVariantsEnvironment for MarkerVariantsUniversal {
|
||||
fn has_namespace(&self, _namespace: &str) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn has_feature(&self, _namespace: &str, _feature: &str) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn has_property(&self, _namespace: &str, _feature: &str, _property: &str) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents one or more nested marker expressions with and/or/parentheses.
|
||||
///
|
||||
/// Marker trees are canonical, meaning any two functionally equivalent markers
|
||||
|
|
@ -1012,7 +1079,7 @@ impl MarkerTree {
|
|||
pub fn evaluate(
|
||||
self,
|
||||
env: &MarkerEnvironment,
|
||||
variants: Option<&[(String, String, String)]>,
|
||||
variants: impl MarkerVariantsEnvironment,
|
||||
extras: &[ExtraName],
|
||||
) -> bool {
|
||||
self.evaluate_reporter_impl(
|
||||
|
|
@ -1029,7 +1096,7 @@ impl MarkerTree {
|
|||
pub fn evaluate_pep751(
|
||||
self,
|
||||
env: &MarkerEnvironment,
|
||||
variants: Option<&[(String, String, String)]>,
|
||||
variants: impl MarkerVariantsEnvironment,
|
||||
extras: &[ExtraName],
|
||||
groups: &[GroupName],
|
||||
) -> bool {
|
||||
|
|
@ -1051,7 +1118,7 @@ impl MarkerTree {
|
|||
pub fn evaluate_optional_environment(
|
||||
self,
|
||||
env: Option<&MarkerEnvironment>,
|
||||
variants: Option<&[(String, String, String)]>,
|
||||
variants: impl MarkerVariantsEnvironment,
|
||||
extras: &[ExtraName],
|
||||
) -> bool {
|
||||
match env {
|
||||
|
|
@ -1071,7 +1138,7 @@ impl MarkerTree {
|
|||
self,
|
||||
env: &MarkerEnvironment,
|
||||
extras: &[ExtraName],
|
||||
variants: Option<&[(String, String, String)]>,
|
||||
variants: impl MarkerVariantsEnvironment,
|
||||
reporter: &mut impl Reporter,
|
||||
) -> bool {
|
||||
self.evaluate_reporter_impl(
|
||||
|
|
@ -1086,7 +1153,7 @@ impl MarkerTree {
|
|||
self,
|
||||
env: &MarkerEnvironment,
|
||||
extras: ExtrasEnvironment,
|
||||
variants: Option<&[(String, String, String)]>,
|
||||
variants: impl MarkerVariantsEnvironment,
|
||||
reporter: &mut impl Reporter,
|
||||
) -> bool {
|
||||
match self.kind() {
|
||||
|
|
@ -1138,39 +1205,14 @@ impl MarkerTree {
|
|||
}
|
||||
MarkerTreeKind::List(marker) => {
|
||||
let edge = match marker.pair() {
|
||||
CanonicalMarkerListPair::VariantNamespaces(marker_namespace) => {
|
||||
let Some(variants) = variants else {
|
||||
// If we're not limiting to specific variants, we're solving universally.
|
||||
return true;
|
||||
};
|
||||
|
||||
variants
|
||||
.iter()
|
||||
.any(|(namespace, _feature, _property)| namespace == marker_namespace)
|
||||
CanonicalMarkerListPair::VariantNamespaces(namespace) => {
|
||||
variants.has_namespace(namespace)
|
||||
}
|
||||
CanonicalMarkerListPair::VariantFeatures(marker_namespace, marker_feature) => {
|
||||
let Some(variants) = variants else {
|
||||
return true;
|
||||
};
|
||||
|
||||
variants.iter().any(|(namespace, feature, _property)| {
|
||||
namespace == marker_namespace && feature == marker_feature
|
||||
})
|
||||
CanonicalMarkerListPair::VariantFeatures(namespace, feature) => {
|
||||
variants.has_feature(namespace, feature)
|
||||
}
|
||||
CanonicalMarkerListPair::VariantProperties(
|
||||
marker_namespace,
|
||||
marker_feature,
|
||||
marker_property,
|
||||
) => {
|
||||
let Some(variants) = variants else {
|
||||
return true;
|
||||
};
|
||||
|
||||
variants.iter().any(|(namespace, feature, property)| {
|
||||
namespace == marker_namespace
|
||||
&& feature == marker_feature
|
||||
&& property == marker_property
|
||||
})
|
||||
CanonicalMarkerListPair::VariantProperties(namespace, feature, property) => {
|
||||
variants.has_property(namespace, feature, property)
|
||||
}
|
||||
CanonicalMarkerListPair::Extras(extra) => extras.extras().contains(extra),
|
||||
CanonicalMarkerListPair::DependencyGroup(dependency_group) => {
|
||||
|
|
@ -2057,7 +2099,9 @@ mod test {
|
|||
use uv_pep440::Version;
|
||||
|
||||
use crate::marker::{MarkerEnvironment, MarkerEnvironmentBuilder};
|
||||
use crate::{MarkerExpression, MarkerOperator, MarkerTree, MarkerValueString};
|
||||
use crate::{
|
||||
MarkerExpression, MarkerOperator, MarkerTree, MarkerValueString, MarkerVariantsUniversal,
|
||||
};
|
||||
|
||||
fn parse_err(input: &str) -> String {
|
||||
MarkerTree::from_str(input).unwrap_err().to_string()
|
||||
|
|
@ -2214,12 +2258,12 @@ mod test {
|
|||
let marker3 = MarkerTree::from_str(
|
||||
"python_version == \"2.7\" and (sys_platform == \"win32\" or sys_platform == \"linux\")",
|
||||
).unwrap();
|
||||
assert!(marker1.evaluate(&env27, None, &[]));
|
||||
assert!(!marker1.evaluate(&env37, None, &[]));
|
||||
assert!(marker2.evaluate(&env27, None, &[]));
|
||||
assert!(marker2.evaluate(&env37, None, &[]));
|
||||
assert!(marker3.evaluate(&env27, None, &[]));
|
||||
assert!(!marker3.evaluate(&env37, None, &[]));
|
||||
assert!(marker1.evaluate(&env27, MarkerVariantsUniversal, &[]));
|
||||
assert!(!marker1.evaluate(&env37, MarkerVariantsUniversal, &[]));
|
||||
assert!(marker2.evaluate(&env27, MarkerVariantsUniversal, &[]));
|
||||
assert!(marker2.evaluate(&env37, MarkerVariantsUniversal, &[]));
|
||||
assert!(marker3.evaluate(&env27, MarkerVariantsUniversal, &[]));
|
||||
assert!(!marker3.evaluate(&env37, MarkerVariantsUniversal, &[]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -2241,48 +2285,48 @@ mod test {
|
|||
let env37 = env37();
|
||||
|
||||
let marker = MarkerTree::from_str("python_version in \"2.7 3.2 3.3\"").unwrap();
|
||||
assert!(marker.evaluate(&env27, None, &[]));
|
||||
assert!(!marker.evaluate(&env37, None, &[]));
|
||||
assert!(marker.evaluate(&env27, MarkerVariantsUniversal, &[]));
|
||||
assert!(!marker.evaluate(&env37, MarkerVariantsUniversal, &[]));
|
||||
|
||||
let marker = MarkerTree::from_str("python_version in \"2.7 3.7\"").unwrap();
|
||||
assert!(marker.evaluate(&env27, None, &[]));
|
||||
assert!(marker.evaluate(&env37, None, &[]));
|
||||
assert!(marker.evaluate(&env27, MarkerVariantsUniversal, &[]));
|
||||
assert!(marker.evaluate(&env37, MarkerVariantsUniversal, &[]));
|
||||
|
||||
let marker = MarkerTree::from_str("python_version in \"2.4 3.8 4.0\"").unwrap();
|
||||
assert!(!marker.evaluate(&env27, None, &[]));
|
||||
assert!(!marker.evaluate(&env37, None, &[]));
|
||||
assert!(!marker.evaluate(&env27, MarkerVariantsUniversal, &[]));
|
||||
assert!(!marker.evaluate(&env37, MarkerVariantsUniversal, &[]));
|
||||
|
||||
let marker = MarkerTree::from_str("python_version not in \"2.7 3.2 3.3\"").unwrap();
|
||||
assert!(!marker.evaluate(&env27, None, &[]));
|
||||
assert!(marker.evaluate(&env37, None, &[]));
|
||||
assert!(!marker.evaluate(&env27, MarkerVariantsUniversal, &[]));
|
||||
assert!(marker.evaluate(&env37, MarkerVariantsUniversal, &[]));
|
||||
|
||||
let marker = MarkerTree::from_str("python_version not in \"2.7 3.7\"").unwrap();
|
||||
assert!(!marker.evaluate(&env27, None, &[]));
|
||||
assert!(!marker.evaluate(&env37, None, &[]));
|
||||
assert!(!marker.evaluate(&env27, MarkerVariantsUniversal, &[]));
|
||||
assert!(!marker.evaluate(&env37, MarkerVariantsUniversal, &[]));
|
||||
|
||||
let marker = MarkerTree::from_str("python_version not in \"2.4 3.8 4.0\"").unwrap();
|
||||
assert!(marker.evaluate(&env27, None, &[]));
|
||||
assert!(marker.evaluate(&env37, None, &[]));
|
||||
assert!(marker.evaluate(&env27, MarkerVariantsUniversal, &[]));
|
||||
assert!(marker.evaluate(&env37, MarkerVariantsUniversal, &[]));
|
||||
|
||||
let marker = MarkerTree::from_str("python_full_version in \"2.7\"").unwrap();
|
||||
assert!(marker.evaluate(&env27, None, &[]));
|
||||
assert!(!marker.evaluate(&env37, None, &[]));
|
||||
assert!(marker.evaluate(&env27, MarkerVariantsUniversal, &[]));
|
||||
assert!(!marker.evaluate(&env37, MarkerVariantsUniversal, &[]));
|
||||
|
||||
let marker = MarkerTree::from_str("implementation_version in \"2.7 3.2 3.3\"").unwrap();
|
||||
assert!(marker.evaluate(&env27, None, &[]));
|
||||
assert!(!marker.evaluate(&env37, None, &[]));
|
||||
assert!(marker.evaluate(&env27, MarkerVariantsUniversal, &[]));
|
||||
assert!(!marker.evaluate(&env37, MarkerVariantsUniversal, &[]));
|
||||
|
||||
let marker = MarkerTree::from_str("implementation_version in \"2.7 3.7\"").unwrap();
|
||||
assert!(marker.evaluate(&env27, None, &[]));
|
||||
assert!(marker.evaluate(&env37, None, &[]));
|
||||
assert!(marker.evaluate(&env27, MarkerVariantsUniversal, &[]));
|
||||
assert!(marker.evaluate(&env37, MarkerVariantsUniversal, &[]));
|
||||
|
||||
let marker = MarkerTree::from_str("implementation_version not in \"2.7 3.7\"").unwrap();
|
||||
assert!(!marker.evaluate(&env27, None, &[]));
|
||||
assert!(!marker.evaluate(&env37, None, &[]));
|
||||
assert!(!marker.evaluate(&env27, MarkerVariantsUniversal, &[]));
|
||||
assert!(!marker.evaluate(&env37, MarkerVariantsUniversal, &[]));
|
||||
|
||||
let marker = MarkerTree::from_str("implementation_version not in \"2.4 3.8 4.0\"").unwrap();
|
||||
assert!(marker.evaluate(&env27, None, &[]));
|
||||
assert!(marker.evaluate(&env37, None, &[]));
|
||||
assert!(marker.evaluate(&env27, MarkerVariantsUniversal, &[]));
|
||||
assert!(marker.evaluate(&env37, MarkerVariantsUniversal, &[]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -2291,7 +2335,7 @@ mod test {
|
|||
fn warnings1() {
|
||||
let env37 = env37();
|
||||
let compare_keys = MarkerTree::from_str("platform_version == sys_platform").unwrap();
|
||||
compare_keys.evaluate(&env37, None, &[]);
|
||||
compare_keys.evaluate(&env37, MarkerVariantsUniversal, &[]);
|
||||
logs_contain(
|
||||
"Comparing two markers with each other doesn't make any sense, will evaluate to false",
|
||||
);
|
||||
|
|
@ -2303,7 +2347,7 @@ mod test {
|
|||
fn warnings2() {
|
||||
let env37 = env37();
|
||||
let non_pep440 = MarkerTree::from_str("python_version >= '3.9.'").unwrap();
|
||||
non_pep440.evaluate(&env37, None, &[]);
|
||||
non_pep440.evaluate(&env37, MarkerVariantsUniversal, &[]);
|
||||
logs_contain(
|
||||
"Expected PEP 440 version to compare with python_version, found `3.9.`, \
|
||||
will evaluate to false: after parsing `3.9`, found `.`, which is \
|
||||
|
|
@ -2317,7 +2361,7 @@ mod test {
|
|||
fn warnings3() {
|
||||
let env37 = env37();
|
||||
let string_string = MarkerTree::from_str("'b' >= 'a'").unwrap();
|
||||
string_string.evaluate(&env37, None, &[]);
|
||||
string_string.evaluate(&env37, MarkerVariantsUniversal, &[]);
|
||||
logs_contain(
|
||||
"Comparing two quoted strings with each other doesn't make sense: 'b' >= 'a', will evaluate to false",
|
||||
);
|
||||
|
|
@ -2329,7 +2373,7 @@ mod test {
|
|||
fn warnings4() {
|
||||
let env37 = env37();
|
||||
let string_string = MarkerTree::from_str(r"os.name == 'posix' and platform.machine == 'x86_64' and platform.python_implementation == 'CPython' and 'Ubuntu' in platform.version and sys.platform == 'linux'").unwrap();
|
||||
string_string.evaluate(&env37, None, &[]);
|
||||
string_string.evaluate(&env37, MarkerVariantsUniversal, &[]);
|
||||
logs_assert(|lines: &[&str]| {
|
||||
let lines: Vec<_> = lines
|
||||
.iter()
|
||||
|
|
@ -2361,18 +2405,18 @@ mod test {
|
|||
let env37 = env37();
|
||||
let result = MarkerTree::from_str("python_version > '3.6'")
|
||||
.unwrap()
|
||||
.evaluate(&env37, None, &[]);
|
||||
.evaluate(&env37, MarkerVariantsUniversal, &[]);
|
||||
assert!(result);
|
||||
|
||||
let result = MarkerTree::from_str("'3.6' > python_version")
|
||||
.unwrap()
|
||||
.evaluate(&env37, None, &[]);
|
||||
.evaluate(&env37, MarkerVariantsUniversal, &[]);
|
||||
assert!(!result);
|
||||
|
||||
// Meaningless expressions are ignored, so this is always true.
|
||||
let result = MarkerTree::from_str("'3.*' == python_version")
|
||||
.unwrap()
|
||||
.evaluate(&env37, None, &[]);
|
||||
.evaluate(&env37, MarkerVariantsUniversal, &[]);
|
||||
assert!(result);
|
||||
}
|
||||
|
||||
|
|
@ -2381,12 +2425,12 @@ mod test {
|
|||
let env37 = env37();
|
||||
let result = MarkerTree::from_str("'nux' in sys_platform")
|
||||
.unwrap()
|
||||
.evaluate(&env37, None, &[]);
|
||||
.evaluate(&env37, MarkerVariantsUniversal, &[]);
|
||||
assert!(result);
|
||||
|
||||
let result = MarkerTree::from_str("sys_platform in 'nux'")
|
||||
.unwrap()
|
||||
.evaluate(&env37, None, &[]);
|
||||
.evaluate(&env37, MarkerVariantsUniversal, &[]);
|
||||
assert!(!result);
|
||||
}
|
||||
|
||||
|
|
@ -2395,7 +2439,7 @@ mod test {
|
|||
let env37 = env37();
|
||||
let result = MarkerTree::from_str("python_version == '3.7.*'")
|
||||
.unwrap()
|
||||
.evaluate(&env37, None, &[]);
|
||||
.evaluate(&env37, MarkerVariantsUniversal, &[]);
|
||||
assert!(result);
|
||||
}
|
||||
|
||||
|
|
@ -2404,7 +2448,7 @@ mod test {
|
|||
let env37 = env37();
|
||||
let result = MarkerTree::from_str("python_version ~= '3.7'")
|
||||
.unwrap()
|
||||
.evaluate(&env37, None, &[]);
|
||||
.evaluate(&env37, MarkerVariantsUniversal, &[]);
|
||||
assert!(result);
|
||||
}
|
||||
|
||||
|
|
@ -3754,68 +3798,69 @@ mod test {
|
|||
#[test]
|
||||
fn marker_evaluation_variants() {
|
||||
let env37 = env37();
|
||||
let gpu_namespaces = [("gpu".to_string(), "cuda".to_string(), "12.4".to_string())];
|
||||
let cpu_namespaces = [("cpu".to_string(), String::new(), String::new())];
|
||||
let gpu_namespaces = [("gpu", "cuda", "12.4")].as_slice();
|
||||
let cpu_namespaces = [("cpu", "", "")].as_slice();
|
||||
|
||||
// namespace variant markers
|
||||
let marker1 = m("'gpu' in variant_namespaces");
|
||||
let marker2 = m("'gpu' not in variant_namespaces");
|
||||
|
||||
// If no variants are provided, we solve universally.
|
||||
assert!(marker1.evaluate(&env37, None, &[]));
|
||||
assert!(marker2.evaluate(&env37, None, &[]));
|
||||
assert!(marker1.evaluate(&env37, MarkerVariantsUniversal, &[]));
|
||||
assert!(marker2.evaluate(&env37, MarkerVariantsUniversal, &[]));
|
||||
|
||||
assert!(marker1.evaluate(&env37, Some(&gpu_namespaces), &[]));
|
||||
assert!(!marker1.evaluate(&env37, Some(&cpu_namespaces), &[]));
|
||||
assert!(!marker2.evaluate(&env37, Some(&gpu_namespaces), &[]));
|
||||
assert!(marker2.evaluate(&env37, Some(&cpu_namespaces), &[]));
|
||||
assert!(marker1.evaluate(&env37, gpu_namespaces, &[]));
|
||||
assert!(!marker1.evaluate(&env37, cpu_namespaces, &[]));
|
||||
assert!(!marker2.evaluate(&env37, gpu_namespaces, &[]));
|
||||
assert!(marker2.evaluate(&env37, cpu_namespaces, &[]));
|
||||
|
||||
// property variant markers
|
||||
let marker3 = m("'gpu :: cuda' in variant_features");
|
||||
let marker4 = m("'gpu :: rocm' in variant_features");
|
||||
|
||||
assert!(marker3.evaluate(&env37, None, &[]));
|
||||
assert!(marker4.evaluate(&env37, None, &[]));
|
||||
assert!(marker3.evaluate(&env37, MarkerVariantsUniversal, &[]));
|
||||
assert!(marker4.evaluate(&env37, MarkerVariantsUniversal, &[]));
|
||||
|
||||
assert!(marker3.evaluate(&env37, Some(&gpu_namespaces), &[]));
|
||||
assert!(!marker3.evaluate(&env37, Some(&cpu_namespaces), &[]));
|
||||
assert!(!marker4.evaluate(&env37, Some(&gpu_namespaces), &[]));
|
||||
assert!(!marker4.evaluate(&env37, Some(&cpu_namespaces), &[]));
|
||||
assert!(marker3.evaluate(&env37, gpu_namespaces, &[]));
|
||||
assert!(!marker3.evaluate(&env37, cpu_namespaces, &[]));
|
||||
assert!(!marker4.evaluate(&env37, gpu_namespaces, &[]));
|
||||
assert!(!marker4.evaluate(&env37, cpu_namespaces, &[]));
|
||||
|
||||
// feature variant markers
|
||||
let marker5 = m("'gpu :: cuda :: 12.4' in variant_properties");
|
||||
let marker6 = m("'gpu :: cuda :: 12.8' in variant_properties");
|
||||
|
||||
assert!(marker5.evaluate(&env37, None, &[]));
|
||||
assert!(marker6.evaluate(&env37, None, &[]));
|
||||
assert!(marker5.evaluate(&env37, MarkerVariantsUniversal, &[]));
|
||||
assert!(marker6.evaluate(&env37, MarkerVariantsUniversal, &[]));
|
||||
|
||||
assert!(marker5.evaluate(&env37, Some(&gpu_namespaces), &[]));
|
||||
assert!(!marker5.evaluate(&env37, Some(&cpu_namespaces), &[]));
|
||||
assert!(!marker6.evaluate(&env37, Some(&gpu_namespaces), &[]));
|
||||
assert!(!marker6.evaluate(&env37, Some(&cpu_namespaces), &[]));
|
||||
assert!(marker5.evaluate(&env37, gpu_namespaces, &[]));
|
||||
assert!(!marker5.evaluate(&env37, cpu_namespaces, &[]));
|
||||
assert!(!marker6.evaluate(&env37, gpu_namespaces, &[]));
|
||||
assert!(!marker6.evaluate(&env37, cpu_namespaces, &[]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn marker_evaluation_variants_combined() {
|
||||
let env37 = env37();
|
||||
let namespaces = [
|
||||
("gpu".to_string(), "cuda".to_string(), "12.4".to_string()),
|
||||
("gpu".to_string(), "cuda".to_string(), "12.6".to_string()),
|
||||
("cpu".to_string(), "x86_64".to_string(), "v1".to_string()),
|
||||
("cpu".to_string(), "x86_64".to_string(), "v2".to_string()),
|
||||
("cpu".to_string(), "x86_64".to_string(), "v3".to_string()),
|
||||
];
|
||||
("gpu", "cuda", "12.4"),
|
||||
("gpu", "cuda", "12.6"),
|
||||
("cpu", "x86_64", "v1"),
|
||||
("cpu", "x86_64", "v2"),
|
||||
("cpu", "x86_64", "v3"),
|
||||
]
|
||||
.as_slice();
|
||||
|
||||
let marker1 = m("'gpu' in variant_namespaces \
|
||||
and 'cpu:: x86_64 :: v3' in variant_properties \
|
||||
and python_version >= '3.7' \
|
||||
and 'gpu :: rocm' not in variant_features");
|
||||
assert!(marker1.evaluate(&env37, None, &[]));
|
||||
assert!(marker1.evaluate(&env37, Some(&namespaces), &[]));
|
||||
assert!(marker1.evaluate(&env37, MarkerVariantsUniversal, &[]));
|
||||
assert!(marker1.evaluate(&env37, namespaces, &[]));
|
||||
|
||||
let marker2 = m("python_version >= '3.7' and 'gpu' not in variant_namespaces");
|
||||
assert!(marker2.evaluate(&env37, None, &[]));
|
||||
assert!(!marker2.evaluate(&env37, Some(&namespaces), &[]));
|
||||
assert!(marker2.evaluate(&env37, MarkerVariantsUniversal, &[]));
|
||||
assert!(!marker2.evaluate(&env37, namespaces, &[]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -3863,33 +3908,30 @@ mod test {
|
|||
#[test]
|
||||
fn variant_invalid() {
|
||||
let env37 = env37();
|
||||
let namespaces = [("gpu".to_string(), "cuda".to_string(), "cuda126".to_string())];
|
||||
let namespaces = [("gpu", "cuda", "cuda126")].as_slice();
|
||||
|
||||
let marker = m(r"'gpu :: cuda :: cuda126 :: gtx1080' in variant_properties");
|
||||
assert!(!marker.evaluate(&env37, Some(&namespaces), &[]));
|
||||
assert!(!marker.evaluate(&env37, namespaces, &[]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn torch_variant_marker() {
|
||||
let env37 = env37();
|
||||
let cu126 = [("nvidia".to_string(), "ctk".to_string(), "12.6".to_string())];
|
||||
let cu126 = [("nvidia", "ctk", "12.6")].as_slice();
|
||||
let cu126_2 = [
|
||||
("nvidia".to_string(), "ctk".to_string(), "12.6".to_string()),
|
||||
(
|
||||
"nvidia".to_string(),
|
||||
"cuda_version".to_string(),
|
||||
">=12.6,<13".to_string(),
|
||||
),
|
||||
];
|
||||
let cu128 = [("nvidia".to_string(), "ctk".to_string(), "12.8".to_string())];
|
||||
("nvidia", "ctk", "12.6"),
|
||||
("nvidia", "cuda_version", ">=12.6,<13"),
|
||||
]
|
||||
.as_slice();
|
||||
let cu128 = [("nvidia", "ctk", "12.8")].as_slice();
|
||||
|
||||
let marker = m(
|
||||
" platform_machine == 'x86_64' and sys_platform == 'linux' and 'nvidia :: ctk :: 12.6' in variant_properties",
|
||||
);
|
||||
|
||||
assert!(marker.evaluate(&env37, None, &[]));
|
||||
assert!(marker.evaluate(&env37, Some(&cu126), &[]));
|
||||
assert!(marker.evaluate(&env37, Some(&cu126_2), &[]));
|
||||
assert!(!marker.evaluate(&env37, Some(&cu128), &[]));
|
||||
assert!(marker.evaluate(&env37, MarkerVariantsUniversal, &[]));
|
||||
assert!(marker.evaluate(&env37, cu126, &[]));
|
||||
assert!(marker.evaluate(&env37, cu126_2, &[]));
|
||||
assert!(!marker.evaluate(&env37, cu128, &[]));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,9 +8,10 @@ use uv_normalize::ExtraName;
|
|||
|
||||
use crate::marker::parse;
|
||||
use crate::{
|
||||
Cursor, MarkerEnvironment, MarkerTree, Pep508Error, Pep508ErrorSource, Pep508Url, Reporter,
|
||||
RequirementOrigin, Scheme, TracingReporter, VerbatimUrl, VerbatimUrlError, expand_env_vars,
|
||||
parse_extras_cursor, split_extras, split_scheme, strip_host,
|
||||
Cursor, MarkerEnvironment, MarkerTree, MarkerVariantsEnvironment, Pep508Error,
|
||||
Pep508ErrorSource, Pep508Url, Reporter, RequirementOrigin, Scheme, TracingReporter,
|
||||
VerbatimUrl, VerbatimUrlError, expand_env_vars, parse_extras_cursor, split_extras,
|
||||
split_scheme, strip_host,
|
||||
};
|
||||
|
||||
/// An extension over [`Pep508Url`] that also supports parsing unnamed requirements, namely paths.
|
||||
|
|
@ -85,7 +86,7 @@ impl<Url: UnnamedRequirementUrl> UnnamedRequirement<Url> {
|
|||
pub fn evaluate_markers(
|
||||
&self,
|
||||
env: &MarkerEnvironment,
|
||||
variants: Option<&[(String, String, String)]>,
|
||||
variants: impl MarkerVariantsEnvironment,
|
||||
extras: &[ExtraName],
|
||||
) -> bool {
|
||||
self.evaluate_optional_environment(Some(env), variants, extras)
|
||||
|
|
@ -95,7 +96,7 @@ impl<Url: UnnamedRequirementUrl> UnnamedRequirement<Url> {
|
|||
pub fn evaluate_optional_environment(
|
||||
&self,
|
||||
env: Option<&MarkerEnvironment>,
|
||||
variants: Option<&[(String, String, String)]>,
|
||||
variants: impl MarkerVariantsEnvironment,
|
||||
extras: &[ExtraName],
|
||||
) -> bool {
|
||||
self.marker
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use tracing::trace;
|
|||
use uv_configuration::{Constraints, Overrides};
|
||||
use uv_distribution::{DistributionDatabase, Reporter};
|
||||
use uv_distribution_types::{Dist, DistributionMetadata, Requirement, RequirementSource};
|
||||
use uv_pep508::MarkerVariantsUniversal;
|
||||
use uv_resolver::{InMemoryIndex, MetadataResponse, ResolverEnvironment};
|
||||
use uv_types::{BuildContext, HashStrategy, RequestedRequirements};
|
||||
|
||||
|
|
@ -91,7 +92,9 @@ impl<'a, Context: BuildContext> LookaheadResolver<'a, Context> {
|
|||
let mut queue: VecDeque<_> = self
|
||||
.constraints
|
||||
.apply(self.overrides.apply(self.requirements))
|
||||
.filter(|requirement| requirement.evaluate_markers(env.marker_environment(), None, &[]))
|
||||
.filter(|requirement| {
|
||||
requirement.evaluate_markers(env.marker_environment(), MarkerVariantsUniversal, &[])
|
||||
})
|
||||
.map(|requirement| (*requirement).clone())
|
||||
.collect();
|
||||
|
||||
|
|
@ -112,7 +115,7 @@ impl<'a, Context: BuildContext> LookaheadResolver<'a, Context> {
|
|||
{
|
||||
if requirement.evaluate_markers(
|
||||
env.marker_environment(),
|
||||
None,
|
||||
MarkerVariantsUniversal,
|
||||
lookahead.extras(),
|
||||
) {
|
||||
queue.push_back((*requirement).clone());
|
||||
|
|
|
|||
|
|
@ -16,7 +16,9 @@ use uv_distribution_types::{
|
|||
};
|
||||
use uv_normalize::{ExtraName, InvalidNameError, PackageName};
|
||||
use uv_pep440::{LocalVersionSlice, LowerBound, Version, VersionSpecifier};
|
||||
use uv_pep508::{MarkerEnvironment, MarkerExpression, MarkerTree, MarkerValueVersion};
|
||||
use uv_pep508::{
|
||||
MarkerEnvironment, MarkerExpression, MarkerTree, MarkerValueVersion, MarkerVariantsUniversal,
|
||||
};
|
||||
use uv_platform_tags::Tags;
|
||||
use uv_pypi_types::ParsedUrl;
|
||||
use uv_redacted::DisplaySafeUrl;
|
||||
|
|
@ -412,7 +414,7 @@ impl NoSolutionError {
|
|||
":".bold(),
|
||||
current_python_version,
|
||||
)?;
|
||||
} else if !markers.evaluate(&self.current_environment, None, &[]) {
|
||||
} else if !markers.evaluate(&self.current_environment, MarkerVariantsUniversal, &[]) {
|
||||
write!(
|
||||
f,
|
||||
"\n\n{}{} The resolution failed for an environment that is not the current one, \
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use petgraph::visit::EdgeRef;
|
|||
use petgraph::{Direction, Graph};
|
||||
use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet};
|
||||
|
||||
use uv_pep508::MarkerTree;
|
||||
use uv_pep508::{MarkerTree, MarkerVariantsUniversal};
|
||||
use uv_pypi_types::{ConflictItem, Conflicts};
|
||||
|
||||
use crate::resolution::ResolutionGraphNode;
|
||||
|
|
@ -272,7 +272,7 @@ pub(crate) fn simplify_conflict_markers(
|
|||
.collect::<Vec<_>>();
|
||||
graph[edge_index]
|
||||
.conflict()
|
||||
.evaluate(None, &extras, &groups)
|
||||
.evaluate(&extras, &groups, MarkerVariantsUniversal)
|
||||
});
|
||||
if !all_paths_satisfied {
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ use uv_git::{RepositoryReference, ResolvedRepositoryReference};
|
|||
use uv_git_types::{GitOid, GitReference, GitUrl, GitUrlParseError};
|
||||
use uv_normalize::{ExtraName, GroupName, PackageName};
|
||||
use uv_pep440::Version;
|
||||
use uv_pep508::{MarkerEnvironment, MarkerTree, VerbatimUrl};
|
||||
use uv_pep508::{MarkerEnvironment, MarkerTree, MarkerVariantsUniversal, VerbatimUrl};
|
||||
use uv_platform_tags::{TagCompatibility, TagPriority, Tags};
|
||||
use uv_pypi_types::{HashDigests, Hashes, ParsedGitUrl, VcsKind};
|
||||
use uv_redacted::DisplaySafeUrl;
|
||||
|
|
@ -982,7 +982,7 @@ impl<'lock> PylockToml {
|
|||
// Omit packages that aren't relevant to the current environment.
|
||||
if !package
|
||||
.marker
|
||||
.evaluate_pep751(markers, None, extras, groups)
|
||||
.evaluate_pep751(markers, MarkerVariantsUniversal, extras, groups)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,11 +14,12 @@ use uv_configuration::{BuildOptions, DependencyGroupsWithDefaults, InstallOption
|
|||
use uv_distribution::{DistributionDatabase, VariantProviderCache};
|
||||
use uv_distribution_types::{Edge, Identifier, Node, Resolution, ResolvedDist};
|
||||
use uv_normalize::{ExtraName, GroupName, PackageName};
|
||||
use uv_pep508::MarkerVariantsUniversal;
|
||||
use uv_platform_tags::Tags;
|
||||
use uv_pypi_types::ResolverMarkerEnvironment;
|
||||
use uv_types::BuildContext;
|
||||
use uv_variants::score_variant;
|
||||
use uv_variants::variants_json::VariantPropertyType;
|
||||
use uv_variants::variants_json::Variant;
|
||||
|
||||
use crate::lock::{LockErrorKind, Package, TagPolicy};
|
||||
use crate::{Lock, LockError};
|
||||
|
|
@ -151,7 +152,7 @@ pub trait Installable<'lock> {
|
|||
// TODO(konsti): Evaluate variant declarations on workspace/path dependencies.
|
||||
if !dep.complexified_marker.evaluate(
|
||||
marker_env,
|
||||
None,
|
||||
MarkerVariantsUniversal,
|
||||
activated_extras.iter().copied(),
|
||||
activated_groups.iter().copied(),
|
||||
) {
|
||||
|
|
@ -215,14 +216,17 @@ pub trait Installable<'lock> {
|
|||
// Add any requirements that are exclusive to the workspace root (e.g., dependencies in
|
||||
// PEP 723 scripts).
|
||||
for dependency in self.lock().requirements() {
|
||||
if !dependency.marker.evaluate(marker_env, None, &[]) {
|
||||
if !dependency
|
||||
.marker
|
||||
.evaluate(marker_env, MarkerVariantsUniversal, &[])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
let root_name = &dependency.name;
|
||||
let dist = self
|
||||
.lock()
|
||||
.find_by_markers(root_name, marker_env, None)
|
||||
.find_by_markers(root_name, marker_env)
|
||||
.map_err(|_| LockErrorKind::MultipleRootPackages {
|
||||
name: root_name.clone(),
|
||||
})?
|
||||
|
|
@ -267,7 +271,10 @@ pub trait Installable<'lock> {
|
|||
})
|
||||
.flatten()
|
||||
{
|
||||
if !dependency.marker.evaluate(marker_env, None, &[]) {
|
||||
if !dependency
|
||||
.marker
|
||||
.evaluate(marker_env, MarkerVariantsUniversal, &[])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -275,7 +282,7 @@ pub trait Installable<'lock> {
|
|||
// TODO(konsti): Evaluate variant declarations on workspace/path dependencies.
|
||||
let dist = self
|
||||
.lock()
|
||||
.find_by_markers(root_name, marker_env, None)
|
||||
.find_by_markers(root_name, marker_env)
|
||||
.map_err(|_| LockErrorKind::MultipleRootPackages {
|
||||
name: root_name.clone(),
|
||||
})?
|
||||
|
|
@ -378,7 +385,7 @@ pub trait Installable<'lock> {
|
|||
// TODO(konsti): Evaluate variants
|
||||
if !dep.complexified_marker.evaluate(
|
||||
marker_env,
|
||||
None,
|
||||
MarkerVariantsUniversal,
|
||||
activated_extras
|
||||
.iter()
|
||||
.chain(additional_activated_extras.iter())
|
||||
|
|
@ -475,7 +482,7 @@ pub trait Installable<'lock> {
|
|||
for dep in deps {
|
||||
if !dep.complexified_marker.evaluate(
|
||||
marker_env,
|
||||
variant_properties.as_deref(),
|
||||
&variant_properties,
|
||||
activated_extras.iter().copied(),
|
||||
activated_groups.iter().copied(),
|
||||
) {
|
||||
|
|
@ -600,9 +607,10 @@ async fn determine_properties<Context: BuildContext>(
|
|||
workspace_root: &Path,
|
||||
distribution_database: &DistributionDatabase<'_, Context>,
|
||||
variants_cache: &VariantProviderCache,
|
||||
) -> Result<Option<Vec<(String, String, String)>>, LockError> {
|
||||
) -> Result<Variant, LockError> {
|
||||
let Some(variants_json) = package.to_registry_variants_json(workspace_root)? else {
|
||||
return Ok(None);
|
||||
// When selecting a non-variant wheel, all variant markers evaluate to false.
|
||||
return Ok(Variant::default());
|
||||
};
|
||||
let resolved_variants = if let Some(resolved_variants) =
|
||||
variants_cache.get_resolved_variants(&variants_json.resource_id())
|
||||
|
|
@ -654,39 +662,15 @@ async fn determine_properties<Context: BuildContext>(
|
|||
}
|
||||
|
||||
if let Some((best_variant, _)) = highest_priority_variant_wheel {
|
||||
// TODO(konsti): Use the proper type everywhere, we shouldn't need to do
|
||||
// this conversion at all.
|
||||
let mut known_properties = BTreeSet::new();
|
||||
for (namespace, features) in resolved_variants
|
||||
// TODO(konsti): We shouldn't need to clone
|
||||
let known_properties = resolved_variants
|
||||
.variants_json
|
||||
.variants
|
||||
.get(best_variant)
|
||||
.expect("TODO(konsti): error handling")
|
||||
{
|
||||
for (feature, values) in features {
|
||||
for value in values {
|
||||
known_properties.insert(VariantPropertyType {
|
||||
namespace: namespace.clone(),
|
||||
feature: feature.clone(),
|
||||
value: value.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
let known_properties: Vec<(String, String, String)> = known_properties
|
||||
.into_iter()
|
||||
.map(|known_property| {
|
||||
(
|
||||
known_property.namespace,
|
||||
known_property.feature,
|
||||
known_property.value,
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
Ok(Some(known_properties))
|
||||
.expect("TODO(konsti): error handling");
|
||||
Ok(known_properties.clone())
|
||||
} else {
|
||||
// When selecting the non-variant wheel, all variant markers evaluate to
|
||||
// false.
|
||||
Ok(Some(Vec::new()))
|
||||
// When selecting the non-variant wheel, all variant markers evaluate to false.
|
||||
Ok(Variant::default())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1111,7 +1111,6 @@ impl Lock {
|
|||
&self,
|
||||
name: &PackageName,
|
||||
marker_env: &MarkerEnvironment,
|
||||
variants: Option<&[(String, String, String)]>,
|
||||
) -> Result<Option<&Package>, String> {
|
||||
let mut found_dist = None;
|
||||
for dist in &self.packages {
|
||||
|
|
@ -1120,7 +1119,7 @@ impl Lock {
|
|||
|| dist
|
||||
.fork_markers
|
||||
.iter()
|
||||
.any(|marker| marker.evaluate_no_extras(marker_env, variants))
|
||||
.any(|marker| marker.evaluate_no_extras(marker_env))
|
||||
{
|
||||
if found_dist.is_some() {
|
||||
return Err(format!("found multiple packages matching `{name}`"));
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet};
|
|||
use uv_configuration::DependencyGroupsWithDefaults;
|
||||
use uv_normalize::{ExtraName, GroupName, PackageName};
|
||||
use uv_pep440::Version;
|
||||
use uv_pep508::MarkerTree;
|
||||
use uv_pep508::{MarkerTree, MarkerVariantsUniversal};
|
||||
use uv_pypi_types::ResolverMarkerEnvironment;
|
||||
|
||||
use crate::lock::PackageId;
|
||||
|
|
@ -126,9 +126,9 @@ impl<'env> TreeDisplay<'env> {
|
|||
continue;
|
||||
}
|
||||
|
||||
if markers.is_some_and(|markers| {
|
||||
!dep.complexified_marker.evaluate_no_extras(markers, None)
|
||||
}) {
|
||||
if markers
|
||||
.is_some_and(|markers| !dep.complexified_marker.evaluate_no_extras(markers))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -190,7 +190,9 @@ impl<'env> TreeDisplay<'env> {
|
|||
if marker.is_false() {
|
||||
continue;
|
||||
}
|
||||
if markers.is_some_and(|markers| !marker.evaluate(markers, None, &[])) {
|
||||
if markers.is_some_and(|markers| {
|
||||
!marker.evaluate(markers, MarkerVariantsUniversal, &[])
|
||||
}) {
|
||||
continue;
|
||||
}
|
||||
// Add the package to the graph.
|
||||
|
|
@ -227,7 +229,9 @@ impl<'env> TreeDisplay<'env> {
|
|||
if marker.is_false() {
|
||||
continue;
|
||||
}
|
||||
if markers.is_some_and(|markers| !marker.evaluate(markers, None, &[])) {
|
||||
if markers.is_some_and(|markers| {
|
||||
!marker.evaluate(markers, MarkerVariantsUniversal, &[])
|
||||
}) {
|
||||
continue;
|
||||
}
|
||||
// Add the package to the graph.
|
||||
|
|
@ -269,9 +273,9 @@ impl<'env> TreeDisplay<'env> {
|
|||
continue;
|
||||
}
|
||||
|
||||
if markers.is_some_and(|markers| {
|
||||
!dep.complexified_marker.evaluate_no_extras(markers, None)
|
||||
}) {
|
||||
if markers
|
||||
.is_some_and(|markers| !dep.complexified_marker.evaluate_no_extras(markers))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use either::Either;
|
|||
use uv_configuration::{Constraints, Overrides};
|
||||
use uv_distribution_types::Requirement;
|
||||
use uv_normalize::PackageName;
|
||||
use uv_pep508::MarkerVariantsUniversal;
|
||||
use uv_types::RequestedRequirements;
|
||||
|
||||
use crate::preferences::Preferences;
|
||||
|
|
@ -116,43 +117,55 @@ impl Manifest {
|
|||
) -> impl Iterator<Item = Cow<'a, Requirement>> + 'a {
|
||||
match mode {
|
||||
// Include all direct and transitive requirements, with constraints and overrides applied.
|
||||
DependencyMode::Transitive => Either::Left(
|
||||
self.lookaheads
|
||||
.iter()
|
||||
.flat_map(move |lookahead| {
|
||||
self.overrides
|
||||
.apply(lookahead.requirements())
|
||||
.filter(move |requirement| {
|
||||
DependencyMode::Transitive => {
|
||||
Either::Left(
|
||||
self.lookaheads
|
||||
.iter()
|
||||
.flat_map(move |lookahead| {
|
||||
self.overrides.apply(lookahead.requirements()).filter(
|
||||
move |requirement| {
|
||||
requirement.evaluate_markers(
|
||||
env.marker_environment(),
|
||||
MarkerVariantsUniversal,
|
||||
lookahead.extras(),
|
||||
)
|
||||
},
|
||||
)
|
||||
})
|
||||
.chain(self.overrides.apply(&self.requirements).filter(
|
||||
move |requirement| {
|
||||
requirement.evaluate_markers(
|
||||
env.marker_environment(),
|
||||
None,
|
||||
lookahead.extras(),
|
||||
MarkerVariantsUniversal,
|
||||
&[],
|
||||
)
|
||||
})
|
||||
})
|
||||
.chain(
|
||||
self.overrides
|
||||
.apply(&self.requirements)
|
||||
.filter(move |requirement| {
|
||||
requirement.evaluate_markers(env.marker_environment(), None, &[])
|
||||
}),
|
||||
)
|
||||
.chain(
|
||||
self.constraints
|
||||
.requirements()
|
||||
.filter(move |requirement| {
|
||||
requirement.evaluate_markers(env.marker_environment(), None, &[])
|
||||
})
|
||||
.map(Cow::Borrowed),
|
||||
),
|
||||
),
|
||||
},
|
||||
))
|
||||
.chain(
|
||||
self.constraints
|
||||
.requirements()
|
||||
.filter(move |requirement| {
|
||||
requirement.evaluate_markers(
|
||||
env.marker_environment(),
|
||||
MarkerVariantsUniversal,
|
||||
&[],
|
||||
)
|
||||
})
|
||||
.map(Cow::Borrowed),
|
||||
),
|
||||
)
|
||||
}
|
||||
// Include direct requirements, with constraints and overrides applied.
|
||||
DependencyMode::Direct => Either::Right(
|
||||
self.overrides
|
||||
.apply(&self.requirements)
|
||||
.chain(self.constraints.requirements().map(Cow::Borrowed))
|
||||
.filter(move |requirement| {
|
||||
requirement.evaluate_markers(env.marker_environment(), None, &[])
|
||||
requirement.evaluate_markers(
|
||||
env.marker_environment(),
|
||||
MarkerVariantsUniversal,
|
||||
&[],
|
||||
)
|
||||
}),
|
||||
),
|
||||
}
|
||||
|
|
@ -170,7 +183,11 @@ impl Manifest {
|
|||
self.overrides
|
||||
.requirements()
|
||||
.filter(move |requirement| {
|
||||
requirement.evaluate_markers(env.marker_environment(), None, &[])
|
||||
requirement.evaluate_markers(
|
||||
env.marker_environment(),
|
||||
MarkerVariantsUniversal,
|
||||
&[],
|
||||
)
|
||||
})
|
||||
.map(Cow::Borrowed),
|
||||
),
|
||||
|
|
@ -179,7 +196,11 @@ impl Manifest {
|
|||
self.overrides
|
||||
.requirements()
|
||||
.filter(move |requirement| {
|
||||
requirement.evaluate_markers(env.marker_environment(), None, &[])
|
||||
requirement.evaluate_markers(
|
||||
env.marker_environment(),
|
||||
MarkerVariantsUniversal,
|
||||
&[],
|
||||
)
|
||||
})
|
||||
.map(Cow::Borrowed),
|
||||
),
|
||||
|
|
@ -214,7 +235,7 @@ impl Manifest {
|
|||
move |requirement| {
|
||||
requirement.evaluate_markers(
|
||||
env.marker_environment(),
|
||||
None,
|
||||
MarkerVariantsUniversal,
|
||||
lookahead.extras(),
|
||||
)
|
||||
},
|
||||
|
|
@ -222,7 +243,11 @@ impl Manifest {
|
|||
})
|
||||
.chain(self.overrides.apply(&self.requirements).filter(
|
||||
move |requirement| {
|
||||
requirement.evaluate_markers(env.marker_environment(), None, &[])
|
||||
requirement.evaluate_markers(
|
||||
env.marker_environment(),
|
||||
MarkerVariantsUniversal,
|
||||
&[],
|
||||
)
|
||||
},
|
||||
)),
|
||||
)
|
||||
|
|
@ -232,7 +257,11 @@ impl Manifest {
|
|||
DependencyMode::Direct => {
|
||||
Either::Right(self.overrides.apply(self.requirements.iter()).filter(
|
||||
move |requirement| {
|
||||
requirement.evaluate_markers(env.marker_environment(), None, &[])
|
||||
requirement.evaluate_markers(
|
||||
env.marker_environment(),
|
||||
MarkerVariantsUniversal,
|
||||
&[],
|
||||
)
|
||||
},
|
||||
))
|
||||
}
|
||||
|
|
@ -251,7 +280,7 @@ impl Manifest {
|
|||
self.overrides
|
||||
.apply(self.requirements.iter())
|
||||
.filter(move |requirement| {
|
||||
requirement.evaluate_markers(env.marker_environment(), None, &[])
|
||||
requirement.evaluate_markers(env.marker_environment(), MarkerVariantsUniversal, &[])
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use tracing::trace;
|
|||
use uv_distribution_types::{IndexUrl, InstalledDist};
|
||||
use uv_normalize::PackageName;
|
||||
use uv_pep440::{Operator, Version};
|
||||
use uv_pep508::{MarkerTree, VerbatimUrl, VersionOrUrl};
|
||||
use uv_pep508::{MarkerTree, MarkerVariantsUniversal, VerbatimUrl, VersionOrUrl};
|
||||
use uv_pypi_types::{HashDigest, HashDigests, HashError};
|
||||
use uv_requirements_txt::{RequirementEntry, RequirementsTxtRequirement};
|
||||
|
||||
|
|
@ -241,7 +241,10 @@ impl Preferences {
|
|||
for preference in preferences {
|
||||
// Filter non-matching preferences when resolving for an environment.
|
||||
if let Some(markers) = env.marker_environment() {
|
||||
if !preference.marker.evaluate(markers, None, &[]) {
|
||||
if !preference
|
||||
.marker
|
||||
.evaluate(markers, MarkerVariantsUniversal, &[])
|
||||
{
|
||||
trace!("Excluding {preference} from preferences due to unmatched markers");
|
||||
continue;
|
||||
}
|
||||
|
|
@ -250,7 +253,7 @@ impl Preferences {
|
|||
if !preference
|
||||
.fork_markers
|
||||
.iter()
|
||||
.any(|marker| marker.evaluate_no_extras(markers, None))
|
||||
.any(|marker| marker.evaluate_no_extras(markers))
|
||||
{
|
||||
trace!(
|
||||
"Excluding {preference} from preferences due to unmatched fork markers"
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use rustc_hash::{FxBuildHasher, FxHashMap};
|
|||
|
||||
use uv_distribution_types::{DistributionMetadata, Name, SourceAnnotation, SourceAnnotations};
|
||||
use uv_normalize::PackageName;
|
||||
use uv_pep508::MarkerTree;
|
||||
use uv_pep508::{MarkerTree, MarkerVariantsUniversal};
|
||||
|
||||
use crate::resolution::{RequirementsTxtDist, ResolutionGraphNode};
|
||||
use crate::{ResolverEnvironment, ResolverOutput};
|
||||
|
|
@ -91,7 +91,11 @@ impl std::fmt::Display for DisplayResolutionGraph<'_> {
|
|||
let mut sources = SourceAnnotations::default();
|
||||
|
||||
for requirement in self.resolution.requirements.iter().filter(|requirement| {
|
||||
requirement.evaluate_markers(self.env.marker_environment(), None, &[])
|
||||
requirement.evaluate_markers(
|
||||
self.env.marker_environment(),
|
||||
MarkerVariantsUniversal,
|
||||
&[],
|
||||
)
|
||||
}) {
|
||||
if let Some(origin) = &requirement.origin {
|
||||
sources.add(
|
||||
|
|
@ -106,7 +110,11 @@ impl std::fmt::Display for DisplayResolutionGraph<'_> {
|
|||
.constraints
|
||||
.requirements()
|
||||
.filter(|requirement| {
|
||||
requirement.evaluate_markers(self.env.marker_environment(), None, &[])
|
||||
requirement.evaluate_markers(
|
||||
self.env.marker_environment(),
|
||||
MarkerVariantsUniversal,
|
||||
&[],
|
||||
)
|
||||
})
|
||||
{
|
||||
if let Some(origin) = &requirement.origin {
|
||||
|
|
@ -122,7 +130,11 @@ impl std::fmt::Display for DisplayResolutionGraph<'_> {
|
|||
.overrides
|
||||
.requirements()
|
||||
.filter(|requirement| {
|
||||
requirement.evaluate_markers(self.env.marker_environment(), None, &[])
|
||||
requirement.evaluate_markers(
|
||||
self.env.marker_environment(),
|
||||
MarkerVariantsUniversal,
|
||||
&[],
|
||||
)
|
||||
})
|
||||
{
|
||||
if let Some(origin) = &requirement.origin {
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ use uv_normalize::{ExtraName, GroupName, PackageName};
|
|||
use uv_pep440::{MIN_VERSION, Version, VersionSpecifiers, release_specifiers_to_ranges};
|
||||
use uv_pep508::{
|
||||
MarkerEnvironment, MarkerExpression, MarkerOperator, MarkerTree, MarkerValueString,
|
||||
MarkerVariantsEnvironment, MarkerVariantsUniversal,
|
||||
};
|
||||
use uv_platform_tags::Tags;
|
||||
use uv_pypi_types::{ConflictItem, ConflictItemRef, Conflicts, VerbatimParsedUrl};
|
||||
|
|
@ -84,7 +85,7 @@ use crate::{
|
|||
pub(crate) use provider::MetadataUnavailable;
|
||||
use uv_torch::TorchStrategy;
|
||||
use uv_variants::resolved_variants::ResolvedVariants;
|
||||
use uv_variants::variants_json::VariantPropertyType;
|
||||
use uv_variants::variants_json::Variant;
|
||||
|
||||
mod availability;
|
||||
mod batch_prefetch;
|
||||
|
|
@ -1819,7 +1820,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
|
|||
None,
|
||||
None,
|
||||
env,
|
||||
None,
|
||||
&MarkerVariantsUniversal,
|
||||
python_requirement,
|
||||
);
|
||||
|
||||
|
|
@ -1855,7 +1856,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
|
|||
|
||||
// If we're resolving for a specific environment, use the host variants, otherwise resolve
|
||||
// for all variants.
|
||||
let variants = Self::variant_properties(
|
||||
let variant = Self::variant_properties(
|
||||
name,
|
||||
version,
|
||||
&version_id,
|
||||
|
|
@ -1948,7 +1949,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
|
|||
dev.as_ref(),
|
||||
Some(name),
|
||||
env,
|
||||
variants.as_deref(),
|
||||
&variant,
|
||||
python_requirement,
|
||||
);
|
||||
|
||||
|
|
@ -2047,55 +2048,37 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
|
|||
pins: &FilePins,
|
||||
env: &ResolverEnvironment,
|
||||
in_memory_index: &InMemoryIndex,
|
||||
) -> Option<Vec<(String, String, String)>> {
|
||||
) -> Variant {
|
||||
// TODO(konsti): Perf/Caching with version selection: This is in the hot path!
|
||||
|
||||
env.marker_environment()?;
|
||||
let resolved_variants = in_memory_index
|
||||
if env.marker_environment().is_none() {
|
||||
return Variant::default();
|
||||
}
|
||||
let Some(resolved_variants) = in_memory_index
|
||||
.variant_priorities()
|
||||
.get(&(version_id.clone(), index_url.cloned()))?;
|
||||
.get(&(version_id.clone(), index_url.cloned()))
|
||||
else {
|
||||
return Variant::default();
|
||||
};
|
||||
|
||||
let filename = pins.get(name, version).unwrap().wheel_filename();
|
||||
let Some(filename) = filename else {
|
||||
// TODO(konsti): Handle installed dists too
|
||||
return None;
|
||||
return Variant::default();
|
||||
};
|
||||
let Some(variant_label) = filename.variant() else {
|
||||
warn!("Wheel variant has no associated variants: {filename}");
|
||||
return None;
|
||||
return Variant::default();
|
||||
};
|
||||
|
||||
// Collect the host properties for marker filtering.
|
||||
// TODO(konsti): Use the proper type everywhere, we shouldn't need to do
|
||||
// this conversion at all.
|
||||
let mut known_properties = BTreeSet::new();
|
||||
let namespaces = resolved_variants
|
||||
// TODO(konsti): We shouldn't need to clone
|
||||
let variant = resolved_variants
|
||||
.variants_json
|
||||
.variants
|
||||
.get(variant_label)
|
||||
.expect("Missing previously select variant label");
|
||||
for (namespace, features) in namespaces {
|
||||
for (feature, values) in features {
|
||||
for value in values {
|
||||
known_properties.insert(VariantPropertyType {
|
||||
namespace: namespace.clone(),
|
||||
feature: feature.clone(),
|
||||
value: value.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
let known_properties: Vec<(String, String, String)> = known_properties
|
||||
.into_iter()
|
||||
.map(|known_property| {
|
||||
(
|
||||
known_property.namespace,
|
||||
known_property.feature,
|
||||
known_property.value,
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
Some(known_properties)
|
||||
variant.clone()
|
||||
}
|
||||
|
||||
/// The regular and dev dependencies filtered by Python version and the markers of this fork,
|
||||
|
|
@ -2109,7 +2092,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
|
|||
dev: Option<&'a GroupName>,
|
||||
name: Option<&PackageName>,
|
||||
env: &'a ResolverEnvironment,
|
||||
variants: Option<&'a [(String, String, String)]>,
|
||||
variants: &'a impl MarkerVariantsEnvironment,
|
||||
python_requirement: &'a PythonRequirement,
|
||||
) -> impl Iterator<Item = Cow<'a, Requirement>> {
|
||||
let python_marker = python_requirement.to_marker_tree();
|
||||
|
|
@ -2166,7 +2149,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
|
|||
dependencies,
|
||||
Some(&extra),
|
||||
env,
|
||||
variants,
|
||||
&variants,
|
||||
python_marker,
|
||||
python_requirement,
|
||||
) {
|
||||
|
|
@ -2236,7 +2219,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
|
|||
dependencies: impl IntoIterator<Item = &'data Requirement> + 'parameters,
|
||||
extra: Option<&'parameters ExtraName>,
|
||||
env: &'parameters ResolverEnvironment,
|
||||
variants: Option<&'parameters [(String, String, String)]>,
|
||||
variants: &'parameters impl MarkerVariantsEnvironment,
|
||||
python_marker: MarkerTree,
|
||||
python_requirement: &'parameters PythonRequirement,
|
||||
) -> impl Iterator<Item = Cow<'data, Requirement>> + 'parameters
|
||||
|
|
@ -2273,7 +2256,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
|
|||
requirement: &Requirement,
|
||||
extra: Option<&ExtraName>,
|
||||
env: &ResolverEnvironment,
|
||||
variants: Option<&[(String, String, String)]>,
|
||||
variants: impl MarkerVariantsEnvironment,
|
||||
python_marker: MarkerTree,
|
||||
python_requirement: &PythonRequirement,
|
||||
) -> bool {
|
||||
|
|
@ -2281,12 +2264,12 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
|
|||
match extra {
|
||||
Some(source_extra) => {
|
||||
// Only include requirements that are relevant for the current extra.
|
||||
if requirement.evaluate_markers(env.marker_environment(), variants, &[]) {
|
||||
if requirement.evaluate_markers(env.marker_environment(), &variants, &[]) {
|
||||
return false;
|
||||
}
|
||||
if !requirement.evaluate_markers(
|
||||
env.marker_environment(),
|
||||
variants,
|
||||
&variants,
|
||||
slice::from_ref(source_extra),
|
||||
) {
|
||||
return false;
|
||||
|
|
@ -2330,7 +2313,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
|
|||
requirement: Cow<'data, Requirement>,
|
||||
extra: Option<&'parameters ExtraName>,
|
||||
env: &'parameters ResolverEnvironment,
|
||||
variants: Option<&'parameters [(String, String, String)]>,
|
||||
variants: impl MarkerVariantsEnvironment + 'parameters,
|
||||
python_marker: MarkerTree,
|
||||
python_requirement: &'parameters PythonRequirement,
|
||||
) -> impl Iterator<Item = Cow<'data, Requirement>> + 'parameters
|
||||
|
|
@ -2422,7 +2405,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
|
|||
match extra {
|
||||
Some(source_extra) => {
|
||||
if !constraint
|
||||
.evaluate_markers(env.marker_environment(), variants, slice::from_ref(source_extra))
|
||||
.evaluate_markers(env.marker_environment(), &variants, slice::from_ref(source_extra))
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
|
@ -2432,7 +2415,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
|
|||
}
|
||||
}
|
||||
None => {
|
||||
if !constraint.evaluate_markers(env.marker_environment(), variants, &[]) {
|
||||
if !constraint.evaluate_markers(env.marker_environment(), &variants, &[]) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use rustc_hash::FxHashMap;
|
|||
use uv_normalize::{ExtraName, GroupName, PackageName};
|
||||
use uv_pep508::{
|
||||
ExtraOperator, MarkerEnvironment, MarkerEnvironmentBuilder, MarkerExpression, MarkerOperator,
|
||||
MarkerTree,
|
||||
MarkerTree, MarkerVariantsEnvironment, MarkerVariantsUniversal,
|
||||
};
|
||||
use uv_pypi_types::{ConflictItem, ConflictPackage, Conflicts};
|
||||
|
||||
|
|
@ -239,12 +239,8 @@ impl UniversalMarker {
|
|||
///
|
||||
/// This should only be used when evaluating a marker that is known not to
|
||||
/// have any extras. For example, the PEP 508 markers on a fork.
|
||||
pub(crate) fn evaluate_no_extras(
|
||||
self,
|
||||
env: &MarkerEnvironment,
|
||||
variants: Option<&[(String, String, String)]>,
|
||||
) -> bool {
|
||||
self.marker.evaluate(env, variants, &[])
|
||||
pub(crate) fn evaluate_no_extras(self, env: &MarkerEnvironment) -> bool {
|
||||
self.marker.evaluate(env, MarkerVariantsUniversal, &[])
|
||||
}
|
||||
|
||||
/// Returns true if this universal marker is satisfied by the given marker
|
||||
|
|
@ -256,7 +252,7 @@ impl UniversalMarker {
|
|||
pub(crate) fn evaluate<P, E, G>(
|
||||
self,
|
||||
env: &MarkerEnvironment,
|
||||
variants: Option<&[(String, String, String)]>,
|
||||
variants: impl MarkerVariantsEnvironment,
|
||||
extras: impl Iterator<Item = (P, E)>,
|
||||
groups: impl Iterator<Item = (P, G)>,
|
||||
) -> bool
|
||||
|
|
@ -436,9 +432,9 @@ impl ConflictMarker {
|
|||
/// list of activated extras and groups.
|
||||
pub(crate) fn evaluate<P, E, G>(
|
||||
self,
|
||||
variants: Option<&[(String, String, String)]>,
|
||||
extras: &[(P, E)],
|
||||
groups: &[(P, G)],
|
||||
variants: impl MarkerVariantsEnvironment,
|
||||
) -> bool
|
||||
where
|
||||
P: Borrow<PackageName>,
|
||||
|
|
@ -745,7 +741,7 @@ pub(crate) fn resolve_conflicts(
|
|||
mod tests {
|
||||
use super::*;
|
||||
use std::str::FromStr;
|
||||
|
||||
use uv_pep508::MarkerVariantsUniversal;
|
||||
use uv_pypi_types::ConflictSet;
|
||||
|
||||
/// Creates a collection of declared conflicts from the sets
|
||||
|
|
@ -875,7 +871,7 @@ mod tests {
|
|||
.collect::<Vec<(PackageName, ExtraName)>>();
|
||||
let groups = Vec::<(PackageName, GroupName)>::new();
|
||||
assert!(
|
||||
!cm.evaluate(None, &extras, &groups),
|
||||
!cm.evaluate(&extras, &groups, MarkerVariantsUniversal),
|
||||
"expected `{extra_names:?}` to evaluate to `false` in `{cm:?}`"
|
||||
);
|
||||
}
|
||||
|
|
@ -898,7 +894,7 @@ mod tests {
|
|||
.collect::<Vec<(PackageName, ExtraName)>>();
|
||||
let groups = Vec::<(PackageName, GroupName)>::new();
|
||||
assert!(
|
||||
cm.evaluate(None, &extras, &groups),
|
||||
cm.evaluate(&extras, &groups, MarkerVariantsUniversal),
|
||||
"expected `{extra_names:?}` to evaluate to `true` in `{cm:?}`"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use uv_distribution_types::{
|
|||
};
|
||||
use uv_normalize::PackageName;
|
||||
use uv_pep440::Version;
|
||||
use uv_pep508::MarkerVariantsUniversal;
|
||||
use uv_pypi_types::{HashDigest, HashDigests, HashError, ResolverMarkerEnvironment};
|
||||
use uv_redacted::DisplaySafeUrl;
|
||||
|
||||
|
|
@ -136,7 +137,7 @@ impl HashStrategy {
|
|||
for (requirement, digests) in constraints {
|
||||
if !requirement.evaluate_markers(
|
||||
marker_env.map(ResolverMarkerEnvironment::markers),
|
||||
None,
|
||||
MarkerVariantsUniversal,
|
||||
&[],
|
||||
) {
|
||||
continue;
|
||||
|
|
@ -182,7 +183,7 @@ impl HashStrategy {
|
|||
for (requirement, digests) in requirements {
|
||||
if !requirement.evaluate_markers(
|
||||
marker_env.map(ResolverMarkerEnvironment::markers),
|
||||
None,
|
||||
MarkerVariantsUniversal,
|
||||
&[],
|
||||
) {
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ pub fn score_variant(
|
|||
target_namespaces: &FxHashMap<VariantNamespace, VariantProviderOutput>,
|
||||
variants_properties: &Variant,
|
||||
) -> Option<Vec<usize>> {
|
||||
for (namespace, features) in variants_properties {
|
||||
for (namespace, features) in &**variants_properties {
|
||||
for (feature, properties) in features {
|
||||
let resolved_properties = target_namespaces
|
||||
.get(namespace)
|
||||
|
|
|
|||
|
|
@ -1,18 +1,60 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use indoc::formatdoc;
|
||||
use rustc_hash::FxHashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use uv_pep508::Requirement;
|
||||
use uv_pep508::{MarkerVariantsEnvironment, Requirement};
|
||||
use uv_pypi_types::VerbatimParsedUrl;
|
||||
|
||||
/// Mapping of namespaces in a variant
|
||||
pub type Variant = FxHashMap<String, FxHashMap<String, Vec<String>>>;
|
||||
|
||||
// TODO(konsti): Validate the string contents
|
||||
pub type VariantNamespace = String;
|
||||
pub type VariantFeature = String;
|
||||
pub type VariantProperty = String;
|
||||
|
||||
/// Mapping of namespaces in a variant
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct Variant(FxHashMap<String, FxHashMap<String, Vec<String>>>);
|
||||
|
||||
impl MarkerVariantsEnvironment for Variant {
|
||||
fn has_namespace(&self, namespace: &str) -> bool {
|
||||
self.0.contains_key(namespace)
|
||||
}
|
||||
|
||||
fn has_feature(&self, namespace: &str, feature: &str) -> bool {
|
||||
let Some(features) = self.0.get(namespace) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let Some(properties) = features.get(feature) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
!properties.is_empty()
|
||||
}
|
||||
|
||||
fn has_property(&self, namespace: &str, feature: &str, property: &str) -> bool {
|
||||
let Some(features) = self.0.get(namespace) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let Some(properties) = features.get(feature) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
properties.iter().any(|p| p == property)
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Variant {
|
||||
type Target = FxHashMap<String, FxHashMap<String, Vec<String>>>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Combined index metadata for wheel variants.
|
||||
///
|
||||
/// See <https://wheelnext.dev/variants.json>
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ use uv_fs::Simplified;
|
|||
use uv_install_wheel::read_record_file;
|
||||
use uv_installer::SitePackages;
|
||||
use uv_normalize::PackageName;
|
||||
use uv_pep508::MarkerVariantsUniversal;
|
||||
use uv_python::{EnvironmentPreference, PythonEnvironment, PythonRequest};
|
||||
|
||||
use crate::commands::ExitStatus;
|
||||
|
|
@ -101,7 +102,7 @@ pub(crate) fn pip_show(
|
|||
requires_map.insert(
|
||||
dist.name(),
|
||||
Box::into_iter(metadata.requires_dist)
|
||||
.filter(|req| req.evaluate_markers(&markers, None, &[]))
|
||||
.filter(|req| req.evaluate_markers(&markers, MarkerVariantsUniversal, &[]))
|
||||
.map(|req| req.name)
|
||||
.sorted_unstable()
|
||||
.dedup()
|
||||
|
|
@ -117,7 +118,7 @@ pub(crate) fn pip_show(
|
|||
}
|
||||
if let Ok(metadata) = installed.metadata() {
|
||||
let requires = Box::into_iter(metadata.requires_dist)
|
||||
.filter(|req| req.evaluate_markers(&markers, None, &[]))
|
||||
.filter(|req| req.evaluate_markers(&markers, MarkerVariantsUniversal, &[]))
|
||||
.map(|req| req.name)
|
||||
.collect_vec();
|
||||
if !requires.is_empty() {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ use uv_distribution_types::{Diagnostic, IndexCapabilities, IndexLocations, Name,
|
|||
use uv_installer::SitePackages;
|
||||
use uv_normalize::PackageName;
|
||||
use uv_pep440::Version;
|
||||
use uv_pep508::{Requirement, VersionOrUrl};
|
||||
use uv_pep508::{MarkerVariantsUniversal, Requirement, VersionOrUrl};
|
||||
use uv_pypi_types::{ResolutionMetadata, ResolverMarkerEnvironment, VerbatimParsedUrl};
|
||||
use uv_python::{EnvironmentPreference, PythonEnvironment, PythonRequest};
|
||||
use uv_resolver::{ExcludeNewer, PrereleaseMode};
|
||||
|
|
@ -254,7 +254,10 @@ impl<'env> DisplayDependencyGraph<'env> {
|
|||
if prune.contains(&requirement.name) {
|
||||
continue;
|
||||
}
|
||||
if !requirement.marker.evaluate(markers, None, &[]) {
|
||||
if !requirement
|
||||
.marker
|
||||
.evaluate(markers, MarkerVariantsUniversal, &[])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ use uv_distribution_types::{
|
|||
use uv_fs::{PortablePathBuf, Simplified};
|
||||
use uv_installer::SitePackages;
|
||||
use uv_normalize::{DefaultExtras, DefaultGroups, PackageName};
|
||||
use uv_pep508::{MarkerTree, VersionOrUrl};
|
||||
use uv_pep508::{MarkerTree, MarkerVariantsUniversal, VersionOrUrl};
|
||||
use uv_pypi_types::{ParsedArchiveUrl, ParsedGitUrl, ParsedUrl};
|
||||
use uv_python::{PythonDownloads, PythonEnvironment, PythonPreference, PythonRequest};
|
||||
use uv_resolver::{FlatIndex, Installable, Lock};
|
||||
|
|
@ -622,7 +622,7 @@ pub(super) async fn do_sync(
|
|||
if !environments.is_empty() {
|
||||
if !environments
|
||||
.iter()
|
||||
.any(|env| env.evaluate(&marker_env, None, &[]))
|
||||
.any(|env| env.evaluate(&marker_env, MarkerVariantsUniversal, &[]))
|
||||
{
|
||||
return Err(ProjectError::LockedPlatformIncompatibility(
|
||||
// For error reporting, we use the "simplified"
|
||||
|
|
|
|||
Loading…
Reference in New Issue