diff --git a/src/packaging/markers.py b/src/packaging/markers.py
index fb7f49cf8..a996f27d8 100644
--- a/src/packaging/markers.py
+++ b/src/packaging/markers.py
@@ -15,6 +15,7 @@
from ._tokenizer import ParserSyntaxError
from .specifiers import InvalidSpecifier, Specifier
from .utils import canonicalize_name
+from .version import InvalidVersion, Version
__all__ = [
"InvalidMarker",
@@ -175,12 +176,20 @@ def _format_marker(
def _eval_op(lhs: str, op: Op, rhs: str) -> bool:
+ # PEP 508 - Environment Markers
+ # https://peps.python.org/pep-0508/#environment-markers
+ # > The operators use the PEP 440 version comparison rules
+ # > when those are defined (that is when both sides have a valid version
+ # > specifier). If there is no defined PEP 440 behaviour and the operator
+ # > exists in Python, then the operator falls back to the Python behaviour.
+ # > Otherwise an error should be raised.
try:
spec = Specifier("".join([op.serialize(), rhs]))
- except InvalidSpecifier:
+ lhs_ver = Version(lhs)
+ except (InvalidSpecifier, InvalidVersion):
pass
else:
- return spec.contains(lhs, prereleases=True)
+ return spec.contains(lhs_ver, prereleases=True)
oper: Operator | None = _operators.get(op.serialize())
if oper is None:
diff --git a/tests/test_markers.py b/tests/test_markers.py
index faf0d13b9..a741b02cf 100644
--- a/tests/test_markers.py
+++ b/tests/test_markers.py
@@ -314,6 +314,14 @@ def test_environment_with_extra_none(self):
{"extra": "different__punctuation_is_EQUAL"},
True,
),
+ # extra name that is also a valid version - version comparison applies
+ # if both sides are valid versions
+ ("extra == 'v8'", {"extra": "quux"}, False),
+ ("extra == 'v8'", {"extra": "v8"}, True),
+ # LHS and RHS are valid versions, so equality uses normalized version
+ ("extra == 'v8-dev'", {"extra": "v8-dev.0"}, True),
+ # LHS and RHS are not valid versions, so equality is str comparison
+ ("extra == 'v8-foo'", {"extra": "v8-foo.0"}, False),
],
)
def test_evaluates(self, marker_string, environment, expected):