Repository navigation
enum.Flag.__contains__ changed behavior since python 3.12 #131045
Description
Activity
- addedtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
on Mar 10, 2025 - addedstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directory3.12only security fixesonly security fixes3.13only security fixesonly security fixes3.14bugs and security fixesbugs and security fixes
on Mar 10, 2025 1 | 2 becomes 3 and I think your surprise comes from the fact that a new member is automatically created. I think you can avoid this starting from 3.12 by specifying the boundary (namely a new member is not automatically created). I haven't checked but this should also have been documented somehow maybe indirectly.
I believe that the reason is because the result of the OR of two enum flag members should remain an enum flag member by default (3.12+) and thus we create that additional member on the fly.
With a different boundary the result would be a pure int and not an enum member. To check if this diagnosis is correct, print the type of the
_in your code.I can check on Wednesday as I'm unavailable until then (and I'm only answering from memory)
- addedpendingThe issue will be closed if no feedback is providedThe issue will be closed if no feedback is provided
on Mar 10, 2025 This behaviour is documented for
enum.IntFlag:If a Flag operation is performed with an IntFlag member and:
- the result is a valid IntFlag: an IntFlag is returned
- the result is not a valid IntFlag: the result depends on the FlagBoundary setting
Perhaps we should mention this in
enum.Flagas well?The intent is that
__contains__will returnTrueif either a member or a member value exists. In other words, ifWeekday(x)would return a valid member, thenx in Weekdayshould return True. The issue you found is that pseudo-members are not created until needed, but are then added to the Enum so thatWeekday(3) is Weekday(3)isTrue(i.e. pseudo-members are also singletons).One solution is to have
__contains__attempt a value -> member conversion so any pseudo-members are created.- removedpendingThe issue will be closed if no feedback is providedThe issue will be closed if no feedback is provided
on Mar 10, 2025 - added a commit that references this issue
on Mar 23, 2025 @ethanfurman What do you want to do with the backports? 3.12 is nearing its last bug fix so I wonder whether you are willing to review my PR (which had conflicts that I resolved but I'm not sure it's entirely correct for you)
Thanks for taking care of that; my PC has been having issues this last week.
Reacted by Bénédikt Tran- added a commit that references this issue
on Mar 24, 2025 Thank you for the report and for the fix!
Metadata
Metadata
Assignees
Labels
Projects
- StatusShow more project fieldsDone
Bug report
Bug description:
I noticed some strange behavior with
enum.Flagan the__contains__method in Python 3.12/3.13, as shown in the following examples.Problem 1: Behavior changes at runtime
In the following code snippet the first print statement returns
False, which is expected, since3is not a member ofWeekday. However, the second print statement returnsTrue, which is unexpected, since3is still not a member ofWeekday.Problem 2: Behavior is not comparable to Python 3.11
Since Python 3.12 the behavior of
Enum.__contains__has changed, so that it is possible to compare not only with an enum-member, but also with non-enum-members (see here or here). So with Python 3.11 the code above will raise anTypeError: unsupported operand type(s) for 'in': 'int' and 'EnumType'. There you have to change the code to the following. But this in turn always produces unexpected behavior in Python 3.12/3.13.Conclusion
I would have expected that in all cases the result is
False, but since Python 3.12 it gets very strange...CPython versions tested on:
3.12, 3.13
Operating systems tested on:
Windows
Linked PRs