Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork33.7k
Description
What is the issue?
The base_generate_next_value_(name, start, count, last_values) inclass Enum is not sufficiently rigorous as a default implementation for assigning values withauto().
Why is it problematic?
For a user employingauto() to assign values for their enums, the expectation is that the function will automatically assign unique values to new enums without the user needing to specify those values manually. However, when used following the creation of analias to a pre-existing enum, the value generated byauto() is not guaranteed to be unique.
Given the following code:
fromenumimportEnum,autoclassExample(Enum):A=auto()B=auto()C=AD=auto()
the expectation is thatA, B, D have been assigned unique values whereasC is an alias ofA. A printout of each of theExample enum's values proves that not to be the case though:
>>>print(Example.A)Example.A>>>print(Example.B)Example.B>>>print(Example.C)Example.A>>>print(Example.D)### UNEXPECTED!Example.B
effectively renderingD as an alias toB rather than its own separate value.
Suggested Cause
Upon closer inspection, the reason seems to be that the base_generate_next_value_ whichauto() relies on is incrementing the "last value that was assigned" rather than the "lastNEW value that was assigned"
Lines 1171 to 1186 ina8abb76
| def_generate_next_value_(name,start,count,last_values): | |
| """ | |
| Generate the next value when not given. | |
| name: the name of the member | |
| start: the initial start value or None | |
| count: the number of existing members | |
| last_value: the last value assigned or None | |
| """ | |
| forlast_valueinreversed(last_values): | |
| try: | |
| returnlast_value+1 | |
| exceptTypeError: | |
| pass | |
| else: | |
| returnstart |
Current Workaround
At the moment, to workaround this issue, the user can:
- Ensure that all aliases are only declaredafter any and all enums assigned with
auto() - Implement a replacement
_generate_next_value_(name, start, count, last_values)function as described in thedocs
This issue only affects code that combines the use ofauto() with aliases. Although straightforward workarounds do exist (overloading_generate_next_value_ is well described in the docs), it seems unintuitive and unfriendly as the default behavior ofauto(). Even simply sortinglast_values before incrementing may be a sufficient solution to this issue, e.g.
def_generate_next_value_(name,start,count,last_values):# for last_value in reversed(last_values):forlast_valueinsorted(last_values,reverse=True):try:returnlast_value+1exceptTypeError:passelse:returnstart