Implementation of swapped marker order

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

However, packaging has never supported this. There are no fewer than three open PRs to add this:

uv also doesn’t fully support this, but it partially does, which I think is why we’ve started getting PRs to fix it now after all these years. (Specifically, uv pip install "tqdm; '3.13' <= python_version" works with uv, but uv pip install "tqdm; '3.14.*' == python_full_version" doesn’t work - it just always installs regardless of the python version.) Though maybe it’s just because someone noticed it, opened an issue, then people are picking it as an easy thing to fix, I don’t know. No one has pointed at a real package trying to use this.

The question is, do we want to allow these reversed expressions, or do we want to tighten the spec (with a PEP) to match current practice (minus a small number of packages that might have only been tested on uv and do have flipped values here). I’m neutral; I feel as a user I’d expect to be able to write it however I want, but as a developer, I like strict rules and I don’t like arbitrary choice. What do people think?

If people are happy with packaging allowing reversed order, we can merge on of the PRs, I think 1126 was the nicest implementation.

  • Make the standard match packaging (no flipped order)
  • Make packaging match the standard (support either order)
0 voters
1 Like

I’m not sure I fully understand the comment about uv. But it sounds like this would affect uv as well - in which case, I’m not clear why the vote is only about packaging.

We need to get Attempt to clarify environment marker evaluation by ncoghlan · Pull Request #1988 · pypa/packaging.python.org · GitHub approved and merged before we attempt to make any further clarifications to the environment marker specification.

However, I checked if the standard really was ambiguous about this and unlike some of the semantic details, the syntax is explicitly spelled out as symmetric in the grammar: Dependency specifiers - Python Packaging User Guide

If we change the standard, then it would affect uv, though I think we could just leave it as undefined behavior, I don’t think we need to tell uv to reject this - they might want to. If we change packaging, then it doesn’t really affect uv, other than probably making the existing bugs with ".*" on the left a little higher priority.

Correct, this is clearly part of the standard, packaging just has never implemented it, so it’s very rare in practice. If we fix it in packaging, that locks us to the current standard; I just want to make sure people are okay with that before we do.

From what you’re saying, if we don’t change the standard, this would affect uv too (at least in the sense that the existing bugs would be confirmed as bugs).

But I don’t think there’s any justification for changing the standard here - “we didn’t implement part of the standard and it seems OK” is a pretty weak argument.

Why wouldn’t people be happy with packaging implementing the standard as currently written? Even if you vote for the other option, that doesn’t necessarily imply that you’re not OK with following the standard.

I’d put it more like “it took over 10 years for someone to notice that packaging didn’t implement this, so let’s make sure we do want it” :wink:

Just in case it becomes relevant, I’ll point out that changing the spec will require a PEP (it’s clearly not just a “clarification”).

1 Like

Good point, updated above.

Notably, a double-sided constraint like '3.9' <= python_version <= '3.12' is not currently allowed.[1] To me, that is the only context in which I’d put '3.9' on the LHS; in other contexts, I think it hurts readability and is apparently uncommon enough that nobody noticed or cared about it for years. (The number of open PRs doesn’t indicate any interest in the issue itself; they all look like AI bot slop to me.)

Personally, I’d prefer to narrow down the standard to match packaging’s implementation; but the overhead of a PEP is probably larger than that of accepting one PR and having a handful of lines of code in packaging that are effectively never used.


  1. If I understand the grammar correctly, that could be written as '3.9' <= python_version and python_version <= '3.12', though. ↩︎

2 Likes