Skip to content

gh-121291: Respect mixin bitwise-operator overrides on Flag subclasses - #155862

Open
SomSamantray wants to merge 5 commits into
python:mainfrom
SomSamantray:gh-121291-enum-flag-mixin-operators
Open

gh-121291: Respect mixin bitwise-operator overrides on Flag subclasses#155862
SomSamantray wants to merge 5 commits into
python:mainfrom
SomSamantray:gh-121291-enum-flag-mixin-operators

Conversation

@SomSamantray

@SomSamantray SomSamantray commented Aug 15, 2026

Copy link
Copy Markdown

EnumType.__new__ (Lib/enum.py) installs Flag's __or__/__and__/__xor__/__ror__/__rand__/__rxor__/__invert__ onto every Flag subclass whenever the name isn't in the subclass's own class body — but that check never looked at what a mixin base actually resolved to, so class MyFlag(Mixin, Flag) silently lost the mixin's own operator overrides to Flag's defaults. The __repr__/__str__/__format__/__reduce_ex__ block a few lines above already handles this correctly (checking whether the class's real MRO-resolved method is still the type default before overwriting); this gives the Flag-operator loop the same MRO-aware check.

The check also has to distinguish a mixin's own override from a mixed-in data type's raw operator (e.g. int.__or__ for IntFlag) — an earlier version of this fix compared only against Flag's own method and broke every IntFlag combination (Color.RED | Color.BLUE silently returned a plain int instead of a boxed IntFlag), caught by running the full test_enum suite including the Doc/howto/enum.rst doctests.

Lib/test/test_enum.py gets a regression test in both OldTestFlag and OldTestIntFlag covering: a mixin's override winning over Flag's default (forward and reflected forms), dunders the mixin didn't touch still getting Flag's own, and the IntFlag/int regression case. Full suite: 1091 tests pass, 0 failures.

One known scope boundary, called out during review: when the overriding mixin is itself the class selected as member_type (e.g. a custom int subclass that also overrides __or__), the identity check still can't tell that apart from the raw data-type operator — the same limitation the pre-existing __repr__/__str__ block already has. Fixing that would need a heavier MRO/__dict__-walk redesign touching both blocks; out of scope here.

Fixes #121291.

…lasses

EnumMeta.__new__ unconditionally installed Flag's __or__/__and__/__xor__/
__ror__/__rand__/__rxor__/__invert__ onto every Flag subclass, silently
discarding a mixin base's own override of these dunders -- even though
the class's MRO should have resolved to the mixin's method.

Give this loop the same MRO-aware check already used a few lines above
for __repr__/__str__/__format__/__reduce_ex__: only install Flag's
method when nothing else (neither a mixin nor a mixed-in data type,
e.g. IntFlag's int) already provides a real override.
Avoids redeclaring an equivalent IntFlag enum inline when
OldTestIntFlag already defines and reuses one.
The fixed loop and NEWS entry cover all seven Flag operator dunders;
extend the regression test to exercise the reflected forms too, per
code review (ce-code-review finding python#2).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

enum.Flag ignores bitwise operator methods from mixins

1 participant