Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enum: auto() is not activated if combined with other values on assignment line #93464

Closed
huwcbjones opened this issue Jun 3, 2022 · 7 comments
Assignees
Labels
3.12 bugs and security fixes stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error

Comments

@huwcbjones
Copy link

huwcbjones commented Jun 3, 2022

Bug report

Creating a Enum that uses automatic values and tuple assignment doesn't work!

from enum import Enum, auto
from typing import Any

class Day(Enum):
    def __new__(cls, value, abbr=None):
        obj = Enum.__new__(cls, value)
        obj.abbr = abbr
        return obj

    @staticmethod
    def _generate_next_value_(name: str, start: int, count: int, last_values: list[Any]) -> Any:
        return name

    MONDAY = auto(), "Mon"
    # etc

print(Day.MONDAY, Day.MONDAY.value, Day.MONDAY.abbr)

Run that snippet and you get

Traceback (most recent call last):
  File "mwe.py", line 5, in 
    class Day(Enum):
  File "lib/python3.9/enum.py", line 288, in __new__
    enum_member = __new__(enum_class, *args)
  File "mwe.py", line 8, in __new__
    obj = Enum.__new__(cls, value)
  File "lib/python3.9/enum.py", line 702, in __new__
    raise ve_exc
ValueError: <enum.auto object at 0x10b673fa0> is not a valid Day

Your environment

  • CPython versions tested on: 3.9.2/3.9.7/3.10.2
  • Operating system and architecture: Debian 11 (amd64)/macOS 11.4 (amd64)
@huwcbjones huwcbjones added the type-bug An unexpected behavior, bug, or error label Jun 3, 2022
@huwcbjones
Copy link
Author

huwcbjones commented Jun 3, 2022

You can bodge around this by replacing the tuple definition + __new__ with a map+property but that feels digusting

from enum import Enum, auto
from typing import Any

class Day(Enum):

    def _generate_next_value_(name: str, start: int, count: int, last_values: list[Any]) -> Any:
        return name

    MONDAY = auto()
    # etc

    @property
    def abbr(self):
        return {
            self.MONDAY: "Mon",
            # etc
        }[self]

print(Day.MONDAY, Day.MONDAY.value, Day.MONDAY.abbr)

prints

Day.MONDAY MONDAY Mon

as expected

@ethanfurman ethanfurman added invalid and removed type-bug An unexpected behavior, bug, or error labels Jun 3, 2022
@ethanfurman
Copy link
Member

"auto" is short for automatic, the idea being that you don't need to type anything beyound auto() on the member assignment line.

If you are adding more on the assignment line, such as , "Mon", then auto() is not the right tool.

@huwcbjones
Copy link
Author

auto() is not the right tool.

As the current docs say

If the exact value is unimportant you can use auto:

I didn't care about the exact value in the "complicated" tuple assignment, hence attempting to using auto.
Would it be possible to update the docs to reflect that then as this is clearly not the case?

If it had been documented that doing auto is for "simple" things, then I wouldn't have opened this issue and also wouldn't have sunk half a day trying to monkey patch the ever living shit out of Enum to try to make it work 🙃

@ethanfurman ethanfurman added docs Documentation in the Doc dir and removed invalid labels Jun 3, 2022
@ethanfurman ethanfurman changed the title Enum: auto and tuple assignment doesn't work Enum: clarify that auto() is the only allowed object (i.e. cannot be combined with other values on assignment line) Jun 3, 2022
@ethanfurman
Copy link
Member

Fair point. You may also want to check out my aenum library. Using it would look like:

class Day(Enum):
    def __new__(cls, value, abbr=None):
        obj = Enum.__new__(cls, value)
        obj.abbr = abbr
        return obj

    @staticmethod
    def _generate_next_value_(name: str, start: int, count: int, last_values: list[Any]) -> Any:
        return name

    MONDAY = auto(abbr="Mon")

@ethanfurman ethanfurman reopened this Jun 3, 2022
@huwcbjones
Copy link
Author

You may also want to check out my aenum library

Ta, shall have a look :)

@d0sboots
Copy link

d0sboots commented Oct 19, 2022

Just ran into the same issue. There's nothing whatsoever in the docs that would lead you to believe that auto() isn't a simple function that calls _generate_next_value_. And the docs say "If the exact value is unimportant you can use auto," which was precisely my use case: I don't care about the value, but I want to also specify additional data which has specifics that I do care about.

In my case, it was easier to just manually specify the values (even though I don't care about them), rather than try to work around the issues of auto().

An example of such "simple" use of auto that ideally would work:

from enum import Enum, auto

class FoodEnum(Enum):
    KETCHUP = auto(), "red"
    MAYO = auto(), "white"
    PICKLES = auto(), "green"
    POPCORN = auto(), "white"

    def __init__(self, value, color):
        self._value_ = value
        self.color = color

print(repr(FoodEnum.MAYO))

@ethanfurman ethanfurman self-assigned this Oct 19, 2022
@ethanfurman
Copy link
Member

I am convinced that auto() should always call _generate_next_value_ -- reclassifying as a bug.

@ethanfurman ethanfurman added type-bug An unexpected behavior, bug, or error stdlib Python modules in the Lib dir 3.12 bugs and security fixes and removed docs Documentation in the Doc dir labels Oct 24, 2022
@ethanfurman ethanfurman changed the title Enum: clarify that auto() is the only allowed object (i.e. cannot be combined with other values on assignment line) Enum: auto() is not activated if combined with other values on assignment line Oct 25, 2022
ethanfurman added a commit that referenced this issue Nov 6, 2022
)

* fix auto() failure during multiple assignment

i.e. `ONE = auto(), 'text'` will now have `ONE' with the value of `(1,
'text')`.  Before it would have been `(<an auto instance>, 'text')`
miss-islington pushed a commit to miss-islington/cpython that referenced this issue Nov 6, 2022
…ythonGH-99148)

* fix auto() failure during multiple assignment

i.e. `ONE = auto(), 'text'` will now have `ONE' with the value of `(1,
'text')`.  Before it would have been `(<an auto instance>, 'text')`
(cherry picked from commit 8feb7ab)

Co-authored-by: Ethan Furman <ethan@stoneleaf.us>
miss-islington added a commit that referenced this issue Nov 6, 2022
)

* fix auto() failure during multiple assignment

i.e. `ONE = auto(), 'text'` will now have `ONE' with the value of `(1,
'text')`.  Before it would have been `(<an auto instance>, 'text')`
(cherry picked from commit 8feb7ab)

Co-authored-by: Ethan Furman <ethan@stoneleaf.us>
hugovk pushed a commit that referenced this issue Dec 5, 2022
Co-authored-by: C.A.M. Gerlach <CAM.Gerlach@Gerlach.CAM>
miss-islington pushed a commit to miss-islington/cpython that referenced this issue Dec 5, 2022
(cherry picked from commit e3a3863)

Co-authored-by: Ethan Furman <ethan@stoneleaf.us>
Co-authored-by: C.A.M. Gerlach <CAM.Gerlach@Gerlach.CAM>
miss-islington added a commit that referenced this issue Dec 5, 2022
(cherry picked from commit e3a3863)

Co-authored-by: Ethan Furman <ethan@stoneleaf.us>
Co-authored-by: C.A.M. Gerlach <CAM.Gerlach@Gerlach.CAM>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3.12 bugs and security fixes stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

3 participants