Summary
While working on pypa/pip#14139, pip needed to evaluate metadata extra markers against the full set of extras selected for a requirement.
packaging.markers.Marker.evaluate() evaluates extra as a single string in one marker environment, which makes sense for the current API. For installers, though, the useful semantics are set-wide:
extra == "gpu" should match if gpu is one of the selected extras.
extra != "gpu" should match only if gpu is not selected.
extra not in ... needs similar set-wide negation semantics.
Without a public helper for that, pip currently needs custom marker-walking logic or repeated single-extra evaluation with special handling for negated comparisons.
While looking at this, I also noticed that the newer set-valued extras marker variable works in some expression shapes, but raises an internal AssertionError in others.
Reproducer
import packaging
from packaging.markers import Marker
print("packaging", packaging.__version__)
env = {"extras": frozenset({"gpu"})}
for expr in [
'"gpu" in extras',
'"cpu" not in extras',
'"gpu" not in extras',
'extras == "gpu"',
'extras != "gpu"',
'extras in "gpu,docs"',
'extras not in "gpu"',
]:
marker = Marker(expr)
try:
result = marker.evaluate(env, context="lock_file")
except Exception as exc:
result = f"{type(exc).__name__}: {exc}"
print(f"{expr} -> {result}")
Observed behavior
With packaging 26.2:
packaging 26.2
"gpu" in extras -> True
"cpu" not in extras -> True
"gpu" not in extras -> False
extras == "gpu" -> AssertionError: lhs must be a string
extras != "gpu" -> AssertionError: lhs must be a string
extras in "gpu,docs" -> AssertionError: lhs must be a string
extras not in "gpu" -> AssertionError: lhs must be a string
Questions
Is the intended API that set-valued marker variables such as extras only work when the set-valued variable appears on the RHS of in / not in, for example:
Marker('"gpu" in extras')
If so, should unsupported expression shapes such as extras == "gpu" raise a public exception instead of an internal AssertionError?
Separately, would packaging be open to exposing a public helper for evaluating metadata extra markers against a selected extras set?
For pip's use case, metadata still uses extra, not extras, so the useful API would be something like "evaluate this marker against these selected extras using installer semantics". That would let tools avoid depending on Marker._markers internals or reimplementing part of marker evaluation.
Context:
Summary
While working on pypa/pip#14139, pip needed to evaluate metadata
extramarkers against the full set of extras selected for a requirement.packaging.markers.Marker.evaluate()evaluatesextraas a single string in one marker environment, which makes sense for the current API. For installers, though, the useful semantics are set-wide:extra == "gpu"should match ifgpuis one of the selected extras.extra != "gpu"should match only ifgpuis not selected.extra not in ...needs similar set-wide negation semantics.Without a public helper for that, pip currently needs custom marker-walking logic or repeated single-extra evaluation with special handling for negated comparisons.
While looking at this, I also noticed that the newer set-valued
extrasmarker variable works in some expression shapes, but raises an internalAssertionErrorin others.Reproducer
Observed behavior
With
packaging 26.2:Questions
Is the intended API that set-valued marker variables such as
extrasonly work when the set-valued variable appears on the RHS ofin/not in, for example:If so, should unsupported expression shapes such as
extras == "gpu"raise a public exception instead of an internalAssertionError?Separately, would
packagingbe open to exposing a public helper for evaluating metadataextramarkers against a selected extras set?For pip's use case, metadata still uses
extra, notextras, so the useful API would be something like "evaluate this marker against these selected extras using installer semantics". That would let tools avoid depending onMarker._markersinternals or reimplementing part of marker evaluation.Context: