From f5110f7b5e38055091c95c6b26d33f35857fad94 Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Sat, 10 Aug 2024 13:23:29 -0400 Subject: [PATCH] Remove uses of `Option` (#5978) ## Summary Follow up to https://github.com/astral-sh/uv/pull/5898. This should fix some of the failures in https://github.com/astral-sh/uv/pull/5887 where `uv lock --locked` is failing due to `Some(true)` and `None` markers not comparing equal. --- crates/distribution-types/src/resolution.rs | 3 +- crates/pep508-rs/src/lib.rs | 61 +++------- crates/pep508-rs/src/marker/mod.rs | 21 ++++ crates/pep508-rs/src/marker/tree.rs | 6 + crates/pep508-rs/src/unnamed.rs | 12 +- crates/pypi-types/src/requirement.rs | 36 ++---- crates/requirements-txt/src/lib.rs | 16 +-- ...nts_txt__test__line-endings-basic.txt.snap | 12 +- ..._test__line-endings-constraints-a.txt.snap | 6 +- ..._test__line-endings-constraints-b.txt.snap | 4 +- ...xt__test__line-endings-for-poetry.txt.snap | 8 +- ...txt__test__line-endings-include-a.txt.snap | 4 +- ...txt__test__line-endings-include-b.txt.snap | 2 +- ...__line-endings-poetry-with-hashes.txt.snap | 20 +--- ...nts_txt__test__line-endings-small.txt.snap | 4 +- ...xt__test__line-endings-whitespace.txt.snap | 4 +- ...quirements_txt__test__parse-basic.txt.snap | 12 +- ...ts_txt__test__parse-constraints-a.txt.snap | 6 +- ...ts_txt__test__parse-constraints-b.txt.snap | 4 +- ...ments_txt__test__parse-for-poetry.txt.snap | 8 +- ...ements_txt__test__parse-include-a.txt.snap | 4 +- ...ements_txt__test__parse-include-b.txt.snap | 2 +- ...t__test__parse-poetry-with-hashes.txt.snap | 20 +--- ...quirements_txt__test__parse-small.txt.snap | 4 +- ...ts_txt__test__parse-unix-bare-url.txt.snap | 6 +- ...ts_txt__test__parse-unix-editable.txt.snap | 18 +-- ...ments_txt__test__parse-whitespace.txt.snap | 4 +- ...txt__test__parse-windows-bare-url.txt.snap | 6 +- ...txt__test__parse-windows-editable.txt.snap | 18 +-- crates/uv-configuration/src/constraints.rs | 12 +- crates/uv-configuration/src/overrides.rs | 12 +- crates/uv-requirements/src/source_tree.rs | 12 +- crates/uv-requirements/src/specification.rs | 4 +- crates/uv-resolver/src/lock.rs | 107 ++++++++---------- crates/uv-resolver/src/preferences.rs | 12 +- crates/uv-resolver/src/pubgrub/package.rs | 6 +- crates/uv-resolver/src/resolution/graph.rs | 10 +- crates/uv-resolver/src/resolver/fork_map.rs | 9 +- crates/uv-resolver/src/resolver/mod.rs | 18 +-- ...missing_dependency_source_unambiguous.snap | 2 +- ...dependency_source_version_unambiguous.snap | 2 +- ...issing_dependency_version_unambiguous.snap | 2 +- crates/uv-workspace/src/pyproject_mut.rs | 4 +- crates/uv-workspace/src/workspace.rs | 4 +- crates/uv/src/commands/pip/tree.rs | 11 +- 45 files changed, 228 insertions(+), 330 deletions(-) diff --git a/crates/distribution-types/src/resolution.rs b/crates/distribution-types/src/resolution.rs index 87919bd04811..7d700ace606f 100644 --- a/crates/distribution-types/src/resolution.rs +++ b/crates/distribution-types/src/resolution.rs @@ -1,4 +1,5 @@ use distribution_filename::DistExtension; +use pep508_rs::MarkerTree; use pypi_types::{HashDigest, Requirement, RequirementSource}; use std::collections::BTreeMap; use uv_normalize::{ExtraName, GroupName, PackageName}; @@ -211,7 +212,7 @@ impl From<&ResolvedDist> for Requirement { Requirement { name: resolved_dist.name().clone(), extras: vec![], - marker: None, + marker: MarkerTree::TRUE, source, origin: None, } diff --git a/crates/pep508-rs/src/lib.rs b/crates/pep508-rs/src/lib.rs index 215cfcb2dc03..08556a18abe5 100644 --- a/crates/pep508-rs/src/lib.rs +++ b/crates/pep508-rs/src/lib.rs @@ -56,7 +56,7 @@ pub use verbatim_url::{ }; mod cursor; -mod marker; +pub mod marker; mod origin; #[cfg(feature = "non-pep508-extensions")] mod unnamed; @@ -149,7 +149,7 @@ pub struct Requirement { /// The markers such as `python_version > "3.8"` in /// `requests [security,tests] >= 2.8.1, == 2.8.* ; python_version > "3.8"`. /// Those are a nested and/or tree. - pub marker: Option, + pub marker: MarkerTree, /// The source file containing the requirement. pub origin: Option, } @@ -190,7 +190,7 @@ impl Display for Requirement { } } } - if let Some(marker) = self.marker.as_ref().and_then(MarkerTree::contents) { + if let Some(marker) = self.marker.contents() { write!(f, " ; {marker}")?; } Ok(()) @@ -256,10 +256,7 @@ impl PyRequirement { /// `requests [security,tests] >= 2.8.1, == 2.8.* ; python_version > "3.8"` #[getter] pub fn marker(&self) -> Option { - self.marker - .as_ref() - .and_then(MarkerTree::contents) - .map(|marker| marker.to_string()) + self.marker.try_to_string() } /// Parses a PEP 440 string @@ -375,11 +372,7 @@ impl PyRequirement { impl Requirement { /// Returns whether the markers apply for the given environment pub fn evaluate_markers(&self, env: &MarkerEnvironment, extras: &[ExtraName]) -> bool { - if let Some(marker) = &self.marker { - marker.evaluate(env, extras) - } else { - true - } + self.marker.evaluate(env, extras) } /// Returns whether the requirement would be satisfied, independent of environment markers, i.e. @@ -393,11 +386,8 @@ impl Requirement { extras: &HashSet, python_versions: &[Version], ) -> bool { - if let Some(marker) = &self.marker { - marker.evaluate_extras_and_python_version(extras, python_versions) - } else { - true - } + self.marker + .evaluate_extras_and_python_version(extras, python_versions) } /// Returns whether the markers apply for the given environment. @@ -406,11 +396,7 @@ impl Requirement { env: &MarkerEnvironment, extras: &[ExtraName], ) -> (bool, Vec) { - if let Some(marker) = &self.marker { - marker.evaluate_collect_warnings(env, extras) - } else { - (true, Vec::new()) - } + self.marker.evaluate_collect_warnings(env, extras) } /// Return the requirement with an additional marker added, to require the given extra. @@ -418,26 +404,14 @@ impl Requirement { /// For example, given `flask >= 2.0.2`, calling `with_extra_marker("dotenv")` would return /// `flask >= 2.0.2 ; extra == "dotenv"`. #[must_use] - pub fn with_extra_marker(self, extra: &ExtraName) -> Self { - let marker = match self.marker { - Some(mut marker) => { - let extra = MarkerTree::expression(MarkerExpression::Extra { - operator: ExtraOperator::Equal, - name: extra.clone(), - }); - marker.and(extra); - marker - } - None => MarkerTree::expression(MarkerExpression::Extra { + pub fn with_extra_marker(mut self, extra: &ExtraName) -> Self { + self.marker + .and(MarkerTree::expression(MarkerExpression::Extra { operator: ExtraOperator::Equal, name: extra.clone(), - }), - }; + })); - Self { - marker: Some(marker), - ..self - } + self } /// Set the source file containing the requirement. @@ -1053,6 +1027,7 @@ fn parse_pep508_requirement( } else { None }; + // wsp* cursor.eat_whitespace(); if let Some((pos, char)) = cursor.next() { @@ -1085,7 +1060,7 @@ fn parse_pep508_requirement( name, extras, version_or_url: requirement_kind, - marker, + marker: marker.unwrap_or_default(), origin: None, }) } @@ -1222,14 +1197,14 @@ mod tests { .into_iter() .collect(), )), - marker: Some(MarkerTree::expression(MarkerExpression::Version { + marker: MarkerTree::expression(MarkerExpression::Version { key: MarkerValueVersion::PythonVersion, specifier: VersionSpecifier::from_pattern( pep440_rs::Operator::LessThan, "2.7".parse().unwrap(), ) .unwrap(), - })), + }), origin: None, }; assert_eq!(requests, expected); @@ -1455,7 +1430,7 @@ mod tests { let expected = Requirement { name: PackageName::from_str("pip").unwrap(), extras: vec![], - marker: None, + marker: MarkerTree::TRUE, version_or_url: Some(VersionOrUrl::Url(Url::parse(url).unwrap())), origin: None, }; diff --git a/crates/pep508-rs/src/marker/mod.rs b/crates/pep508-rs/src/marker/mod.rs index 0bf200c97810..29a078ebc191 100644 --- a/crates/pep508-rs/src/marker/mod.rs +++ b/crates/pep508-rs/src/marker/mod.rs @@ -21,3 +21,24 @@ pub use tree::{ MarkerOperator, MarkerTree, MarkerTreeContents, MarkerTreeKind, MarkerValue, MarkerValueString, MarkerValueVersion, MarkerWarningKind, StringMarkerTree, StringVersion, VersionMarkerTree, }; + +/// `serde` helpers for [`MarkerTree`]. +pub mod ser { + use super::MarkerTree; + use serde::Serialize; + + /// A helper for `serde(skip_serializing_if)`. + pub fn is_empty(marker: &MarkerTree) -> bool { + marker.contents().is_none() + } + + /// A helper for `serde(serialize_with)`. + /// + /// Note this will panic if `marker.contents()` is `None`, and so should be paired with `is_empty`. + pub fn serialize(marker: &MarkerTree, s: S) -> Result + where + S: serde::Serializer, + { + marker.contents().unwrap().serialize(s) + } +} diff --git a/crates/pep508-rs/src/marker/tree.rs b/crates/pep508-rs/src/marker/tree.rs index 1939401a3686..b0518f880f6f 100644 --- a/crates/pep508-rs/src/marker/tree.rs +++ b/crates/pep508-rs/src/marker/tree.rs @@ -564,6 +564,12 @@ impl Display for MarkerExpression { #[derive(Clone, Eq, Hash, PartialEq, PartialOrd, Ord)] pub struct MarkerTree(NodeId); +impl Default for MarkerTree { + fn default() -> Self { + MarkerTree::TRUE + } +} + impl<'de> Deserialize<'de> for MarkerTree { fn deserialize(deserializer: D) -> Result where diff --git a/crates/pep508-rs/src/unnamed.rs b/crates/pep508-rs/src/unnamed.rs index 2e07c65accc6..a6244eed2353 100644 --- a/crates/pep508-rs/src/unnamed.rs +++ b/crates/pep508-rs/src/unnamed.rs @@ -75,7 +75,7 @@ pub struct UnnamedRequirement { /// The markers such as `python_version > "3.8"` in /// `requests [security,tests] >= 2.8.1, == 2.8.* ; python_version > "3.8"`. /// Those are a nested and/or tree. - pub marker: Option, + pub marker: MarkerTree, /// The source file containing the requirement. pub origin: Option, } @@ -92,11 +92,7 @@ impl UnnamedRequirement { env: Option<&MarkerEnvironment>, extras: &[ExtraName], ) -> bool { - if let Some(marker) = &self.marker { - marker.evaluate_optional_environment(env, extras) - } else { - true - } + self.marker.evaluate_optional_environment(env, extras) } /// Set the source file containing the requirement. @@ -136,7 +132,7 @@ impl Display for UnnamedRequirement { .join(",") )?; } - if let Some(marker) = self.marker.as_ref().and_then(MarkerTree::contents) { + if let Some(marker) = self.marker.contents() { write!(f, " ; {marker}")?; } Ok(()) @@ -207,7 +203,7 @@ fn parse_unnamed_requirement( Ok(UnnamedRequirement { url, extras, - marker, + marker: marker.unwrap_or_default(), origin: None, }) } diff --git a/crates/pypi-types/src/requirement.rs b/crates/pypi-types/src/requirement.rs index 5d994b3d3787..58e9cea3fd2b 100644 --- a/crates/pypi-types/src/requirement.rs +++ b/crates/pypi-types/src/requirement.rs @@ -3,12 +3,13 @@ use std::path::{Path, PathBuf}; use std::str::FromStr; use distribution_filename::DistExtension; -use serde::Serialize; use thiserror::Error; use url::Url; use pep440_rs::VersionSpecifiers; -use pep508_rs::{MarkerEnvironment, MarkerTree, RequirementOrigin, VerbatimUrl, VersionOrUrl}; +use pep508_rs::{ + marker, MarkerEnvironment, MarkerTree, RequirementOrigin, VerbatimUrl, VersionOrUrl, +}; use uv_fs::PortablePathBuf; use uv_git::{GitReference, GitSha, GitUrl}; use uv_normalize::{ExtraName, PackageName}; @@ -40,28 +41,17 @@ pub struct Requirement { #[serde(skip_serializing_if = "Vec::is_empty", default)] pub extras: Vec, #[serde( - skip_serializing_if = "marker_is_empty", - serialize_with = "serialize_marker", + skip_serializing_if = "marker::ser::is_empty", + serialize_with = "marker::ser::serialize", default )] - pub marker: Option, + pub marker: MarkerTree, #[serde(flatten)] pub source: RequirementSource, #[serde(skip)] pub origin: Option, } -fn marker_is_empty(marker: &Option) -> bool { - marker.as_ref().and_then(MarkerTree::contents).is_none() -} - -fn serialize_marker(marker: &Option, s: S) -> Result -where - S: serde::Serializer, -{ - marker.as_ref().unwrap().contents().unwrap().serialize(s) -} - impl Requirement { /// Returns whether the markers apply for the given environment. /// @@ -69,11 +59,7 @@ impl Requirement { /// expressions based on the environment to `true`. That is, this provides /// environment independent marker evaluation. pub fn evaluate_markers(&self, env: Option<&MarkerEnvironment>, extras: &[ExtraName]) -> bool { - if let Some(marker) = &self.marker { - marker.evaluate_optional_environment(env, extras) - } else { - true - } + self.marker.evaluate_optional_environment(env, extras) } /// Returns `true` if the requirement is editable. @@ -256,7 +242,7 @@ impl Display for Requirement { write!(f, " @ {url}")?; } } - if let Some(marker) = self.marker.as_ref().and_then(MarkerTree::contents) { + if let Some(marker) = self.marker.contents() { write!(f, " ; {marker}")?; } Ok(()) @@ -715,7 +701,7 @@ impl TryFrom for RequirementSource { mod tests { use std::path::{Path, PathBuf}; - use pep508_rs::VerbatimUrl; + use pep508_rs::{MarkerTree, VerbatimUrl}; use crate::{Requirement, RequirementSource}; @@ -724,7 +710,7 @@ mod tests { let requirement = Requirement { name: "foo".parse().unwrap(), extras: vec![], - marker: None, + marker: MarkerTree::TRUE, source: RequirementSource::Registry { specifier: ">1,<2".parse().unwrap(), index: None, @@ -744,7 +730,7 @@ mod tests { let requirement = Requirement { name: "foo".parse().unwrap(), extras: vec![], - marker: None, + marker: MarkerTree::TRUE, source: RequirementSource::Directory { install_path: PathBuf::from(path), lock_path: PathBuf::from(path), diff --git a/crates/requirements-txt/src/lib.rs b/crates/requirements-txt/src/lib.rs index 7c5a17716847..7005f60f5fb1 100644 --- a/crates/requirements-txt/src/lib.rs +++ b/crates/requirements-txt/src/lib.rs @@ -1691,7 +1691,7 @@ mod test { ), extras: [], version_or_url: None, - marker: None, + marker: true, origin: Some( File( "/subdir/sibling.txt", @@ -1755,7 +1755,7 @@ mod test { ), extras: [], version_or_url: None, - marker: None, + marker: true, origin: Some( File( "/requirements.txt", @@ -1864,7 +1864,7 @@ mod test { }, }, extras: [], - marker: None, + marker: true, origin: Some( File( "/grandchild.txt", @@ -1978,7 +1978,7 @@ mod test { ), extras: [], version_or_url: None, - marker: None, + marker: true, origin: Some( File( "/./sibling.txt", @@ -2007,7 +2007,7 @@ mod test { ), ), ), - marker: None, + marker: true, origin: Some( File( "/requirements.txt", @@ -2038,7 +2038,7 @@ mod test { ), ), ), - marker: None, + marker: true, origin: Some( File( "/requirements.txt", @@ -2069,7 +2069,7 @@ mod test { ), ), ), - marker: None, + marker: true, origin: Some( File( "/requirements.txt", @@ -2098,7 +2098,7 @@ mod test { ), ), ), - marker: None, + marker: true, origin: Some( File( "/requirements.txt", diff --git a/crates/requirements-txt/src/snapshots/requirements_txt__test__line-endings-basic.txt.snap b/crates/requirements-txt/src/snapshots/requirements_txt__test__line-endings-basic.txt.snap index 60d86edb04b7..7e4e91716566 100644 --- a/crates/requirements-txt/src/snapshots/requirements_txt__test__line-endings-basic.txt.snap +++ b/crates/requirements-txt/src/snapshots/requirements_txt__test__line-endings-basic.txt.snap @@ -23,7 +23,7 @@ RequirementsTxt { ), ), ), - marker: None, + marker: true, origin: Some( File( "/basic.txt", @@ -52,7 +52,7 @@ RequirementsTxt { ), ), ), - marker: None, + marker: true, origin: Some( File( "/basic.txt", @@ -81,7 +81,7 @@ RequirementsTxt { ), ), ), - marker: None, + marker: true, origin: Some( File( "/basic.txt", @@ -110,7 +110,7 @@ RequirementsTxt { ), ), ), - marker: None, + marker: true, origin: Some( File( "/basic.txt", @@ -139,7 +139,7 @@ RequirementsTxt { ), ), ), - marker: None, + marker: true, origin: Some( File( "/basic.txt", @@ -168,7 +168,7 @@ RequirementsTxt { ), ), ), - marker: None, + marker: true, origin: Some( File( "/basic.txt", diff --git a/crates/requirements-txt/src/snapshots/requirements_txt__test__line-endings-constraints-a.txt.snap b/crates/requirements-txt/src/snapshots/requirements_txt__test__line-endings-constraints-a.txt.snap index 5fa0a3a74002..23936a97f567 100644 --- a/crates/requirements-txt/src/snapshots/requirements_txt__test__line-endings-constraints-a.txt.snap +++ b/crates/requirements-txt/src/snapshots/requirements_txt__test__line-endings-constraints-a.txt.snap @@ -23,7 +23,7 @@ RequirementsTxt { ), ), ), - marker: None, + marker: true, origin: Some( File( "/constraints-a.txt", @@ -52,7 +52,7 @@ RequirementsTxt { ), ), ), - marker: None, + marker: true, origin: Some( File( "/constraints-b.txt", @@ -76,7 +76,7 @@ RequirementsTxt { ), ), ), - marker: None, + marker: true, origin: Some( File( "/constraints-b.txt", diff --git a/crates/requirements-txt/src/snapshots/requirements_txt__test__line-endings-constraints-b.txt.snap b/crates/requirements-txt/src/snapshots/requirements_txt__test__line-endings-constraints-b.txt.snap index 5068a0870d42..37181b2c7ef6 100644 --- a/crates/requirements-txt/src/snapshots/requirements_txt__test__line-endings-constraints-b.txt.snap +++ b/crates/requirements-txt/src/snapshots/requirements_txt__test__line-endings-constraints-b.txt.snap @@ -23,7 +23,7 @@ RequirementsTxt { ), ), ), - marker: None, + marker: true, origin: Some( File( "/constraints-b.txt", @@ -52,7 +52,7 @@ RequirementsTxt { ), ), ), - marker: None, + marker: true, origin: Some( File( "/constraints-b.txt", diff --git a/crates/requirements-txt/src/snapshots/requirements_txt__test__line-endings-for-poetry.txt.snap b/crates/requirements-txt/src/snapshots/requirements_txt__test__line-endings-for-poetry.txt.snap index 6073a0df0330..81116f5acfea 100644 --- a/crates/requirements-txt/src/snapshots/requirements_txt__test__line-endings-for-poetry.txt.snap +++ b/crates/requirements-txt/src/snapshots/requirements_txt__test__line-endings-for-poetry.txt.snap @@ -23,7 +23,7 @@ RequirementsTxt { ), ), ), - marker: None, + marker: true, origin: Some( File( "/for-poetry.txt", @@ -52,7 +52,7 @@ RequirementsTxt { ), ), ), - marker: None, + marker: true, origin: Some( File( "/for-poetry.txt", @@ -70,7 +70,7 @@ RequirementsTxt { ), extras: [], version_or_url: None, - marker: None, + marker: true, origin: Some( File( "/for-poetry.txt", @@ -107,7 +107,7 @@ RequirementsTxt { ), ), ), - marker: None, + marker: true, origin: Some( File( "/for-poetry.txt", diff --git a/crates/requirements-txt/src/snapshots/requirements_txt__test__line-endings-include-a.txt.snap b/crates/requirements-txt/src/snapshots/requirements_txt__test__line-endings-include-a.txt.snap index 431b25b2cd85..600237f91e43 100644 --- a/crates/requirements-txt/src/snapshots/requirements_txt__test__line-endings-include-a.txt.snap +++ b/crates/requirements-txt/src/snapshots/requirements_txt__test__line-endings-include-a.txt.snap @@ -12,7 +12,7 @@ RequirementsTxt { ), extras: [], version_or_url: None, - marker: None, + marker: true, origin: Some( File( "/include-b.txt", @@ -41,7 +41,7 @@ RequirementsTxt { ), ), ), - marker: None, + marker: true, origin: Some( File( "/include-a.txt", diff --git a/crates/requirements-txt/src/snapshots/requirements_txt__test__line-endings-include-b.txt.snap b/crates/requirements-txt/src/snapshots/requirements_txt__test__line-endings-include-b.txt.snap index 9cbe6c861ad6..4fcb6d137a6a 100644 --- a/crates/requirements-txt/src/snapshots/requirements_txt__test__line-endings-include-b.txt.snap +++ b/crates/requirements-txt/src/snapshots/requirements_txt__test__line-endings-include-b.txt.snap @@ -12,7 +12,7 @@ RequirementsTxt { ), extras: [], version_or_url: None, - marker: None, + marker: true, origin: Some( File( "/include-b.txt", diff --git a/crates/requirements-txt/src/snapshots/requirements_txt__test__line-endings-poetry-with-hashes.txt.snap b/crates/requirements-txt/src/snapshots/requirements_txt__test__line-endings-poetry-with-hashes.txt.snap index 556273fbf294..87aafb3e5382 100644 --- a/crates/requirements-txt/src/snapshots/requirements_txt__test__line-endings-poetry-with-hashes.txt.snap +++ b/crates/requirements-txt/src/snapshots/requirements_txt__test__line-endings-poetry-with-hashes.txt.snap @@ -23,9 +23,7 @@ RequirementsTxt { ), ), ), - marker: Some( - python_version >= '3.8' and python_version < '4.0', - ), + marker: python_version >= '3.8' and python_version < '4.0', origin: Some( File( "/poetry-with-hashes.txt", @@ -56,9 +54,7 @@ RequirementsTxt { ), ), ), - marker: Some( - python_version >= '3.8' and python_version < '4.0', - ), + marker: python_version >= '3.8' and python_version < '4.0', origin: Some( File( "/poetry-with-hashes.txt", @@ -89,9 +85,7 @@ RequirementsTxt { ), ), ), - marker: Some( - python_version >= '3.8' and python_version < '4.0' and platform_system == 'Windows', - ), + marker: python_version >= '3.8' and python_version < '4.0' and platform_system == 'Windows', origin: Some( File( "/poetry-with-hashes.txt", @@ -122,9 +116,7 @@ RequirementsTxt { ), ), ), - marker: Some( - python_version >= '3.8' and python_version < '4.0', - ), + marker: python_version >= '3.8' and python_version < '4.0', origin: Some( File( "/poetry-with-hashes.txt", @@ -156,9 +148,7 @@ RequirementsTxt { ), ), ), - marker: Some( - python_version >= '3.8' and python_version < '4.0', - ), + marker: python_version >= '3.8' and python_version < '4.0', origin: Some( File( "/poetry-with-hashes.txt", diff --git a/crates/requirements-txt/src/snapshots/requirements_txt__test__line-endings-small.txt.snap b/crates/requirements-txt/src/snapshots/requirements_txt__test__line-endings-small.txt.snap index c57791d2d596..c946cc2cab6e 100644 --- a/crates/requirements-txt/src/snapshots/requirements_txt__test__line-endings-small.txt.snap +++ b/crates/requirements-txt/src/snapshots/requirements_txt__test__line-endings-small.txt.snap @@ -23,7 +23,7 @@ RequirementsTxt { ), ), ), - marker: None, + marker: true, origin: Some( File( "/small.txt", @@ -52,7 +52,7 @@ RequirementsTxt { ), ), ), - marker: None, + marker: true, origin: Some( File( "/small.txt", diff --git a/crates/requirements-txt/src/snapshots/requirements_txt__test__line-endings-whitespace.txt.snap b/crates/requirements-txt/src/snapshots/requirements_txt__test__line-endings-whitespace.txt.snap index 181e74dbe6e5..b4800fd93e17 100644 --- a/crates/requirements-txt/src/snapshots/requirements_txt__test__line-endings-whitespace.txt.snap +++ b/crates/requirements-txt/src/snapshots/requirements_txt__test__line-endings-whitespace.txt.snap @@ -12,7 +12,7 @@ RequirementsTxt { ), extras: [], version_or_url: None, - marker: None, + marker: true, origin: Some( File( "/whitespace.txt", @@ -83,7 +83,7 @@ RequirementsTxt { }, ), ), - marker: None, + marker: true, origin: Some( File( "/whitespace.txt", diff --git a/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-basic.txt.snap b/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-basic.txt.snap index 60d86edb04b7..7e4e91716566 100644 --- a/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-basic.txt.snap +++ b/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-basic.txt.snap @@ -23,7 +23,7 @@ RequirementsTxt { ), ), ), - marker: None, + marker: true, origin: Some( File( "/basic.txt", @@ -52,7 +52,7 @@ RequirementsTxt { ), ), ), - marker: None, + marker: true, origin: Some( File( "/basic.txt", @@ -81,7 +81,7 @@ RequirementsTxt { ), ), ), - marker: None, + marker: true, origin: Some( File( "/basic.txt", @@ -110,7 +110,7 @@ RequirementsTxt { ), ), ), - marker: None, + marker: true, origin: Some( File( "/basic.txt", @@ -139,7 +139,7 @@ RequirementsTxt { ), ), ), - marker: None, + marker: true, origin: Some( File( "/basic.txt", @@ -168,7 +168,7 @@ RequirementsTxt { ), ), ), - marker: None, + marker: true, origin: Some( File( "/basic.txt", diff --git a/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-constraints-a.txt.snap b/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-constraints-a.txt.snap index 5fa0a3a74002..23936a97f567 100644 --- a/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-constraints-a.txt.snap +++ b/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-constraints-a.txt.snap @@ -23,7 +23,7 @@ RequirementsTxt { ), ), ), - marker: None, + marker: true, origin: Some( File( "/constraints-a.txt", @@ -52,7 +52,7 @@ RequirementsTxt { ), ), ), - marker: None, + marker: true, origin: Some( File( "/constraints-b.txt", @@ -76,7 +76,7 @@ RequirementsTxt { ), ), ), - marker: None, + marker: true, origin: Some( File( "/constraints-b.txt", diff --git a/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-constraints-b.txt.snap b/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-constraints-b.txt.snap index 5068a0870d42..37181b2c7ef6 100644 --- a/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-constraints-b.txt.snap +++ b/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-constraints-b.txt.snap @@ -23,7 +23,7 @@ RequirementsTxt { ), ), ), - marker: None, + marker: true, origin: Some( File( "/constraints-b.txt", @@ -52,7 +52,7 @@ RequirementsTxt { ), ), ), - marker: None, + marker: true, origin: Some( File( "/constraints-b.txt", diff --git a/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-for-poetry.txt.snap b/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-for-poetry.txt.snap index 6073a0df0330..81116f5acfea 100644 --- a/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-for-poetry.txt.snap +++ b/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-for-poetry.txt.snap @@ -23,7 +23,7 @@ RequirementsTxt { ), ), ), - marker: None, + marker: true, origin: Some( File( "/for-poetry.txt", @@ -52,7 +52,7 @@ RequirementsTxt { ), ), ), - marker: None, + marker: true, origin: Some( File( "/for-poetry.txt", @@ -70,7 +70,7 @@ RequirementsTxt { ), extras: [], version_or_url: None, - marker: None, + marker: true, origin: Some( File( "/for-poetry.txt", @@ -107,7 +107,7 @@ RequirementsTxt { ), ), ), - marker: None, + marker: true, origin: Some( File( "/for-poetry.txt", diff --git a/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-include-a.txt.snap b/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-include-a.txt.snap index 431b25b2cd85..600237f91e43 100644 --- a/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-include-a.txt.snap +++ b/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-include-a.txt.snap @@ -12,7 +12,7 @@ RequirementsTxt { ), extras: [], version_or_url: None, - marker: None, + marker: true, origin: Some( File( "/include-b.txt", @@ -41,7 +41,7 @@ RequirementsTxt { ), ), ), - marker: None, + marker: true, origin: Some( File( "/include-a.txt", diff --git a/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-include-b.txt.snap b/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-include-b.txt.snap index 9cbe6c861ad6..4fcb6d137a6a 100644 --- a/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-include-b.txt.snap +++ b/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-include-b.txt.snap @@ -12,7 +12,7 @@ RequirementsTxt { ), extras: [], version_or_url: None, - marker: None, + marker: true, origin: Some( File( "/include-b.txt", diff --git a/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-poetry-with-hashes.txt.snap b/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-poetry-with-hashes.txt.snap index 556273fbf294..87aafb3e5382 100644 --- a/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-poetry-with-hashes.txt.snap +++ b/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-poetry-with-hashes.txt.snap @@ -23,9 +23,7 @@ RequirementsTxt { ), ), ), - marker: Some( - python_version >= '3.8' and python_version < '4.0', - ), + marker: python_version >= '3.8' and python_version < '4.0', origin: Some( File( "/poetry-with-hashes.txt", @@ -56,9 +54,7 @@ RequirementsTxt { ), ), ), - marker: Some( - python_version >= '3.8' and python_version < '4.0', - ), + marker: python_version >= '3.8' and python_version < '4.0', origin: Some( File( "/poetry-with-hashes.txt", @@ -89,9 +85,7 @@ RequirementsTxt { ), ), ), - marker: Some( - python_version >= '3.8' and python_version < '4.0' and platform_system == 'Windows', - ), + marker: python_version >= '3.8' and python_version < '4.0' and platform_system == 'Windows', origin: Some( File( "/poetry-with-hashes.txt", @@ -122,9 +116,7 @@ RequirementsTxt { ), ), ), - marker: Some( - python_version >= '3.8' and python_version < '4.0', - ), + marker: python_version >= '3.8' and python_version < '4.0', origin: Some( File( "/poetry-with-hashes.txt", @@ -156,9 +148,7 @@ RequirementsTxt { ), ), ), - marker: Some( - python_version >= '3.8' and python_version < '4.0', - ), + marker: python_version >= '3.8' and python_version < '4.0', origin: Some( File( "/poetry-with-hashes.txt", diff --git a/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-small.txt.snap b/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-small.txt.snap index c57791d2d596..c946cc2cab6e 100644 --- a/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-small.txt.snap +++ b/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-small.txt.snap @@ -23,7 +23,7 @@ RequirementsTxt { ), ), ), - marker: None, + marker: true, origin: Some( File( "/small.txt", @@ -52,7 +52,7 @@ RequirementsTxt { ), ), ), - marker: None, + marker: true, origin: Some( File( "/small.txt", diff --git a/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-unix-bare-url.txt.snap b/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-unix-bare-url.txt.snap index 5b354448d3f6..32a0becfafe1 100644 --- a/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-unix-bare-url.txt.snap +++ b/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-unix-bare-url.txt.snap @@ -44,7 +44,7 @@ RequirementsTxt { }, }, extras: [], - marker: None, + marker: true, origin: Some( File( "/bare-url.txt", @@ -98,7 +98,7 @@ RequirementsTxt { "dev", ), ], - marker: None, + marker: true, origin: Some( File( "/bare-url.txt", @@ -148,7 +148,7 @@ RequirementsTxt { }, }, extras: [], - marker: None, + marker: true, origin: Some( File( "/bare-url.txt", diff --git a/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-unix-editable.txt.snap b/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-unix-editable.txt.snap index ebbce9d1cde8..fbddd4a08380 100644 --- a/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-unix-editable.txt.snap +++ b/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-unix-editable.txt.snap @@ -53,7 +53,7 @@ RequirementsTxt { "dev", ), ], - marker: None, + marker: true, origin: Some( File( "/editable.txt", @@ -110,7 +110,7 @@ RequirementsTxt { "dev", ), ], - marker: None, + marker: true, origin: Some( File( "/editable.txt", @@ -167,9 +167,7 @@ RequirementsTxt { "dev", ), ], - marker: Some( - python_version >= '3.9' and os_name == 'posix', - ), + marker: python_version >= '3.9' and os_name == 'posix', origin: Some( File( "/editable.txt", @@ -226,9 +224,7 @@ RequirementsTxt { "dev", ), ], - marker: Some( - python_version >= '3.9' and os_name == 'posix', - ), + marker: python_version >= '3.9' and os_name == 'posix', origin: Some( File( "/editable.txt", @@ -278,9 +274,7 @@ RequirementsTxt { }, }, extras: [], - marker: Some( - python_version >= '3.9' and os_name == 'posix', - ), + marker: python_version >= '3.9' and os_name == 'posix', origin: Some( File( "/editable.txt", @@ -330,7 +324,7 @@ RequirementsTxt { }, }, extras: [], - marker: None, + marker: true, origin: Some( File( "/editable.txt", diff --git a/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-whitespace.txt.snap b/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-whitespace.txt.snap index 181e74dbe6e5..b4800fd93e17 100644 --- a/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-whitespace.txt.snap +++ b/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-whitespace.txt.snap @@ -12,7 +12,7 @@ RequirementsTxt { ), extras: [], version_or_url: None, - marker: None, + marker: true, origin: Some( File( "/whitespace.txt", @@ -83,7 +83,7 @@ RequirementsTxt { }, ), ), - marker: None, + marker: true, origin: Some( File( "/whitespace.txt", diff --git a/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-windows-bare-url.txt.snap b/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-windows-bare-url.txt.snap index ddf5d5c52434..68a137a00c20 100644 --- a/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-windows-bare-url.txt.snap +++ b/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-windows-bare-url.txt.snap @@ -44,7 +44,7 @@ RequirementsTxt { }, }, extras: [], - marker: None, + marker: true, origin: Some( File( "/bare-url.txt", @@ -98,7 +98,7 @@ RequirementsTxt { "dev", ), ], - marker: None, + marker: true, origin: Some( File( "/bare-url.txt", @@ -148,7 +148,7 @@ RequirementsTxt { }, }, extras: [], - marker: None, + marker: true, origin: Some( File( "/bare-url.txt", diff --git a/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-windows-editable.txt.snap b/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-windows-editable.txt.snap index d648d594c2e3..5d212db86b4e 100644 --- a/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-windows-editable.txt.snap +++ b/crates/requirements-txt/src/snapshots/requirements_txt__test__parse-windows-editable.txt.snap @@ -53,7 +53,7 @@ RequirementsTxt { "dev", ), ], - marker: None, + marker: true, origin: Some( File( "/editable.txt", @@ -110,7 +110,7 @@ RequirementsTxt { "dev", ), ], - marker: None, + marker: true, origin: Some( File( "/editable.txt", @@ -167,9 +167,7 @@ RequirementsTxt { "dev", ), ], - marker: Some( - python_version >= '3.9' and os_name == 'posix', - ), + marker: python_version >= '3.9' and os_name == 'posix', origin: Some( File( "/editable.txt", @@ -226,9 +224,7 @@ RequirementsTxt { "dev", ), ], - marker: Some( - python_version >= '3.9' and os_name == 'posix', - ), + marker: python_version >= '3.9' and os_name == 'posix', origin: Some( File( "/editable.txt", @@ -278,9 +274,7 @@ RequirementsTxt { }, }, extras: [], - marker: Some( - python_version >= '3.9' and os_name == 'posix', - ), + marker: python_version >= '3.9' and os_name == 'posix', origin: Some( File( "/editable.txt", @@ -330,7 +324,7 @@ RequirementsTxt { }, }, extras: [], - marker: None, + marker: true, origin: Some( File( "/editable.txt", diff --git a/crates/uv-configuration/src/constraints.rs b/crates/uv-configuration/src/constraints.rs index 9a5d892dc998..16a7bc6d8ab9 100644 --- a/crates/uv-configuration/src/constraints.rs +++ b/crates/uv-configuration/src/constraints.rs @@ -60,11 +60,7 @@ impl Constraints { // ASSUMPTION: There is one `extra = "..."`, and it's either the only marker or part // of the main conjunction. - let Some(extra_expression) = requirement - .marker - .as_ref() - .and_then(MarkerTree::top_level_extra) - else { + let Some(extra_expression) = requirement.marker.top_level_extra() else { // Case 2: A non-optional dependency with constraint(s). return Either::Right(Either::Right( std::iter::once(requirement).chain(constraints.iter().map(Cow::Borrowed)), @@ -79,11 +75,9 @@ impl Constraints { constraints.iter().cloned().map(move |constraint| { // Add the extra to the override marker. let mut joint_marker = MarkerTree::expression(extra_expression.clone()); - if let Some(marker) = &constraint.marker { - joint_marker.and(marker.clone()); - } + joint_marker.and(constraint.marker.clone()); Cow::Owned(Requirement { - marker: Some(joint_marker.clone()), + marker: joint_marker, ..constraint }) }), diff --git a/crates/uv-configuration/src/overrides.rs b/crates/uv-configuration/src/overrides.rs index f0c12aafcfe9..316ac998d11f 100644 --- a/crates/uv-configuration/src/overrides.rs +++ b/crates/uv-configuration/src/overrides.rs @@ -50,11 +50,7 @@ impl Overrides { // ASSUMPTION: There is one `extra = "..."`, and it's either the only marker or part // of the main conjunction. - let Some(extra_expression) = requirement - .marker - .as_ref() - .and_then(MarkerTree::top_level_extra) - else { + let Some(extra_expression) = requirement.marker.top_level_extra() else { // Case 2: A non-optional dependency with override(s). return Either::Right(Either::Right(overrides.iter().map(Cow::Borrowed))); }; @@ -67,11 +63,9 @@ impl Overrides { move |override_requirement| { // Add the extra to the override marker. let mut joint_marker = MarkerTree::expression(extra_expression.clone()); - if let Some(marker) = &override_requirement.marker { - joint_marker.and(marker.clone()); - } + joint_marker.and(override_requirement.marker.clone()); Cow::Owned(Requirement { - marker: Some(joint_marker.clone()), + marker: joint_marker, ..override_requirement.clone() }) }, diff --git a/crates/uv-requirements/src/source_tree.rs b/crates/uv-requirements/src/source_tree.rs index 0f223f418a8e..c259a6339896 100644 --- a/crates/uv-requirements/src/source_tree.rs +++ b/crates/uv-requirements/src/source_tree.rs @@ -104,10 +104,7 @@ impl<'a, Context: BuildContext> SourceTreeResolver<'a, Context> { .into_iter() .map(|requirement| Requirement { origin: Some(origin.clone()), - marker: requirement - .marker - .map(|marker| marker.simplify_extras(extras)) - .filter(|marker| !marker.is_true()), + marker: requirement.marker.simplify_extras(extras), ..requirement }) .collect(); @@ -117,7 +114,7 @@ impl<'a, Context: BuildContext> SourceTreeResolver<'a, Context> { // Find the first recursive requirement. // TODO(charlie): Respect markers on recursive extras. let Some(index) = requirements.iter().position(|requirement| { - requirement.name == metadata.name && requirement.marker.is_none() + requirement.name == metadata.name && requirement.marker.is_true() }) else { break; }; @@ -129,9 +126,8 @@ impl<'a, Context: BuildContext> SourceTreeResolver<'a, Context> { for requirement in &mut requirements { requirement.marker = requirement .marker - .take() - .map(|marker| marker.simplify_extras(&recursive.extras)) - .filter(|marker| !marker.is_true()); + .clone() + .simplify_extras(&recursive.extras); } } diff --git a/crates/uv-requirements/src/specification.rs b/crates/uv-requirements/src/specification.rs index 3784962dfa9b..211423b036f9 100644 --- a/crates/uv-requirements/src/specification.rs +++ b/crates/uv-requirements/src/specification.rs @@ -37,7 +37,7 @@ use cache_key::CanonicalUrl; use distribution_types::{ FlatIndexLocation, IndexUrl, UnresolvedRequirement, UnresolvedRequirementSpecification, }; -use pep508_rs::{UnnamedRequirement, UnnamedRequirementUrl}; +use pep508_rs::{MarkerTree, UnnamedRequirement, UnnamedRequirementUrl}; use pypi_types::Requirement; use pypi_types::VerbatimParsedUrl; use requirements_txt::{RequirementsTxt, RequirementsTxtRequirement}; @@ -193,7 +193,7 @@ impl RequirementsSpecification { requirement: UnresolvedRequirement::Unnamed(UnnamedRequirement { url: VerbatimParsedUrl::parse_absolute_path(path)?, extras: vec![], - marker: None, + marker: MarkerTree::TRUE, origin: None, }), hashes: vec![], diff --git a/crates/uv-resolver/src/lock.rs b/crates/uv-resolver/src/lock.rs index 901b1530e7c2..814ae3dcb125 100644 --- a/crates/uv-resolver/src/lock.rs +++ b/crates/uv-resolver/src/lock.rs @@ -94,30 +94,24 @@ impl Lock { for package in &mut lock.packages { for dep in &mut package.dependencies { - if let Some(marker) = &mut dep.marker { - *marker = marker.clone().simplify_python_versions( - python_version.clone(), - python_full_version.clone(), - ); - } + dep.marker = dep.marker.clone().simplify_python_versions( + python_version.clone(), + python_full_version.clone(), + ); } for dep in package.optional_dependencies.values_mut().flatten() { - if let Some(marker) = &mut dep.marker { - *marker = marker.clone().simplify_python_versions( - python_version.clone(), - python_full_version.clone(), - ); - } + dep.marker = dep.marker.clone().simplify_python_versions( + python_version.clone(), + python_full_version.clone(), + ); } for dep in package.dev_dependencies.values_mut().flatten() { - if let Some(marker) = &mut dep.marker { - *marker = marker.clone().simplify_python_versions( - python_version.clone(), - python_full_version.clone(), - ); - } + dep.marker = dep.marker.clone().simplify_python_versions( + python_version.clone(), + python_full_version.clone(), + ); } } } @@ -146,8 +140,8 @@ impl Lock { else { continue; }; - let marker = edge.weight().as_ref(); - locked_dist.add_dependency(dependency_dist, marker); + let marker = edge.weight().clone(); + locked_dist.add_dependency(dependency_dist, marker.unwrap_or_default()); } let id = locked_dist.id.clone(); if let Some(locked_dist) = locked_dists.insert(id, locked_dist) { @@ -178,8 +172,12 @@ impl Lock { else { continue; }; - let marker = edge.weight().as_ref(); - locked_dist.add_optional_dependency(extra.clone(), dependency_dist, marker); + let marker = edge.weight().clone(); + locked_dist.add_optional_dependency( + extra.clone(), + dependency_dist, + marker.unwrap_or_default(), + ); } } if let Some(group) = dist.dev.as_ref() { @@ -196,8 +194,12 @@ impl Lock { else { continue; }; - let marker = edge.weight().as_ref(); - locked_dist.add_dev_dependency(group.clone(), dependency_dist, marker); + let marker = edge.weight().clone(); + locked_dist.add_dev_dependency( + group.clone(), + dependency_dist, + marker.unwrap_or_default(), + ); } } } @@ -488,11 +490,7 @@ impl Lock { )) }; for dep in deps { - if dep - .marker - .as_ref() - .map_or(true, |marker| marker.evaluate(marker_env, &[])) - { + if dep.marker.evaluate(marker_env, &[]) { let dep_dist = self.find_by_id(&dep.package_id); if seen.insert((&dep.package_id, None)) { queue.push_back((dep_dist, None)); @@ -772,7 +770,7 @@ impl Package { } /// Add the [`AnnotatedDist`] as a dependency of the [`Package`]. - fn add_dependency(&mut self, annotated_dist: &AnnotatedDist, marker: Option<&MarkerTree>) { + fn add_dependency(&mut self, annotated_dist: &AnnotatedDist, marker: MarkerTree) { let new_dep = Dependency::from_annotated_dist(annotated_dist, marker); for existing_dep in &mut self.dependencies { if existing_dep.package_id == new_dep.package_id @@ -790,7 +788,7 @@ impl Package { &mut self, extra: ExtraName, annotated_dist: &AnnotatedDist, - marker: Option<&MarkerTree>, + marker: MarkerTree, ) { self.optional_dependencies .entry(extra) @@ -803,7 +801,7 @@ impl Package { &mut self, dev: GroupName, annotated_dist: &AnnotatedDist, - marker: Option<&MarkerTree>, + marker: MarkerTree, ) { self.dev_dependencies .entry(dev) @@ -1072,15 +1070,11 @@ impl Package { for dep in deps { if let Some(mut dep) = dep.to_requirement(workspace_root, &mut dependency_extras)? { // Add back the extra marker expression. - let marker = MarkerTree::expression(MarkerExpression::Extra { - operator: ExtraOperator::Equal, - name: extra.clone(), - }); - - match dep.marker { - Some(ref mut tree) => tree.and(marker), - None => dep.marker = Some(marker), - } + dep.marker + .and(MarkerTree::expression(MarkerExpression::Extra { + operator: ExtraOperator::Equal, + name: extra.clone(), + })); requires_dist.push(dep); } @@ -2282,17 +2276,13 @@ impl TryFrom for Wheel { struct Dependency { package_id: PackageId, extra: BTreeSet, - marker: Option, + marker: MarkerTree, } impl Dependency { - fn from_annotated_dist( - annotated_dist: &AnnotatedDist, - marker: Option<&MarkerTree>, - ) -> Dependency { + fn from_annotated_dist(annotated_dist: &AnnotatedDist, marker: MarkerTree) -> Dependency { let package_id = PackageId::from_annotated_dist(annotated_dist); let extra = annotated_dist.extra.iter().cloned().collect(); - let marker = marker.cloned(); Dependency { package_id, extra, @@ -2389,7 +2379,7 @@ impl Dependency { .collect::(); table.insert("extra", value(extra_array)); } - if let Some(marker) = self.marker.as_ref().and_then(MarkerTree::contents) { + if let Some(marker) = self.marker.contents() { table.insert("marker", value(marker.to_string())); } @@ -2425,7 +2415,8 @@ struct DependencyWire { package_id: PackageIdForDependency, #[serde(default)] extra: BTreeSet, - marker: Option, + #[serde(default)] + marker: MarkerTree, } impl DependencyWire { @@ -2816,10 +2807,8 @@ impl<'env> TreeDisplay<'env> { // Skip dependencies that don't apply to the current environment. if let Some(environment_markers) = markers { - if let Some(dependency_markers) = dependency.marker.as_ref() { - if !dependency_markers.evaluate(environment_markers, &[]) { - continue; - } + if !dependency.marker.evaluate(environment_markers, &[]) { + continue; } } @@ -2847,10 +2836,8 @@ impl<'env> TreeDisplay<'env> { // Skip dependencies that don't apply to the current environment. if let Some(environment_markers) = markers { - if let Some(dependency_markers) = dependency.marker.as_ref() { - if !dependency_markers.evaluate(environment_markers, &[]) { - continue; - } + if !dependency.marker.evaluate(environment_markers, &[]) { + continue; } } @@ -2884,10 +2871,8 @@ impl<'env> TreeDisplay<'env> { // Skip dependencies that don't apply to the current environment. if let Some(environment_markers) = markers { - if let Some(dependency_markers) = dependency.marker.as_ref() { - if !dependency_markers.evaluate(environment_markers, &[]) { - continue; - } + if !dependency.marker.evaluate(environment_markers, &[]) { + continue; } } diff --git a/crates/uv-resolver/src/preferences.rs b/crates/uv-resolver/src/preferences.rs index 1b355803d87a..67f8f0a97a06 100644 --- a/crates/uv-resolver/src/preferences.rs +++ b/crates/uv-resolver/src/preferences.rs @@ -23,7 +23,7 @@ pub struct Preference { name: PackageName, version: Version, /// The markers on the requirement itself (those after the semicolon). - marker: Option, + marker: MarkerTree, /// If coming from a package with diverging versions, the markers of the forks this preference /// is part of, otherwise `None`. fork_markers: Option>, @@ -77,7 +77,7 @@ impl Preference { Self { name: dist.name().clone(), version: version.clone(), - marker: None, + marker: MarkerTree::TRUE, // Installed distributions don't have fork annotations. fork_markers: None, hashes: Vec::new(), @@ -89,7 +89,7 @@ impl Preference { Self { name: package.id.name.clone(), version: package.id.version.clone(), - marker: None, + marker: MarkerTree::TRUE, fork_markers: package.fork_markers().cloned(), hashes: Vec::new(), } @@ -128,11 +128,7 @@ impl Preferences { for preference in preferences { // Filter non-matching preferences when resolving for an environment. if let Some(markers) = markers { - if !preference - .marker - .as_ref() - .map_or(true, |marker| marker.evaluate(markers, &[])) - { + if !preference.marker.evaluate(markers, &[]) { trace!("Excluding {preference} from preferences due to unmatched markers"); continue; } diff --git a/crates/uv-resolver/src/pubgrub/package.rs b/crates/uv-resolver/src/pubgrub/package.rs index 994dd94864a1..5502948c264f 100644 --- a/crates/uv-resolver/src/pubgrub/package.rs +++ b/crates/uv-resolver/src/pubgrub/package.rs @@ -94,16 +94,14 @@ impl PubGrubPackage { pub(crate) fn from_package( name: PackageName, extra: Option, - marker: Option, + marker: MarkerTree, ) -> Self { // Remove all extra expressions from the marker, since we track extras // separately. This also avoids an issue where packages added via // extras end up having two distinct marker expressions, which in turn // makes them two distinct packages. This results in PubGrub being // unable to unify version constraints across such packages. - let marker = marker - .map(|m| m.simplify_extras_with(|_| true)) - .and_then(|marker| marker.contents()); + let marker = marker.simplify_extras_with(|_| true).contents(); if let Some(extra) = extra { Self(Arc::new(PubGrubPackageInner::Extra { name, diff --git a/crates/uv-resolver/src/resolution/graph.rs b/crates/uv-resolver/src/resolution/graph.rs index 7e2b215106de..77c18753df65 100644 --- a/crates/uv-resolver/src/resolution/graph.rs +++ b/crates/uv-resolver/src/resolution/graph.rs @@ -587,10 +587,7 @@ impl ResolutionGraph { .constraints .apply(self.overrides.apply(archive.metadata.requires_dist.iter())) { - let Some(ref marker_tree) = req.marker else { - continue; - }; - add_marker_params_from_tree(marker_tree, &mut seen_marker_values); + add_marker_params_from_tree(&req.marker, &mut seen_marker_values); } } @@ -599,10 +596,7 @@ impl ResolutionGraph { .constraints .apply(self.overrides.apply(self.requirements.iter())) { - let Some(ref marker_tree) = direct_req.marker else { - continue; - }; - add_marker_params_from_tree(marker_tree, &mut seen_marker_values); + add_marker_params_from_tree(&direct_req.marker, &mut seen_marker_values); } // Generate the final marker expression as a conjunction of diff --git a/crates/uv-resolver/src/resolver/fork_map.rs b/crates/uv-resolver/src/resolver/fork_map.rs index 236ce148e62c..907c36b9b4ad 100644 --- a/crates/uv-resolver/src/resolver/fork_map.rs +++ b/crates/uv-resolver/src/resolver/fork_map.rs @@ -15,7 +15,7 @@ pub(crate) struct ForkMap(FxHashMap>>); #[derive(Debug, Clone)] struct Entry { value: T, - marker: Option, + marker: MarkerTree, } impl Default for ForkMap { @@ -67,12 +67,7 @@ impl ForkMap { // with the current fork, i.e. the markers are not disjoint. ResolverMarkers::Fork(fork) => values .iter() - .filter(|entry| { - !entry - .marker - .as_ref() - .is_some_and(|marker| fork.is_disjoint(marker)) - }) + .filter(|entry| !fork.is_disjoint(&entry.marker)) .map(|entry| &entry.value) .collect(), diff --git a/crates/uv-resolver/src/resolver/mod.rs b/crates/uv-resolver/src/resolver/mod.rs index c6b060050d24..ea899bbb059b 100644 --- a/crates/uv-resolver/src/resolver/mod.rs +++ b/crates/uv-resolver/src/resolver/mod.rs @@ -1598,12 +1598,11 @@ impl ResolverState ResolverState bool { - let Some(marker) = requirement.marker.as_ref() else { - return true; - }; - !markers.is_disjoint(marker) + !markers.is_disjoint(&requirement.marker) } diff --git a/crates/uv-resolver/src/snapshots/uv_resolver__lock__tests__missing_dependency_source_unambiguous.snap b/crates/uv-resolver/src/snapshots/uv_resolver__lock__tests__missing_dependency_source_unambiguous.snap index c86022c9fa74..8c2ed72bb65a 100644 --- a/crates/uv-resolver/src/snapshots/uv_resolver__lock__tests__missing_dependency_source_unambiguous.snap +++ b/crates/uv-resolver/src/snapshots/uv_resolver__lock__tests__missing_dependency_source_unambiguous.snap @@ -99,7 +99,7 @@ Ok( ), }, extra: {}, - marker: None, + marker: true, }, ], optional_dependencies: {}, diff --git a/crates/uv-resolver/src/snapshots/uv_resolver__lock__tests__missing_dependency_source_version_unambiguous.snap b/crates/uv-resolver/src/snapshots/uv_resolver__lock__tests__missing_dependency_source_version_unambiguous.snap index c86022c9fa74..8c2ed72bb65a 100644 --- a/crates/uv-resolver/src/snapshots/uv_resolver__lock__tests__missing_dependency_source_version_unambiguous.snap +++ b/crates/uv-resolver/src/snapshots/uv_resolver__lock__tests__missing_dependency_source_version_unambiguous.snap @@ -99,7 +99,7 @@ Ok( ), }, extra: {}, - marker: None, + marker: true, }, ], optional_dependencies: {}, diff --git a/crates/uv-resolver/src/snapshots/uv_resolver__lock__tests__missing_dependency_version_unambiguous.snap b/crates/uv-resolver/src/snapshots/uv_resolver__lock__tests__missing_dependency_version_unambiguous.snap index c86022c9fa74..8c2ed72bb65a 100644 --- a/crates/uv-resolver/src/snapshots/uv_resolver__lock__tests__missing_dependency_version_unambiguous.snap +++ b/crates/uv-resolver/src/snapshots/uv_resolver__lock__tests__missing_dependency_version_unambiguous.snap @@ -99,7 +99,7 @@ Ok( ), }, extra: {}, - marker: None, + marker: true, }, ], optional_dependencies: {}, diff --git a/crates/uv-workspace/src/pyproject_mut.rs b/crates/uv-workspace/src/pyproject_mut.rs index b105c98c1adf..23ad59a8fe82 100644 --- a/crates/uv-workspace/src/pyproject_mut.rs +++ b/crates/uv-workspace/src/pyproject_mut.rs @@ -522,8 +522,8 @@ fn update_requirement(old: &mut Requirement, new: &Requirement, has_source: bool } // Update the marker expression. - if let Some(marker) = new.marker.clone() { - old.marker = Some(marker); + if new.marker.contents().is_some() { + old.marker = new.marker.clone(); } } diff --git a/crates/uv-workspace/src/workspace.rs b/crates/uv-workspace/src/workspace.rs index 6dad72e6e8c7..38b5de75cba3 100644 --- a/crates/uv-workspace/src/workspace.rs +++ b/crates/uv-workspace/src/workspace.rs @@ -8,7 +8,7 @@ use glob::{glob, GlobError, PatternError}; use rustc_hash::FxHashSet; use tracing::{debug, trace, warn}; -use pep508_rs::{RequirementOrigin, VerbatimUrl}; +use pep508_rs::{MarkerTree, RequirementOrigin, VerbatimUrl}; use pypi_types::{Requirement, RequirementSource}; use uv_fs::{absolutize_path, normalize_path, relative_to, Simplified}; use uv_normalize::{GroupName, PackageName, DEV_DEPENDENCIES}; @@ -282,7 +282,7 @@ impl Workspace { Some(Requirement { name: project.name.clone(), extras, - marker: None, + marker: MarkerTree::TRUE, source: RequirementSource::Directory { install_path: member.root.clone(), lock_path: member diff --git a/crates/uv/src/commands/pip/tree.rs b/crates/uv/src/commands/pip/tree.rs index b5d3014ddaed..2e2442e902e7 100644 --- a/crates/uv/src/commands/pip/tree.rs +++ b/crates/uv/src/commands/pip/tree.rs @@ -139,12 +139,11 @@ impl DisplayDependencyGraph { // Add all transitive requirements. for metadata in packages.values().flatten() { // Ignore any optional dependencies. - for required in metadata.requires_dist.iter().filter(|requirement| { - requirement - .marker - .as_ref() - .map_or(true, |m| m.evaluate(markers, &[])) - }) { + for required in metadata + .requires_dist + .iter() + .filter(|requirement| requirement.marker.evaluate(markers, &[])) + { let dependency = if invert { Dependency::Inverted( required.name.clone(),