Skip to content

Commit

Permalink
Treat invalid extras as false
Browse files Browse the repository at this point in the history
  • Loading branch information
charliermarsh committed Aug 22, 2024
1 parent 720814c commit 7effdf0
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 17 deletions.
3 changes: 2 additions & 1 deletion crates/pep508-rs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use thiserror::Error;
use url::Url;

use crate::marker::MarkerValueExtra;
use cursor::Cursor;
pub use marker::{
ContainsMarkerTree, ExtraMarkerTree, ExtraOperator, InMarkerTree, MarkerEnvironment,
Expand Down Expand Up @@ -408,7 +409,7 @@ impl<T: Pep508Url> Requirement<T> {
self.marker
.and(MarkerTree::expression(MarkerExpression::Extra {
operator: ExtraOperator::Equal,
name: extra.clone(),
name: MarkerValueExtra::Extra(extra.clone()),
}));

self
Expand Down
4 changes: 2 additions & 2 deletions crates/pep508-rs/src/marker/algebra.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@ use pep440_rs::{Version, VersionSpecifier};
use pubgrub::Range;
use rustc_hash::FxHashMap;
use std::sync::LazyLock;
use uv_normalize::ExtraName;
use uv_pubgrub::PubGrubSpecifier;

use crate::marker::MarkerValueExtra;
use crate::ExtraOperator;
use crate::{MarkerExpression, MarkerOperator, MarkerValueString, MarkerValueVersion};

Expand Down Expand Up @@ -446,7 +446,7 @@ pub(crate) enum Variable {
///
/// We keep extras at the leaves of the tree, so when simplifying extras we can
/// trivially remove the leaves without having to reconstruct the entire tree.
Extra(ExtraName),
Extra(MarkerValueExtra),
}

/// A decision node in an Algebraic Decision Diagram.
Expand Down
5 changes: 3 additions & 2 deletions crates/pep508-rs/src/marker/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ mod tree;
pub use environment::{MarkerEnvironment, MarkerEnvironmentBuilder};
pub use tree::{
ContainsMarkerTree, ExtraMarkerTree, ExtraOperator, InMarkerTree, MarkerExpression,
MarkerOperator, MarkerTree, MarkerTreeContents, MarkerTreeKind, MarkerValue, MarkerValueString,
MarkerValueVersion, MarkerWarningKind, StringMarkerTree, StringVersion, VersionMarkerTree,
MarkerOperator, MarkerTree, MarkerTreeContents, MarkerTreeKind, MarkerValue, MarkerValueExtra,
MarkerValueString, MarkerValueVersion, MarkerWarningKind, StringMarkerTree, StringVersion,
VersionMarkerTree,
};

/// `serde` helpers for [`MarkerTree`].
Expand Down
10 changes: 5 additions & 5 deletions crates/pep508-rs/src/marker/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use pep440_rs::{Version, VersionPattern, VersionSpecifier};
use uv_normalize::ExtraName;

use crate::cursor::Cursor;
use crate::marker::MarkerValueExtra;
use crate::{
ExtraOperator, MarkerExpression, MarkerOperator, MarkerTree, MarkerValue, MarkerValueVersion,
MarkerWarningKind, Pep508Error, Pep508ErrorSource, Pep508Url, Reporter,
Expand Down Expand Up @@ -427,14 +428,13 @@ fn parse_extra_expr(
reporter: &mut impl Reporter,
) -> Option<MarkerExpression> {
let name = match ExtraName::from_str(value) {
Ok(name) => name,
Ok(name) => MarkerValueExtra::Extra(name),
Err(err) => {
reporter.report(
MarkerWarningKind::ExtraInvalidComparison,
format!("Expected extra name, found '{value}', will be ignored: {err}"),
format!("Expected extra name (found `{value}`): {err}"),
);

return None;
MarkerValueExtra::Arbitrary(value.to_string())
}
};

Expand Down Expand Up @@ -575,5 +575,5 @@ pub(crate) fn parse_markers<T: Pep508Url>(

// If the tree consisted entirely of arbitrary expressions
// that were ignored, it evaluates to true.
parse_markers_cursor(&mut chars, reporter).map(|result| result.unwrap_or(MarkerTree::TRUE))
parse_markers_cursor(&mut chars, reporter).map(|result| result.unwrap_or(MarkerTree::FALSE))
}
56 changes: 49 additions & 7 deletions crates/pep508-rs/src/marker/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,33 @@ impl Deref for StringVersion {
}
}

/// The [`ExtraName`] value used in `extra` markers.
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub enum MarkerValueExtra {
/// A valid [`ExtraName`].
Extra(ExtraName),
/// An invalid name, preserved as an arbitrary string.
Arbitrary(String),
}

impl MarkerValueExtra {
fn as_extra(&self) -> Option<&ExtraName> {
match self {
Self::Extra(extra) => Some(extra),
Self::Arbitrary(_) => None,
}
}
}

impl Display for MarkerValueExtra {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Extra(extra) => extra.fmt(f),
Self::Arbitrary(string) => string.fmt(f),
}
}
}

/// Represents one clause such as `python_version > "3.8"`.
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
#[allow(missing_docs)]
Expand Down Expand Up @@ -471,7 +498,7 @@ pub enum MarkerExpression {
/// `extra <extra op> '...'` or `'...' <extra op> extra`.
Extra {
operator: ExtraOperator,
name: ExtraName,
name: MarkerValueExtra,
},
}

Expand Down Expand Up @@ -885,7 +912,12 @@ impl MarkerTree {
}
MarkerTreeKind::Extra(marker) => {
return marker
.edge(extras.contains(marker.name()))
.edge(
marker
.name()
.as_extra()
.is_some_and(|extra| extras.contains(extra)),
)
.evaluate_reporter_impl(env, extras, reporter);
}
}
Expand Down Expand Up @@ -931,7 +963,12 @@ impl MarkerTree {
.children()
.any(|(_, tree)| tree.evaluate_extras_and_python_version(extras, python_versions)),
MarkerTreeKind::Extra(marker) => marker
.edge(extras.contains(marker.name()))
.edge(
marker
.name()
.as_extra()
.is_some_and(|extra| extras.contains(extra)),
)
.evaluate_extras_and_python_version(extras, python_versions),
}
}
Expand All @@ -956,7 +993,12 @@ impl MarkerTree {
.children()
.any(|(_, tree)| tree.evaluate_extras(extras)),
MarkerTreeKind::Extra(marker) => marker
.edge(extras.contains(marker.name()))
.edge(
marker
.name()
.as_extra()
.is_some_and(|extra| extras.contains(extra)),
)
.evaluate_extras(extras),
}
}
Expand Down Expand Up @@ -1145,7 +1187,7 @@ impl MarkerTree {

fn simplify_extras_with_impl(self, is_extra: &impl Fn(&ExtraName) -> bool) -> MarkerTree {
MarkerTree(INTERNER.lock().restrict(self.0, &|var| match var {
Variable::Extra(name) => is_extra(name).then_some(true),
Variable::Extra(name) => Some(name.as_extra().is_some_and(is_extra)),
_ => None,
}))
}
Expand Down Expand Up @@ -1375,14 +1417,14 @@ impl Ord for ContainsMarkerTree<'_> {
/// A node representing the existence or absence of a given extra, such as `extra == 'bar'`.
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct ExtraMarkerTree<'a> {
name: &'a ExtraName,
name: &'a MarkerValueExtra,
high: NodeId,
low: NodeId,
}

impl ExtraMarkerTree<'_> {
/// Returns the name of the extra in this expression.
pub fn name(&self) -> &ExtraName {
pub fn name(&self) -> &MarkerValueExtra {
self.name
}

Expand Down
42 changes: 42 additions & 0 deletions crates/uv/tests/pip_compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11829,3 +11829,45 @@ fn compatible_build_constraint() -> Result<()> {

Ok(())
}

/// Ensure that we treat invalid extra markers as `false`, i.e., in projects that define
/// non-spec-compliant extras.
#[test]
fn invalid_extra() -> Result<()> {
let context = TestContext::new("3.12");

let setup_py = context.temp_dir.child("setup.py");
setup_py.write_str(indoc! {r#"
from setuptools import setup
extras_require = {
"_anyio": ["anyio"],
"config": ["jsonschema>=2.6.0"],
"encryption": ["iniconfig"],
}
setup(name="project", install_requires=[], extras_require=extras_require)
"#})?;

let requirements_in = context.temp_dir.child("requirements.in");
requirements_in.write_str(".[encryption]")?;


uv_snapshot!(context.filters(), context.pip_compile()
.arg("requirements.in"), @r###"
success: true
exit_code: 0
----- stdout -----
# This file was autogenerated by uv via the following command:
# uv pip compile --cache-dir [CACHE_DIR] requirements.in
iniconfig==2.0.0
# via project
.
# via -r requirements.in
----- stderr -----
Resolved 2 packages in [TIME]
"###);

Ok(())
}

0 comments on commit 7effdf0

Please sign in to comment.