From 7c087a24c4f56847cd464fcb5ef3762840c67eb8 Mon Sep 17 00:00:00 2001 From: armorbreak001 Date: Wed, 22 Apr 2026 19:57:13 +0800 Subject: [PATCH] fix(markers): handle version pattern on LHS when marker variable is on RHS When a marker like "'3.12.*' == python_full_version" is evaluated, the variable is on the RHS so the resolved env value (e.g. '3.12.3') was used as the specifier pattern while the literal ('3.12.*') was treated as the item to check. Since '3.12.*' is not a valid PEP 440 version, Specifier.contains() silently returned False. Now try building the specifier from lhs when the first attempt doesn't match and lhs doesn't parse as a concrete version. --- src/packaging/markers.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/packaging/markers.py b/src/packaging/markers.py index 65d7f330b..6c926d2a0 100644 --- a/src/packaging/markers.py +++ b/src/packaging/markers.py @@ -14,6 +14,7 @@ from ._parser import parse_marker as _parse_marker from ._tokenizer import ParserSyntaxError from .specifiers import InvalidSpecifier, Specifier +from .version import Version, InvalidVersion from .utils import canonicalize_name __all__ = [ @@ -221,7 +222,24 @@ def _eval_op(lhs: str, op: Op, rhs: str | AbstractSet[str], *, key: str) -> bool except InvalidSpecifier: pass else: - return spec.contains(lhs, prereleases=True) + if spec.contains(lhs, prereleases=True): + return True + # When the marker variable is on the RHS, lhs may be a version + # pattern (e.g. "3.12.*") while rhs is the resolved env value. + # Building the specifier from rhs produced no match (above), so + # try building it from lhs instead — but only when lhs doesn't + # parse as a concrete version (to avoid wrong answers for + # asymmetric operators like "<" / ">"). + try: + Version(lhs) + except InvalidVersion: + try: + swapped = Specifier(f"{op_str}{lhs}") + except InvalidSpecifier: + pass + else: + if swapped.contains(rhs, prereleases=True): + return True oper: Operator | None = _operators.get(op_str) if oper is None: