Repository navigation
enum.IntFlag regression: missing values cause TypeError #88408
Description
Activity
With the change introduced in https://bugs.python.org/issue38250 7aaeb2a I observe a regression in behavior of enum.IntFlag with missing values.
Consider this code (from pyproj):
from enum import IntFlag class GeodIntermediateFlag(IntFlag): DEFAULT = 0x0 NPTS_MASK = 0xF NPTS_ROUND = 0x0 NPTS_CEIL = 0x1 NPTS_TRUNC = 0x2 DEL_S_MASK = 0xF0 DEL_S_RECALC = 0x00 DEL_S_NO_RECALC = 0x10 AZIS_MASK = 0xF00 AZIS_DISCARD = 0x000 AZIS_KEEP = 0x100
This is a valid code in Python 3.9, however produces a TypeError in Python 3.10.0b1:
Traceback (most recent call last): File "intflag.py", line 3, in <module> class GeodIntermediateFlag(IntFlag): File "/usr/lib64/python3.10/enum.py", line 544, in __new__ raise TypeError( TypeError: invalid Flag 'GeodIntermediateFlag' -- missing values: 4, 8, 32, 64, 128, 512, 1024, 2048Since I don't see this behavior mentioned in https://docs.python.org/3.10/library/enum.html or https://docs.python.org/3.10/whatsnew/3.10.html or https://docs.python.org/3.10/whatsnew/changelog.html I believe this is a regression.
- added3.10 (EOL)end of lifeend of lifestdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
on May 26, 2021 We are already blocked in Python 3.10 beta 2, Ethan, could you give a look at this so we can introduce the fix when we release the next beta?
That is an intentional change. The cause is that the masks include bits that are not named in the Flag.
The user-side fix is to add a
boundary=KEEPoption to the flag:class GeodIntermediateFlag(IntFlag, boundary=KEEP)
The enum library fix could be one of two things:
-
automatically use the KEEP boundary when these conditions arise, and issue a DeprecationWarning; or
-
lose that particular check.
I'm inclined to go with option 2, since
boundaryis designed to answer the question of what to do when Flag.A | Flag.B does not exist in Flag.-
To clarify, it's caused by these mask entries in the enum:
NPTS_MASK = 0xF DEL_S_MASK = 0xF0 AZIS_MASK = 0xF00
Since the masks are not an aggregation of individual bits defined in the enum, it's an error.
I'm inclined to go with [removing the check], since
boundaryis designed to answer the question of what to do when Flag.A | Flag.B does not exist in Flag.I think that would cause various problems in the API and implementation. For example, without underlying individual bits, repr() may be nonsensical.
I wonder if CONFORM could tolerate these, since it's ultimately going to discard invalid bits. And then perhaps CONFORM is the default.
Actually, thinking about that a little bit more, KEEP was added for exactly this situation, as some stdlib flags exhibit the same behavior.
So the real question is what should happen with, for example,
GeodIntermediateFlag(0x80)
?
The idea behind boundary is what should happen when values are created that don't have names in the Enum/Flag? The options for boundary are:
STRICT -> an error is raised (default for Enum)
EJECT -> the integer 0x80 is returned (not a flag)
CONFORM -> unnamed bits are discarded (so the DEFAULT flag would be returned)
KEEP -> an unnamed flag with value 0x80 is returnedSo KEEP is currently doing double-duty -- this reinforces my desire to go with option 2 and return KEEP to single-duty status.
Those are good points -- the difficulty is knowing which behavior the user wants. And if the desired run-time behavior doesn't match the boundary flag the user is stuck.
For example, if the default is CONFORM or KEEP, but the user wants an error if 0x80 comes up, they would have to explicitly check for that value since the Flag would happily return it instead of raising.
Rather than make such masks containing unknown bits, this would be best practice if you want to use STRICT, correct?
NPTS_ROUND = 0x0 NPTS_CEIL = 0x1 NPTS_TRUNC = 0x2 NPTS_MASK = NPTS_ROUND | NPTS_CEIL | NPTS_TRUNC
Otherwise, if your input may have unknown bits, use CONFORM.
18 remaining items
- added3.11only security fixesonly security fixesand removed
on Jun 10, 2021 Also changing error reporting to be less susceptible to DOS attacks.
jacobtylerwalls commented
on Jun 14, 2021 jacobtylerwallsmannequinMannequinMore actionsWith the followup patch merged, can this be closed now?
Yup, just had to get back from the weekend. :-)
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields: