Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 33.9k
Description
What is the issue?
The base _generate_next_value_(name, start, count, last_values) in class Enum is not sufficiently rigorous as a default implementation for assigning values with auto().
Why is it problematic?
For a user employing auto() 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 an alias to a pre-existing enum, the value generated by auto() is not guaranteed to be unique.
Given the following code:
fromenumimportEnum, autoclassExample(Enum): A=auto() B=auto() C=AD=auto()the expectation is that A, B, D have been assigned unique values whereas C is an alias of A. A printout of each of the Example 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.Beffectively rendering D as an alias to B rather than its own separate value.
Suggested Cause
Upon closer inspection, the reason seems to be that the base _generate_next_value_ which auto() relies on is incrementing the "last value that was assigned" rather than the "last NEW value that was assigned"
Lines 1171 to 1186 in a8abb76
| 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 declared after any and all enums assigned with
auto() - Implement a replacement
_generate_next_value_(name, start, count, last_values)function as described in the docs
This issue only affects code that combines the use of auto() 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 of auto(). Even simply sorting last_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