Remove uses of `Option<MarkerTree>` (#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.
This commit is contained in:
Ibraheem Ahmed 2024-08-10 13:23:29 -04:00 committed by GitHub
parent 4eced1bd0c
commit f5110f7b5e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
45 changed files with 228 additions and 330 deletions

View File

@ -1,4 +1,5 @@
use distribution_filename::DistExtension; use distribution_filename::DistExtension;
use pep508_rs::MarkerTree;
use pypi_types::{HashDigest, Requirement, RequirementSource}; use pypi_types::{HashDigest, Requirement, RequirementSource};
use std::collections::BTreeMap; use std::collections::BTreeMap;
use uv_normalize::{ExtraName, GroupName, PackageName}; use uv_normalize::{ExtraName, GroupName, PackageName};
@ -211,7 +212,7 @@ impl From<&ResolvedDist> for Requirement {
Requirement { Requirement {
name: resolved_dist.name().clone(), name: resolved_dist.name().clone(),
extras: vec![], extras: vec![],
marker: None, marker: MarkerTree::TRUE,
source, source,
origin: None, origin: None,
} }

View File

@ -56,7 +56,7 @@ pub use verbatim_url::{
}; };
mod cursor; mod cursor;
mod marker; pub mod marker;
mod origin; mod origin;
#[cfg(feature = "non-pep508-extensions")] #[cfg(feature = "non-pep508-extensions")]
mod unnamed; mod unnamed;
@ -149,7 +149,7 @@ pub struct Requirement<T: Pep508Url = VerbatimUrl> {
/// The markers such as `python_version > "3.8"` in /// The markers such as `python_version > "3.8"` in
/// `requests [security,tests] >= 2.8.1, == 2.8.* ; python_version > "3.8"`. /// `requests [security,tests] >= 2.8.1, == 2.8.* ; python_version > "3.8"`.
/// Those are a nested and/or tree. /// Those are a nested and/or tree.
pub marker: Option<MarkerTree>, pub marker: MarkerTree,
/// The source file containing the requirement. /// The source file containing the requirement.
pub origin: Option<RequirementOrigin>, pub origin: Option<RequirementOrigin>,
} }
@ -190,7 +190,7 @@ impl<T: Pep508Url + Display> Display for Requirement<T> {
} }
} }
} }
if let Some(marker) = self.marker.as_ref().and_then(MarkerTree::contents) { if let Some(marker) = self.marker.contents() {
write!(f, " ; {marker}")?; write!(f, " ; {marker}")?;
} }
Ok(()) Ok(())
@ -256,10 +256,7 @@ impl PyRequirement {
/// `requests [security,tests] >= 2.8.1, == 2.8.* ; python_version > "3.8"` /// `requests [security,tests] >= 2.8.1, == 2.8.* ; python_version > "3.8"`
#[getter] #[getter]
pub fn marker(&self) -> Option<String> { pub fn marker(&self) -> Option<String> {
self.marker self.marker.try_to_string()
.as_ref()
.and_then(MarkerTree::contents)
.map(|marker| marker.to_string())
} }
/// Parses a PEP 440 string /// Parses a PEP 440 string
@ -375,11 +372,7 @@ impl PyRequirement {
impl<T: Pep508Url> Requirement<T> { impl<T: Pep508Url> Requirement<T> {
/// Returns whether the markers apply for the given environment /// Returns whether the markers apply for the given environment
pub fn evaluate_markers(&self, env: &MarkerEnvironment, extras: &[ExtraName]) -> bool { pub fn evaluate_markers(&self, env: &MarkerEnvironment, extras: &[ExtraName]) -> bool {
if let Some(marker) = &self.marker { self.marker.evaluate(env, extras)
marker.evaluate(env, extras)
} else {
true
}
} }
/// Returns whether the requirement would be satisfied, independent of environment markers, i.e. /// Returns whether the requirement would be satisfied, independent of environment markers, i.e.
@ -393,11 +386,8 @@ impl<T: Pep508Url> Requirement<T> {
extras: &HashSet<ExtraName>, extras: &HashSet<ExtraName>,
python_versions: &[Version], python_versions: &[Version],
) -> bool { ) -> bool {
if let Some(marker) = &self.marker { self.marker
marker.evaluate_extras_and_python_version(extras, python_versions) .evaluate_extras_and_python_version(extras, python_versions)
} else {
true
}
} }
/// Returns whether the markers apply for the given environment. /// Returns whether the markers apply for the given environment.
@ -406,11 +396,7 @@ impl<T: Pep508Url> Requirement<T> {
env: &MarkerEnvironment, env: &MarkerEnvironment,
extras: &[ExtraName], extras: &[ExtraName],
) -> (bool, Vec<MarkerWarning>) { ) -> (bool, Vec<MarkerWarning>) {
if let Some(marker) = &self.marker { self.marker.evaluate_collect_warnings(env, extras)
marker.evaluate_collect_warnings(env, extras)
} else {
(true, Vec::new())
}
} }
/// Return the requirement with an additional marker added, to require the given extra. /// Return the requirement with an additional marker added, to require the given extra.
@ -418,26 +404,14 @@ impl<T: Pep508Url> Requirement<T> {
/// For example, given `flask >= 2.0.2`, calling `with_extra_marker("dotenv")` would return /// For example, given `flask >= 2.0.2`, calling `with_extra_marker("dotenv")` would return
/// `flask >= 2.0.2 ; extra == "dotenv"`. /// `flask >= 2.0.2 ; extra == "dotenv"`.
#[must_use] #[must_use]
pub fn with_extra_marker(self, extra: &ExtraName) -> Self { pub fn with_extra_marker(mut self, extra: &ExtraName) -> Self {
let marker = match self.marker { self.marker
Some(mut marker) => { .and(MarkerTree::expression(MarkerExpression::Extra {
let extra = MarkerTree::expression(MarkerExpression::Extra {
operator: ExtraOperator::Equal, operator: ExtraOperator::Equal,
name: extra.clone(), name: extra.clone(),
}); }));
marker.and(extra);
marker
}
None => MarkerTree::expression(MarkerExpression::Extra {
operator: ExtraOperator::Equal,
name: extra.clone(),
}),
};
Self { self
marker: Some(marker),
..self
}
} }
/// Set the source file containing the requirement. /// Set the source file containing the requirement.
@ -1053,6 +1027,7 @@ fn parse_pep508_requirement<T: Pep508Url>(
} else { } else {
None None
}; };
// wsp* // wsp*
cursor.eat_whitespace(); cursor.eat_whitespace();
if let Some((pos, char)) = cursor.next() { if let Some((pos, char)) = cursor.next() {
@ -1085,7 +1060,7 @@ fn parse_pep508_requirement<T: Pep508Url>(
name, name,
extras, extras,
version_or_url: requirement_kind, version_or_url: requirement_kind,
marker, marker: marker.unwrap_or_default(),
origin: None, origin: None,
}) })
} }
@ -1222,14 +1197,14 @@ mod tests {
.into_iter() .into_iter()
.collect(), .collect(),
)), )),
marker: Some(MarkerTree::expression(MarkerExpression::Version { marker: MarkerTree::expression(MarkerExpression::Version {
key: MarkerValueVersion::PythonVersion, key: MarkerValueVersion::PythonVersion,
specifier: VersionSpecifier::from_pattern( specifier: VersionSpecifier::from_pattern(
pep440_rs::Operator::LessThan, pep440_rs::Operator::LessThan,
"2.7".parse().unwrap(), "2.7".parse().unwrap(),
) )
.unwrap(), .unwrap(),
})), }),
origin: None, origin: None,
}; };
assert_eq!(requests, expected); assert_eq!(requests, expected);
@ -1455,7 +1430,7 @@ mod tests {
let expected = Requirement { let expected = Requirement {
name: PackageName::from_str("pip").unwrap(), name: PackageName::from_str("pip").unwrap(),
extras: vec![], extras: vec![],
marker: None, marker: MarkerTree::TRUE,
version_or_url: Some(VersionOrUrl::Url(Url::parse(url).unwrap())), version_or_url: Some(VersionOrUrl::Url(Url::parse(url).unwrap())),
origin: None, origin: None,
}; };

View File

@ -21,3 +21,24 @@ pub use tree::{
MarkerOperator, MarkerTree, MarkerTreeContents, MarkerTreeKind, MarkerValue, MarkerValueString, MarkerOperator, MarkerTree, MarkerTreeContents, MarkerTreeKind, MarkerValue, MarkerValueString,
MarkerValueVersion, MarkerWarningKind, StringMarkerTree, StringVersion, VersionMarkerTree, 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<S>(marker: &MarkerTree, s: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
marker.contents().unwrap().serialize(s)
}
}

View File

@ -564,6 +564,12 @@ impl Display for MarkerExpression {
#[derive(Clone, Eq, Hash, PartialEq, PartialOrd, Ord)] #[derive(Clone, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct MarkerTree(NodeId); pub struct MarkerTree(NodeId);
impl Default for MarkerTree {
fn default() -> Self {
MarkerTree::TRUE
}
}
impl<'de> Deserialize<'de> for MarkerTree { impl<'de> Deserialize<'de> for MarkerTree {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where

View File

@ -75,7 +75,7 @@ pub struct UnnamedRequirement<Url: UnnamedRequirementUrl = VerbatimUrl> {
/// The markers such as `python_version > "3.8"` in /// The markers such as `python_version > "3.8"` in
/// `requests [security,tests] >= 2.8.1, == 2.8.* ; python_version > "3.8"`. /// `requests [security,tests] >= 2.8.1, == 2.8.* ; python_version > "3.8"`.
/// Those are a nested and/or tree. /// Those are a nested and/or tree.
pub marker: Option<MarkerTree>, pub marker: MarkerTree,
/// The source file containing the requirement. /// The source file containing the requirement.
pub origin: Option<RequirementOrigin>, pub origin: Option<RequirementOrigin>,
} }
@ -92,11 +92,7 @@ impl<Url: UnnamedRequirementUrl> UnnamedRequirement<Url> {
env: Option<&MarkerEnvironment>, env: Option<&MarkerEnvironment>,
extras: &[ExtraName], extras: &[ExtraName],
) -> bool { ) -> bool {
if let Some(marker) = &self.marker { self.marker.evaluate_optional_environment(env, extras)
marker.evaluate_optional_environment(env, extras)
} else {
true
}
} }
/// Set the source file containing the requirement. /// Set the source file containing the requirement.
@ -136,7 +132,7 @@ impl<Url: UnnamedRequirementUrl> Display for UnnamedRequirement<Url> {
.join(",") .join(",")
)?; )?;
} }
if let Some(marker) = self.marker.as_ref().and_then(MarkerTree::contents) { if let Some(marker) = self.marker.contents() {
write!(f, " ; {marker}")?; write!(f, " ; {marker}")?;
} }
Ok(()) Ok(())
@ -207,7 +203,7 @@ fn parse_unnamed_requirement<Url: UnnamedRequirementUrl>(
Ok(UnnamedRequirement { Ok(UnnamedRequirement {
url, url,
extras, extras,
marker, marker: marker.unwrap_or_default(),
origin: None, origin: None,
}) })
} }

View File

@ -3,12 +3,13 @@ use std::path::{Path, PathBuf};
use std::str::FromStr; use std::str::FromStr;
use distribution_filename::DistExtension; use distribution_filename::DistExtension;
use serde::Serialize;
use thiserror::Error; use thiserror::Error;
use url::Url; use url::Url;
use pep440_rs::VersionSpecifiers; 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_fs::PortablePathBuf;
use uv_git::{GitReference, GitSha, GitUrl}; use uv_git::{GitReference, GitSha, GitUrl};
use uv_normalize::{ExtraName, PackageName}; use uv_normalize::{ExtraName, PackageName};
@ -40,28 +41,17 @@ pub struct Requirement {
#[serde(skip_serializing_if = "Vec::is_empty", default)] #[serde(skip_serializing_if = "Vec::is_empty", default)]
pub extras: Vec<ExtraName>, pub extras: Vec<ExtraName>,
#[serde( #[serde(
skip_serializing_if = "marker_is_empty", skip_serializing_if = "marker::ser::is_empty",
serialize_with = "serialize_marker", serialize_with = "marker::ser::serialize",
default default
)] )]
pub marker: Option<MarkerTree>, pub marker: MarkerTree,
#[serde(flatten)] #[serde(flatten)]
pub source: RequirementSource, pub source: RequirementSource,
#[serde(skip)] #[serde(skip)]
pub origin: Option<RequirementOrigin>, pub origin: Option<RequirementOrigin>,
} }
fn marker_is_empty(marker: &Option<MarkerTree>) -> bool {
marker.as_ref().and_then(MarkerTree::contents).is_none()
}
fn serialize_marker<S>(marker: &Option<MarkerTree>, s: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
marker.as_ref().unwrap().contents().unwrap().serialize(s)
}
impl Requirement { impl Requirement {
/// Returns whether the markers apply for the given environment. /// 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 /// expressions based on the environment to `true`. That is, this provides
/// environment independent marker evaluation. /// environment independent marker evaluation.
pub fn evaluate_markers(&self, env: Option<&MarkerEnvironment>, extras: &[ExtraName]) -> bool { pub fn evaluate_markers(&self, env: Option<&MarkerEnvironment>, extras: &[ExtraName]) -> bool {
if let Some(marker) = &self.marker { self.marker.evaluate_optional_environment(env, extras)
marker.evaluate_optional_environment(env, extras)
} else {
true
}
} }
/// Returns `true` if the requirement is editable. /// Returns `true` if the requirement is editable.
@ -256,7 +242,7 @@ impl Display for Requirement {
write!(f, " @ {url}")?; 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}")?; write!(f, " ; {marker}")?;
} }
Ok(()) Ok(())
@ -715,7 +701,7 @@ impl TryFrom<RequirementSourceWire> for RequirementSource {
mod tests { mod tests {
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use pep508_rs::VerbatimUrl; use pep508_rs::{MarkerTree, VerbatimUrl};
use crate::{Requirement, RequirementSource}; use crate::{Requirement, RequirementSource};
@ -724,7 +710,7 @@ mod tests {
let requirement = Requirement { let requirement = Requirement {
name: "foo".parse().unwrap(), name: "foo".parse().unwrap(),
extras: vec![], extras: vec![],
marker: None, marker: MarkerTree::TRUE,
source: RequirementSource::Registry { source: RequirementSource::Registry {
specifier: ">1,<2".parse().unwrap(), specifier: ">1,<2".parse().unwrap(),
index: None, index: None,
@ -744,7 +730,7 @@ mod tests {
let requirement = Requirement { let requirement = Requirement {
name: "foo".parse().unwrap(), name: "foo".parse().unwrap(),
extras: vec![], extras: vec![],
marker: None, marker: MarkerTree::TRUE,
source: RequirementSource::Directory { source: RequirementSource::Directory {
install_path: PathBuf::from(path), install_path: PathBuf::from(path),
lock_path: PathBuf::from(path), lock_path: PathBuf::from(path),

View File

@ -1691,7 +1691,7 @@ mod test {
), ),
extras: [], extras: [],
version_or_url: None, version_or_url: None,
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/subdir/sibling.txt", "<REQUIREMENTS_DIR>/subdir/sibling.txt",
@ -1755,7 +1755,7 @@ mod test {
), ),
extras: [], extras: [],
version_or_url: None, version_or_url: None,
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/requirements.txt", "<REQUIREMENTS_DIR>/requirements.txt",
@ -1864,7 +1864,7 @@ mod test {
}, },
}, },
extras: [], extras: [],
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/grandchild.txt", "<REQUIREMENTS_DIR>/grandchild.txt",
@ -1978,7 +1978,7 @@ mod test {
), ),
extras: [], extras: [],
version_or_url: None, version_or_url: None,
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/./sibling.txt", "<REQUIREMENTS_DIR>/./sibling.txt",
@ -2007,7 +2007,7 @@ mod test {
), ),
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/requirements.txt", "<REQUIREMENTS_DIR>/requirements.txt",
@ -2038,7 +2038,7 @@ mod test {
), ),
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/requirements.txt", "<REQUIREMENTS_DIR>/requirements.txt",
@ -2069,7 +2069,7 @@ mod test {
), ),
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/requirements.txt", "<REQUIREMENTS_DIR>/requirements.txt",
@ -2098,7 +2098,7 @@ mod test {
), ),
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/requirements.txt", "<REQUIREMENTS_DIR>/requirements.txt",

View File

@ -23,7 +23,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/basic.txt", "<REQUIREMENTS_DIR>/basic.txt",
@ -52,7 +52,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/basic.txt", "<REQUIREMENTS_DIR>/basic.txt",
@ -81,7 +81,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/basic.txt", "<REQUIREMENTS_DIR>/basic.txt",
@ -110,7 +110,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/basic.txt", "<REQUIREMENTS_DIR>/basic.txt",
@ -139,7 +139,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/basic.txt", "<REQUIREMENTS_DIR>/basic.txt",
@ -168,7 +168,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/basic.txt", "<REQUIREMENTS_DIR>/basic.txt",

View File

@ -23,7 +23,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/constraints-a.txt", "<REQUIREMENTS_DIR>/constraints-a.txt",
@ -52,7 +52,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/constraints-b.txt", "<REQUIREMENTS_DIR>/constraints-b.txt",
@ -76,7 +76,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/constraints-b.txt", "<REQUIREMENTS_DIR>/constraints-b.txt",

View File

@ -23,7 +23,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/constraints-b.txt", "<REQUIREMENTS_DIR>/constraints-b.txt",
@ -52,7 +52,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/constraints-b.txt", "<REQUIREMENTS_DIR>/constraints-b.txt",

View File

@ -23,7 +23,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/for-poetry.txt", "<REQUIREMENTS_DIR>/for-poetry.txt",
@ -52,7 +52,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/for-poetry.txt", "<REQUIREMENTS_DIR>/for-poetry.txt",
@ -70,7 +70,7 @@ RequirementsTxt {
), ),
extras: [], extras: [],
version_or_url: None, version_or_url: None,
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/for-poetry.txt", "<REQUIREMENTS_DIR>/for-poetry.txt",
@ -107,7 +107,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/for-poetry.txt", "<REQUIREMENTS_DIR>/for-poetry.txt",

View File

@ -12,7 +12,7 @@ RequirementsTxt {
), ),
extras: [], extras: [],
version_or_url: None, version_or_url: None,
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/include-b.txt", "<REQUIREMENTS_DIR>/include-b.txt",
@ -41,7 +41,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/include-a.txt", "<REQUIREMENTS_DIR>/include-a.txt",

View File

@ -12,7 +12,7 @@ RequirementsTxt {
), ),
extras: [], extras: [],
version_or_url: None, version_or_url: None,
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/include-b.txt", "<REQUIREMENTS_DIR>/include-b.txt",

View File

@ -23,9 +23,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: Some( marker: python_version >= '3.8' and python_version < '4.0',
python_version >= '3.8' and python_version < '4.0',
),
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/poetry-with-hashes.txt", "<REQUIREMENTS_DIR>/poetry-with-hashes.txt",
@ -56,9 +54,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: Some( marker: python_version >= '3.8' and python_version < '4.0',
python_version >= '3.8' and python_version < '4.0',
),
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/poetry-with-hashes.txt", "<REQUIREMENTS_DIR>/poetry-with-hashes.txt",
@ -89,9 +85,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: Some( marker: python_version >= '3.8' and python_version < '4.0' and platform_system == 'Windows',
python_version >= '3.8' and python_version < '4.0' and platform_system == 'Windows',
),
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/poetry-with-hashes.txt", "<REQUIREMENTS_DIR>/poetry-with-hashes.txt",
@ -122,9 +116,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: Some( marker: python_version >= '3.8' and python_version < '4.0',
python_version >= '3.8' and python_version < '4.0',
),
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/poetry-with-hashes.txt", "<REQUIREMENTS_DIR>/poetry-with-hashes.txt",
@ -156,9 +148,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: Some( marker: python_version >= '3.8' and python_version < '4.0',
python_version >= '3.8' and python_version < '4.0',
),
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/poetry-with-hashes.txt", "<REQUIREMENTS_DIR>/poetry-with-hashes.txt",

View File

@ -23,7 +23,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/small.txt", "<REQUIREMENTS_DIR>/small.txt",
@ -52,7 +52,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/small.txt", "<REQUIREMENTS_DIR>/small.txt",

View File

@ -12,7 +12,7 @@ RequirementsTxt {
), ),
extras: [], extras: [],
version_or_url: None, version_or_url: None,
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/whitespace.txt", "<REQUIREMENTS_DIR>/whitespace.txt",
@ -83,7 +83,7 @@ RequirementsTxt {
}, },
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/whitespace.txt", "<REQUIREMENTS_DIR>/whitespace.txt",

View File

@ -23,7 +23,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/basic.txt", "<REQUIREMENTS_DIR>/basic.txt",
@ -52,7 +52,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/basic.txt", "<REQUIREMENTS_DIR>/basic.txt",
@ -81,7 +81,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/basic.txt", "<REQUIREMENTS_DIR>/basic.txt",
@ -110,7 +110,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/basic.txt", "<REQUIREMENTS_DIR>/basic.txt",
@ -139,7 +139,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/basic.txt", "<REQUIREMENTS_DIR>/basic.txt",
@ -168,7 +168,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/basic.txt", "<REQUIREMENTS_DIR>/basic.txt",

View File

@ -23,7 +23,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/constraints-a.txt", "<REQUIREMENTS_DIR>/constraints-a.txt",
@ -52,7 +52,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/constraints-b.txt", "<REQUIREMENTS_DIR>/constraints-b.txt",
@ -76,7 +76,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/constraints-b.txt", "<REQUIREMENTS_DIR>/constraints-b.txt",

View File

@ -23,7 +23,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/constraints-b.txt", "<REQUIREMENTS_DIR>/constraints-b.txt",
@ -52,7 +52,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/constraints-b.txt", "<REQUIREMENTS_DIR>/constraints-b.txt",

View File

@ -23,7 +23,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/for-poetry.txt", "<REQUIREMENTS_DIR>/for-poetry.txt",
@ -52,7 +52,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/for-poetry.txt", "<REQUIREMENTS_DIR>/for-poetry.txt",
@ -70,7 +70,7 @@ RequirementsTxt {
), ),
extras: [], extras: [],
version_or_url: None, version_or_url: None,
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/for-poetry.txt", "<REQUIREMENTS_DIR>/for-poetry.txt",
@ -107,7 +107,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/for-poetry.txt", "<REQUIREMENTS_DIR>/for-poetry.txt",

View File

@ -12,7 +12,7 @@ RequirementsTxt {
), ),
extras: [], extras: [],
version_or_url: None, version_or_url: None,
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/include-b.txt", "<REQUIREMENTS_DIR>/include-b.txt",
@ -41,7 +41,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/include-a.txt", "<REQUIREMENTS_DIR>/include-a.txt",

View File

@ -12,7 +12,7 @@ RequirementsTxt {
), ),
extras: [], extras: [],
version_or_url: None, version_or_url: None,
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/include-b.txt", "<REQUIREMENTS_DIR>/include-b.txt",

View File

@ -23,9 +23,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: Some( marker: python_version >= '3.8' and python_version < '4.0',
python_version >= '3.8' and python_version < '4.0',
),
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/poetry-with-hashes.txt", "<REQUIREMENTS_DIR>/poetry-with-hashes.txt",
@ -56,9 +54,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: Some( marker: python_version >= '3.8' and python_version < '4.0',
python_version >= '3.8' and python_version < '4.0',
),
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/poetry-with-hashes.txt", "<REQUIREMENTS_DIR>/poetry-with-hashes.txt",
@ -89,9 +85,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: Some( marker: python_version >= '3.8' and python_version < '4.0' and platform_system == 'Windows',
python_version >= '3.8' and python_version < '4.0' and platform_system == 'Windows',
),
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/poetry-with-hashes.txt", "<REQUIREMENTS_DIR>/poetry-with-hashes.txt",
@ -122,9 +116,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: Some( marker: python_version >= '3.8' and python_version < '4.0',
python_version >= '3.8' and python_version < '4.0',
),
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/poetry-with-hashes.txt", "<REQUIREMENTS_DIR>/poetry-with-hashes.txt",
@ -156,9 +148,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: Some( marker: python_version >= '3.8' and python_version < '4.0',
python_version >= '3.8' and python_version < '4.0',
),
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/poetry-with-hashes.txt", "<REQUIREMENTS_DIR>/poetry-with-hashes.txt",

View File

@ -23,7 +23,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/small.txt", "<REQUIREMENTS_DIR>/small.txt",
@ -52,7 +52,7 @@ RequirementsTxt {
), ),
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/small.txt", "<REQUIREMENTS_DIR>/small.txt",

View File

@ -44,7 +44,7 @@ RequirementsTxt {
}, },
}, },
extras: [], extras: [],
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/bare-url.txt", "<REQUIREMENTS_DIR>/bare-url.txt",
@ -98,7 +98,7 @@ RequirementsTxt {
"dev", "dev",
), ),
], ],
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/bare-url.txt", "<REQUIREMENTS_DIR>/bare-url.txt",
@ -148,7 +148,7 @@ RequirementsTxt {
}, },
}, },
extras: [], extras: [],
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/bare-url.txt", "<REQUIREMENTS_DIR>/bare-url.txt",

View File

@ -53,7 +53,7 @@ RequirementsTxt {
"dev", "dev",
), ),
], ],
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/editable.txt", "<REQUIREMENTS_DIR>/editable.txt",
@ -110,7 +110,7 @@ RequirementsTxt {
"dev", "dev",
), ),
], ],
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/editable.txt", "<REQUIREMENTS_DIR>/editable.txt",
@ -167,9 +167,7 @@ RequirementsTxt {
"dev", "dev",
), ),
], ],
marker: Some( marker: python_version >= '3.9' and os_name == 'posix',
python_version >= '3.9' and os_name == 'posix',
),
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/editable.txt", "<REQUIREMENTS_DIR>/editable.txt",
@ -226,9 +224,7 @@ RequirementsTxt {
"dev", "dev",
), ),
], ],
marker: Some( marker: python_version >= '3.9' and os_name == 'posix',
python_version >= '3.9' and os_name == 'posix',
),
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/editable.txt", "<REQUIREMENTS_DIR>/editable.txt",
@ -278,9 +274,7 @@ RequirementsTxt {
}, },
}, },
extras: [], extras: [],
marker: Some( marker: python_version >= '3.9' and os_name == 'posix',
python_version >= '3.9' and os_name == 'posix',
),
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/editable.txt", "<REQUIREMENTS_DIR>/editable.txt",
@ -330,7 +324,7 @@ RequirementsTxt {
}, },
}, },
extras: [], extras: [],
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/editable.txt", "<REQUIREMENTS_DIR>/editable.txt",

View File

@ -12,7 +12,7 @@ RequirementsTxt {
), ),
extras: [], extras: [],
version_or_url: None, version_or_url: None,
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/whitespace.txt", "<REQUIREMENTS_DIR>/whitespace.txt",
@ -83,7 +83,7 @@ RequirementsTxt {
}, },
), ),
), ),
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/whitespace.txt", "<REQUIREMENTS_DIR>/whitespace.txt",

View File

@ -44,7 +44,7 @@ RequirementsTxt {
}, },
}, },
extras: [], extras: [],
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/bare-url.txt", "<REQUIREMENTS_DIR>/bare-url.txt",
@ -98,7 +98,7 @@ RequirementsTxt {
"dev", "dev",
), ),
], ],
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/bare-url.txt", "<REQUIREMENTS_DIR>/bare-url.txt",
@ -148,7 +148,7 @@ RequirementsTxt {
}, },
}, },
extras: [], extras: [],
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/bare-url.txt", "<REQUIREMENTS_DIR>/bare-url.txt",

View File

@ -53,7 +53,7 @@ RequirementsTxt {
"dev", "dev",
), ),
], ],
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/editable.txt", "<REQUIREMENTS_DIR>/editable.txt",
@ -110,7 +110,7 @@ RequirementsTxt {
"dev", "dev",
), ),
], ],
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/editable.txt", "<REQUIREMENTS_DIR>/editable.txt",
@ -167,9 +167,7 @@ RequirementsTxt {
"dev", "dev",
), ),
], ],
marker: Some( marker: python_version >= '3.9' and os_name == 'posix',
python_version >= '3.9' and os_name == 'posix',
),
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/editable.txt", "<REQUIREMENTS_DIR>/editable.txt",
@ -226,9 +224,7 @@ RequirementsTxt {
"dev", "dev",
), ),
], ],
marker: Some( marker: python_version >= '3.9' and os_name == 'posix',
python_version >= '3.9' and os_name == 'posix',
),
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/editable.txt", "<REQUIREMENTS_DIR>/editable.txt",
@ -278,9 +274,7 @@ RequirementsTxt {
}, },
}, },
extras: [], extras: [],
marker: Some( marker: python_version >= '3.9' and os_name == 'posix',
python_version >= '3.9' and os_name == 'posix',
),
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/editable.txt", "<REQUIREMENTS_DIR>/editable.txt",
@ -330,7 +324,7 @@ RequirementsTxt {
}, },
}, },
extras: [], extras: [],
marker: None, marker: true,
origin: Some( origin: Some(
File( File(
"<REQUIREMENTS_DIR>/editable.txt", "<REQUIREMENTS_DIR>/editable.txt",

View File

@ -60,11 +60,7 @@ impl Constraints {
// ASSUMPTION: There is one `extra = "..."`, and it's either the only marker or part // ASSUMPTION: There is one `extra = "..."`, and it's either the only marker or part
// of the main conjunction. // of the main conjunction.
let Some(extra_expression) = requirement let Some(extra_expression) = requirement.marker.top_level_extra() else {
.marker
.as_ref()
.and_then(MarkerTree::top_level_extra)
else {
// Case 2: A non-optional dependency with constraint(s). // Case 2: A non-optional dependency with constraint(s).
return Either::Right(Either::Right( return Either::Right(Either::Right(
std::iter::once(requirement).chain(constraints.iter().map(Cow::Borrowed)), std::iter::once(requirement).chain(constraints.iter().map(Cow::Borrowed)),
@ -79,11 +75,9 @@ impl Constraints {
constraints.iter().cloned().map(move |constraint| { constraints.iter().cloned().map(move |constraint| {
// Add the extra to the override marker. // Add the extra to the override marker.
let mut joint_marker = MarkerTree::expression(extra_expression.clone()); let mut joint_marker = MarkerTree::expression(extra_expression.clone());
if let Some(marker) = &constraint.marker { joint_marker.and(constraint.marker.clone());
joint_marker.and(marker.clone());
}
Cow::Owned(Requirement { Cow::Owned(Requirement {
marker: Some(joint_marker.clone()), marker: joint_marker,
..constraint ..constraint
}) })
}), }),

View File

@ -50,11 +50,7 @@ impl Overrides {
// ASSUMPTION: There is one `extra = "..."`, and it's either the only marker or part // ASSUMPTION: There is one `extra = "..."`, and it's either the only marker or part
// of the main conjunction. // of the main conjunction.
let Some(extra_expression) = requirement let Some(extra_expression) = requirement.marker.top_level_extra() else {
.marker
.as_ref()
.and_then(MarkerTree::top_level_extra)
else {
// Case 2: A non-optional dependency with override(s). // Case 2: A non-optional dependency with override(s).
return Either::Right(Either::Right(overrides.iter().map(Cow::Borrowed))); return Either::Right(Either::Right(overrides.iter().map(Cow::Borrowed)));
}; };
@ -67,11 +63,9 @@ impl Overrides {
move |override_requirement| { move |override_requirement| {
// Add the extra to the override marker. // Add the extra to the override marker.
let mut joint_marker = MarkerTree::expression(extra_expression.clone()); let mut joint_marker = MarkerTree::expression(extra_expression.clone());
if let Some(marker) = &override_requirement.marker { joint_marker.and(override_requirement.marker.clone());
joint_marker.and(marker.clone());
}
Cow::Owned(Requirement { Cow::Owned(Requirement {
marker: Some(joint_marker.clone()), marker: joint_marker,
..override_requirement.clone() ..override_requirement.clone()
}) })
}, },

View File

@ -104,10 +104,7 @@ impl<'a, Context: BuildContext> SourceTreeResolver<'a, Context> {
.into_iter() .into_iter()
.map(|requirement| Requirement { .map(|requirement| Requirement {
origin: Some(origin.clone()), origin: Some(origin.clone()),
marker: requirement marker: requirement.marker.simplify_extras(extras),
.marker
.map(|marker| marker.simplify_extras(extras))
.filter(|marker| !marker.is_true()),
..requirement ..requirement
}) })
.collect(); .collect();
@ -117,7 +114,7 @@ impl<'a, Context: BuildContext> SourceTreeResolver<'a, Context> {
// Find the first recursive requirement. // Find the first recursive requirement.
// TODO(charlie): Respect markers on recursive extras. // TODO(charlie): Respect markers on recursive extras.
let Some(index) = requirements.iter().position(|requirement| { let Some(index) = requirements.iter().position(|requirement| {
requirement.name == metadata.name && requirement.marker.is_none() requirement.name == metadata.name && requirement.marker.is_true()
}) else { }) else {
break; break;
}; };
@ -129,9 +126,8 @@ impl<'a, Context: BuildContext> SourceTreeResolver<'a, Context> {
for requirement in &mut requirements { for requirement in &mut requirements {
requirement.marker = requirement requirement.marker = requirement
.marker .marker
.take() .clone()
.map(|marker| marker.simplify_extras(&recursive.extras)) .simplify_extras(&recursive.extras);
.filter(|marker| !marker.is_true());
} }
} }

View File

@ -37,7 +37,7 @@ use cache_key::CanonicalUrl;
use distribution_types::{ use distribution_types::{
FlatIndexLocation, IndexUrl, UnresolvedRequirement, UnresolvedRequirementSpecification, FlatIndexLocation, IndexUrl, UnresolvedRequirement, UnresolvedRequirementSpecification,
}; };
use pep508_rs::{UnnamedRequirement, UnnamedRequirementUrl}; use pep508_rs::{MarkerTree, UnnamedRequirement, UnnamedRequirementUrl};
use pypi_types::Requirement; use pypi_types::Requirement;
use pypi_types::VerbatimParsedUrl; use pypi_types::VerbatimParsedUrl;
use requirements_txt::{RequirementsTxt, RequirementsTxtRequirement}; use requirements_txt::{RequirementsTxt, RequirementsTxtRequirement};
@ -193,7 +193,7 @@ impl RequirementsSpecification {
requirement: UnresolvedRequirement::Unnamed(UnnamedRequirement { requirement: UnresolvedRequirement::Unnamed(UnnamedRequirement {
url: VerbatimParsedUrl::parse_absolute_path(path)?, url: VerbatimParsedUrl::parse_absolute_path(path)?,
extras: vec![], extras: vec![],
marker: None, marker: MarkerTree::TRUE,
origin: None, origin: None,
}), }),
hashes: vec![], hashes: vec![],

View File

@ -94,33 +94,27 @@ impl Lock {
for package in &mut lock.packages { for package in &mut lock.packages {
for dep in &mut package.dependencies { for dep in &mut package.dependencies {
if let Some(marker) = &mut dep.marker { dep.marker = dep.marker.clone().simplify_python_versions(
*marker = marker.clone().simplify_python_versions(
python_version.clone(), python_version.clone(),
python_full_version.clone(), python_full_version.clone(),
); );
} }
}
for dep in package.optional_dependencies.values_mut().flatten() { for dep in package.optional_dependencies.values_mut().flatten() {
if let Some(marker) = &mut dep.marker { dep.marker = dep.marker.clone().simplify_python_versions(
*marker = marker.clone().simplify_python_versions(
python_version.clone(), python_version.clone(),
python_full_version.clone(), python_full_version.clone(),
); );
} }
}
for dep in package.dev_dependencies.values_mut().flatten() { for dep in package.dev_dependencies.values_mut().flatten() {
if let Some(marker) = &mut dep.marker { dep.marker = dep.marker.clone().simplify_python_versions(
*marker = marker.clone().simplify_python_versions(
python_version.clone(), python_version.clone(),
python_full_version.clone(), python_full_version.clone(),
); );
} }
} }
} }
}
Ok(lock) Ok(lock)
} }
@ -146,8 +140,8 @@ impl Lock {
else { else {
continue; continue;
}; };
let marker = edge.weight().as_ref(); let marker = edge.weight().clone();
locked_dist.add_dependency(dependency_dist, marker); locked_dist.add_dependency(dependency_dist, marker.unwrap_or_default());
} }
let id = locked_dist.id.clone(); let id = locked_dist.id.clone();
if let Some(locked_dist) = locked_dists.insert(id, locked_dist) { if let Some(locked_dist) = locked_dists.insert(id, locked_dist) {
@ -178,8 +172,12 @@ impl Lock {
else { else {
continue; continue;
}; };
let marker = edge.weight().as_ref(); let marker = edge.weight().clone();
locked_dist.add_optional_dependency(extra.clone(), dependency_dist, marker); locked_dist.add_optional_dependency(
extra.clone(),
dependency_dist,
marker.unwrap_or_default(),
);
} }
} }
if let Some(group) = dist.dev.as_ref() { if let Some(group) = dist.dev.as_ref() {
@ -196,8 +194,12 @@ impl Lock {
else { else {
continue; continue;
}; };
let marker = edge.weight().as_ref(); let marker = edge.weight().clone();
locked_dist.add_dev_dependency(group.clone(), dependency_dist, marker); locked_dist.add_dev_dependency(
group.clone(),
dependency_dist,
marker.unwrap_or_default(),
);
} }
} }
} }
@ -488,11 +490,7 @@ impl Lock {
)) ))
}; };
for dep in deps { for dep in deps {
if dep if dep.marker.evaluate(marker_env, &[]) {
.marker
.as_ref()
.map_or(true, |marker| marker.evaluate(marker_env, &[]))
{
let dep_dist = self.find_by_id(&dep.package_id); let dep_dist = self.find_by_id(&dep.package_id);
if seen.insert((&dep.package_id, None)) { if seen.insert((&dep.package_id, None)) {
queue.push_back((dep_dist, None)); queue.push_back((dep_dist, None));
@ -772,7 +770,7 @@ impl Package {
} }
/// Add the [`AnnotatedDist`] as a dependency of the [`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); let new_dep = Dependency::from_annotated_dist(annotated_dist, marker);
for existing_dep in &mut self.dependencies { for existing_dep in &mut self.dependencies {
if existing_dep.package_id == new_dep.package_id if existing_dep.package_id == new_dep.package_id
@ -790,7 +788,7 @@ impl Package {
&mut self, &mut self,
extra: ExtraName, extra: ExtraName,
annotated_dist: &AnnotatedDist, annotated_dist: &AnnotatedDist,
marker: Option<&MarkerTree>, marker: MarkerTree,
) { ) {
self.optional_dependencies self.optional_dependencies
.entry(extra) .entry(extra)
@ -803,7 +801,7 @@ impl Package {
&mut self, &mut self,
dev: GroupName, dev: GroupName,
annotated_dist: &AnnotatedDist, annotated_dist: &AnnotatedDist,
marker: Option<&MarkerTree>, marker: MarkerTree,
) { ) {
self.dev_dependencies self.dev_dependencies
.entry(dev) .entry(dev)
@ -1072,15 +1070,11 @@ impl Package {
for dep in deps { for dep in deps {
if let Some(mut dep) = dep.to_requirement(workspace_root, &mut dependency_extras)? { if let Some(mut dep) = dep.to_requirement(workspace_root, &mut dependency_extras)? {
// Add back the extra marker expression. // Add back the extra marker expression.
let marker = MarkerTree::expression(MarkerExpression::Extra { dep.marker
.and(MarkerTree::expression(MarkerExpression::Extra {
operator: ExtraOperator::Equal, operator: ExtraOperator::Equal,
name: extra.clone(), name: extra.clone(),
}); }));
match dep.marker {
Some(ref mut tree) => tree.and(marker),
None => dep.marker = Some(marker),
}
requires_dist.push(dep); requires_dist.push(dep);
} }
@ -2282,17 +2276,13 @@ impl TryFrom<WheelWire> for Wheel {
struct Dependency { struct Dependency {
package_id: PackageId, package_id: PackageId,
extra: BTreeSet<ExtraName>, extra: BTreeSet<ExtraName>,
marker: Option<MarkerTree>, marker: MarkerTree,
} }
impl Dependency { impl Dependency {
fn from_annotated_dist( fn from_annotated_dist(annotated_dist: &AnnotatedDist, marker: MarkerTree) -> Dependency {
annotated_dist: &AnnotatedDist,
marker: Option<&MarkerTree>,
) -> Dependency {
let package_id = PackageId::from_annotated_dist(annotated_dist); let package_id = PackageId::from_annotated_dist(annotated_dist);
let extra = annotated_dist.extra.iter().cloned().collect(); let extra = annotated_dist.extra.iter().cloned().collect();
let marker = marker.cloned();
Dependency { Dependency {
package_id, package_id,
extra, extra,
@ -2389,7 +2379,7 @@ impl Dependency {
.collect::<Array>(); .collect::<Array>();
table.insert("extra", value(extra_array)); 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())); table.insert("marker", value(marker.to_string()));
} }
@ -2425,7 +2415,8 @@ struct DependencyWire {
package_id: PackageIdForDependency, package_id: PackageIdForDependency,
#[serde(default)] #[serde(default)]
extra: BTreeSet<ExtraName>, extra: BTreeSet<ExtraName>,
marker: Option<MarkerTree>, #[serde(default)]
marker: MarkerTree,
} }
impl DependencyWire { impl DependencyWire {
@ -2816,12 +2807,10 @@ impl<'env> TreeDisplay<'env> {
// Skip dependencies that don't apply to the current environment. // Skip dependencies that don't apply to the current environment.
if let Some(environment_markers) = markers { if let Some(environment_markers) = markers {
if let Some(dependency_markers) = dependency.marker.as_ref() { if !dependency.marker.evaluate(environment_markers, &[]) {
if !dependency_markers.evaluate(environment_markers, &[]) {
continue; continue;
} }
} }
}
dependencies.entry(parent).or_default().push(child); dependencies.entry(parent).or_default().push(child);
} }
@ -2847,12 +2836,10 @@ impl<'env> TreeDisplay<'env> {
// Skip dependencies that don't apply to the current environment. // Skip dependencies that don't apply to the current environment.
if let Some(environment_markers) = markers { if let Some(environment_markers) = markers {
if let Some(dependency_markers) = dependency.marker.as_ref() { if !dependency.marker.evaluate(environment_markers, &[]) {
if !dependency_markers.evaluate(environment_markers, &[]) {
continue; continue;
} }
} }
}
optional_dependencies optional_dependencies
.entry(parent) .entry(parent)
@ -2884,12 +2871,10 @@ impl<'env> TreeDisplay<'env> {
// Skip dependencies that don't apply to the current environment. // Skip dependencies that don't apply to the current environment.
if let Some(environment_markers) = markers { if let Some(environment_markers) = markers {
if let Some(dependency_markers) = dependency.marker.as_ref() { if !dependency.marker.evaluate(environment_markers, &[]) {
if !dependency_markers.evaluate(environment_markers, &[]) {
continue; continue;
} }
} }
}
dev_dependencies dev_dependencies
.entry(parent) .entry(parent)

View File

@ -23,7 +23,7 @@ pub struct Preference {
name: PackageName, name: PackageName,
version: Version, version: Version,
/// The markers on the requirement itself (those after the semicolon). /// The markers on the requirement itself (those after the semicolon).
marker: Option<MarkerTree>, marker: MarkerTree,
/// If coming from a package with diverging versions, the markers of the forks this preference /// If coming from a package with diverging versions, the markers of the forks this preference
/// is part of, otherwise `None`. /// is part of, otherwise `None`.
fork_markers: Option<BTreeSet<MarkerTree>>, fork_markers: Option<BTreeSet<MarkerTree>>,
@ -77,7 +77,7 @@ impl Preference {
Self { Self {
name: dist.name().clone(), name: dist.name().clone(),
version: version.clone(), version: version.clone(),
marker: None, marker: MarkerTree::TRUE,
// Installed distributions don't have fork annotations. // Installed distributions don't have fork annotations.
fork_markers: None, fork_markers: None,
hashes: Vec::new(), hashes: Vec::new(),
@ -89,7 +89,7 @@ impl Preference {
Self { Self {
name: package.id.name.clone(), name: package.id.name.clone(),
version: package.id.version.clone(), version: package.id.version.clone(),
marker: None, marker: MarkerTree::TRUE,
fork_markers: package.fork_markers().cloned(), fork_markers: package.fork_markers().cloned(),
hashes: Vec::new(), hashes: Vec::new(),
} }
@ -128,11 +128,7 @@ impl Preferences {
for preference in preferences { for preference in preferences {
// Filter non-matching preferences when resolving for an environment. // Filter non-matching preferences when resolving for an environment.
if let Some(markers) = markers { if let Some(markers) = markers {
if !preference if !preference.marker.evaluate(markers, &[]) {
.marker
.as_ref()
.map_or(true, |marker| marker.evaluate(markers, &[]))
{
trace!("Excluding {preference} from preferences due to unmatched markers"); trace!("Excluding {preference} from preferences due to unmatched markers");
continue; continue;
} }

View File

@ -94,16 +94,14 @@ impl PubGrubPackage {
pub(crate) fn from_package( pub(crate) fn from_package(
name: PackageName, name: PackageName,
extra: Option<ExtraName>, extra: Option<ExtraName>,
marker: Option<MarkerTree>, marker: MarkerTree,
) -> Self { ) -> Self {
// Remove all extra expressions from the marker, since we track extras // Remove all extra expressions from the marker, since we track extras
// separately. This also avoids an issue where packages added via // separately. This also avoids an issue where packages added via
// extras end up having two distinct marker expressions, which in turn // extras end up having two distinct marker expressions, which in turn
// makes them two distinct packages. This results in PubGrub being // makes them two distinct packages. This results in PubGrub being
// unable to unify version constraints across such packages. // unable to unify version constraints across such packages.
let marker = marker let marker = marker.simplify_extras_with(|_| true).contents();
.map(|m| m.simplify_extras_with(|_| true))
.and_then(|marker| marker.contents());
if let Some(extra) = extra { if let Some(extra) = extra {
Self(Arc::new(PubGrubPackageInner::Extra { Self(Arc::new(PubGrubPackageInner::Extra {
name, name,

View File

@ -587,10 +587,7 @@ impl ResolutionGraph {
.constraints .constraints
.apply(self.overrides.apply(archive.metadata.requires_dist.iter())) .apply(self.overrides.apply(archive.metadata.requires_dist.iter()))
{ {
let Some(ref marker_tree) = req.marker else { add_marker_params_from_tree(&req.marker, &mut seen_marker_values);
continue;
};
add_marker_params_from_tree(marker_tree, &mut seen_marker_values);
} }
} }
@ -599,10 +596,7 @@ impl ResolutionGraph {
.constraints .constraints
.apply(self.overrides.apply(self.requirements.iter())) .apply(self.overrides.apply(self.requirements.iter()))
{ {
let Some(ref marker_tree) = direct_req.marker else { add_marker_params_from_tree(&direct_req.marker, &mut seen_marker_values);
continue;
};
add_marker_params_from_tree(marker_tree, &mut seen_marker_values);
} }
// Generate the final marker expression as a conjunction of // Generate the final marker expression as a conjunction of

View File

@ -15,7 +15,7 @@ pub(crate) struct ForkMap<T>(FxHashMap<PackageName, Vec<Entry<T>>>);
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct Entry<T> { struct Entry<T> {
value: T, value: T,
marker: Option<MarkerTree>, marker: MarkerTree,
} }
impl<T> Default for ForkMap<T> { impl<T> Default for ForkMap<T> {
@ -67,12 +67,7 @@ impl<T> ForkMap<T> {
// with the current fork, i.e. the markers are not disjoint. // with the current fork, i.e. the markers are not disjoint.
ResolverMarkers::Fork(fork) => values ResolverMarkers::Fork(fork) => values
.iter() .iter()
.filter(|entry| { .filter(|entry| !fork.is_disjoint(&entry.marker))
!entry
.marker
.as_ref()
.is_some_and(|marker| fork.is_disjoint(marker))
})
.map(|entry| &entry.value) .map(|entry| &entry.value)
.collect(), .collect(),

View File

@ -1598,12 +1598,11 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
// If the requirement is `requests ; sys_platform == 'darwin'` and the // If the requirement is `requests ; sys_platform == 'darwin'` and the
// constraint is `requests ; python_version == '3.6'`, the constraint // constraint is `requests ; python_version == '3.6'`, the constraint
// should only apply when _both_ markers are true. // should only apply when _both_ markers are true.
if let Some(marker) = requirement.marker.as_ref() { if requirement.marker.is_true() {
let marker = constraint.marker.as_ref().map(|m| { Cow::Borrowed(constraint)
let mut marker = marker.clone(); } else {
marker.and(m.clone()); let mut marker = constraint.marker.clone();
marker marker.and(requirement.marker.clone());
}).or_else(|| Some(marker.clone()));
Cow::Owned(Requirement { Cow::Owned(Requirement {
name: constraint.name.clone(), name: constraint.name.clone(),
@ -1612,8 +1611,6 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
origin: constraint.origin.clone(), origin: constraint.origin.clone(),
marker marker
}) })
} else {
Cow::Borrowed(constraint)
} }
}) })
) )
@ -3120,8 +3117,5 @@ fn satisfies_requires_python(
/// Returns true if and only if the given requirement's marker expression has a /// Returns true if and only if the given requirement's marker expression has a
/// possible true value given the `markers` expression given. /// possible true value given the `markers` expression given.
fn possible_to_satisfy_markers(markers: &MarkerTree, requirement: &Requirement) -> bool { fn possible_to_satisfy_markers(markers: &MarkerTree, requirement: &Requirement) -> bool {
let Some(marker) = requirement.marker.as_ref() else { !markers.is_disjoint(&requirement.marker)
return true;
};
!markers.is_disjoint(marker)
} }

View File

@ -99,7 +99,7 @@ Ok(
), ),
}, },
extra: {}, extra: {},
marker: None, marker: true,
}, },
], ],
optional_dependencies: {}, optional_dependencies: {},

View File

@ -99,7 +99,7 @@ Ok(
), ),
}, },
extra: {}, extra: {},
marker: None, marker: true,
}, },
], ],
optional_dependencies: {}, optional_dependencies: {},

View File

@ -99,7 +99,7 @@ Ok(
), ),
}, },
extra: {}, extra: {},
marker: None, marker: true,
}, },
], ],
optional_dependencies: {}, optional_dependencies: {},

View File

@ -522,8 +522,8 @@ fn update_requirement(old: &mut Requirement, new: &Requirement, has_source: bool
} }
// Update the marker expression. // Update the marker expression.
if let Some(marker) = new.marker.clone() { if new.marker.contents().is_some() {
old.marker = Some(marker); old.marker = new.marker.clone();
} }
} }

View File

@ -8,7 +8,7 @@ use glob::{glob, GlobError, PatternError};
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use tracing::{debug, trace, warn}; use tracing::{debug, trace, warn};
use pep508_rs::{RequirementOrigin, VerbatimUrl}; use pep508_rs::{MarkerTree, RequirementOrigin, VerbatimUrl};
use pypi_types::{Requirement, RequirementSource}; use pypi_types::{Requirement, RequirementSource};
use uv_fs::{absolutize_path, normalize_path, relative_to, Simplified}; use uv_fs::{absolutize_path, normalize_path, relative_to, Simplified};
use uv_normalize::{GroupName, PackageName, DEV_DEPENDENCIES}; use uv_normalize::{GroupName, PackageName, DEV_DEPENDENCIES};
@ -282,7 +282,7 @@ impl Workspace {
Some(Requirement { Some(Requirement {
name: project.name.clone(), name: project.name.clone(),
extras, extras,
marker: None, marker: MarkerTree::TRUE,
source: RequirementSource::Directory { source: RequirementSource::Directory {
install_path: member.root.clone(), install_path: member.root.clone(),
lock_path: member lock_path: member

View File

@ -139,12 +139,11 @@ impl DisplayDependencyGraph {
// Add all transitive requirements. // Add all transitive requirements.
for metadata in packages.values().flatten() { for metadata in packages.values().flatten() {
// Ignore any optional dependencies. // Ignore any optional dependencies.
for required in metadata.requires_dist.iter().filter(|requirement| { for required in metadata
requirement .requires_dist
.marker .iter()
.as_ref() .filter(|requirement| requirement.marker.evaluate(markers, &[]))
.map_or(true, |m| m.evaluate(markers, &[])) {
}) {
let dependency = if invert { let dependency = if invert {
Dependency::Inverted( Dependency::Inverted(
required.name.clone(), required.name.clone(),