Skip to content

fix: correct allows_all containment check for "!=" vs "not in"#955

Open
hexonal wants to merge 2 commits into
python-poetry:mainfrom
hexonal:fix-constraint-allows-all-containment
Open

fix: correct allows_all containment check for "!=" vs "not in"#955
hexonal wants to merge 2 commits into
python-poetry:mainfrom
hexonal:fix-constraint-allows-all-containment

Conversation

@hexonal

@hexonal hexonal commented Jul 16, 2026

Copy link
Copy Markdown

Fixes python-poetry/poetry#10977

Constraint.allows_all() had a containment check backwards for the case where self is a != constraint and other is a not in constraint. It tested self.value not in other.value, but the correct check has the same shape as the existing not in / not in branch just above it: other.value in self.value.

Concretely:

>>> from poetry.core.version.markers import parse_marker
>>> m = parse_marker('os_name != "a" and "b" not in os_name')
>>> str(m)  # before: the `!=` clause silently disappears
'"b" not in os_name'
>>> m.validate({"os_name": "a"})  # before: True (wrong)
>>> m.validate({"os_name": "a"})  # after: False (correct)

This happened because MultiMarker/constraint intersection logic uses allows_all to drop a clause it believes is redundant. The old formula wrongly considered os_name != "a" redundant given "b" not in os_name, even though os_name == "a" satisfies the latter but not the former.

I merged the two branches for self._operator == "not in" and self._operator == "!=" under other.operator == "not in" since they resolve to the identical correct formula.

Added regression tests in tests/constraints/generic/test_constraint.py (direct allows_all cases) and tests/version/test_markers.py (the exact marker/validate scenario from the issue, plus two adjacent cases).

Constraint.allows_all() compared self.value not in other.value when
self is "!=" and other is "not in", but the correct check has the
same shape as the existing "not in"/"not in" case: other.value in
self.value. For example, "os_name != 'a'" does not allow everything
"'b' not in os_name" allows, since os_name == "a" satisfies the
latter but not the former; the old formula returned True here,
causing the "!=" term to be dropped when combined with "and".

Fixes python-poetry/poetry#10977.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

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.

poetry-core drops the != term from x != "a" and "b" not in x

2 participants