Skip to content

Fix marker version comparison when variable is on the RHS (issue #934)#1126

Open
r266-tech wants to merge 2 commits intopypa:mainfrom
r266-tech:fix/rhs-marker-version-comparison
Open

Fix marker version comparison when variable is on the RHS (issue #934)#1126
r266-tech wants to merge 2 commits intopypa:mainfrom
r266-tech:fix/rhs-marker-version-comparison

Conversation

@r266-tech
Copy link

Summary

Fixes #934.

PEP 508 permits marker expressions with the variable on either side:

python_version >= '3.9'     # variable on LHS — worked before
'3.9' <= python_version     # variable on RHS — broken before this fix
'3.13.*' == python_full_version  # wildcard failed entirely

Root cause

_eval_op always builds a Specifier from its rhs argument and then checks whether lhs is contained in it. _evaluate_markers was passing operands in the original (possibly reversed) order without adjusting for direction, so when the variable was on the RHS the Specifier was constructed from the environment value (e.g. '3.13.7') and the literal pattern ('3.13.*') was used as the containment query — which fails because a wildcard is not a valid plain version string.

Fix

An invert flag is threaded into _eval_op. When the marker variable was on the RHS and the operator is a directional comparison (i.e. not in / not in), _eval_op swaps the operands and flips the operator (e.g. <=>=) so the Specifier is always built from the literal and the environment value is what gets checked.

Membership operators (in / not in) already handle both directions correctly and are left untouched.

Tests added

Seven new parametrised cases in TestMarker.test_marker_variable_on_rhs:

Marker Environment Expected
'3.13.*' == python_full_version 3.13.7 True
'3.13.*' == python_full_version 3.14.0 False
'3.9' <= python_version 3.13 True
'3.14' > python_version 3.13 True
'3.14' > python_version 3.15 False
'posix' == os_name posix True
'nt' != os_name posix True

Full test suite: 60 634 passed, 1 skipped (the skip is an unrelated Linux-only test).

Fixes pypa#934.

PEP 508 allows marker expressions with the variable on either side, e.g.:

    python_version >= '3.9'
    '3.9' <= python_version   # equivalent

Previously _evaluate_markers passed the operands to _eval_op in the
original (possibly reversed) order without adjusting for the direction.
For version-comparison operators this caused _eval_op to construct a
Specifier from the environment value (e.g. '3.13.7') and then check
containment of the literal pattern ('3.13.*'), which failed because the
wildcard is not a valid version string.

Fix: thread an invert flag through _eval_op. When the marker variable was
on the RHS and the operator is a directional comparison (not 'in' /
'not in'), swap the operands back and flip the operator so the Specifier
is always built from the literal and the environment value is the thing
being checked.  Membership operators (in / not in) already work correctly
in either direction and are left untouched.

Add regression tests covering ==, <=, > with version markers and == / !=
with non-version markers when the variable is on the RHS.
@henryiii
Copy link
Contributor

Duplicate of #1112. Not sure if we want to do this still.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Marker version comparison fails when the marker variable is on the RHS of a term.

3 participants