Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Doc/howto/enum.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1353,6 +1353,13 @@ to handle any extra arguments::
members; it is then replaced by Enum's :meth:`__new__` which is used after
class creation for lookup of existing members.

.. warning::

*Do not* call `super().__new__()`, as the lookup-only `__new__` is the one
that is found; instead, use the data type directly -- e.g.::

obj = int.__new__(cls, value)


OrderedEnum
^^^^^^^^^^^
Expand Down
7 changes: 7 additions & 0 deletions Lib/enum.py
Original file line number Diff line number Diff line change
Expand Up @@ -856,6 +856,8 @@ def _create_(cls, class_name, names, *, module=None, qualname=None, type=None, s
value = first_enum._generate_next_value_(name, start, count, last_values[:])
last_values.append(value)
names.append((name, value))
if names is None:
names = ()

# Here, names is either an iterable of (name, value) or a mapping.
for item in names:
Expand Down Expand Up @@ -1112,6 +1114,11 @@ def __new__(cls, value):
for member in cls._member_map_.values():
if member._value_ == value:
return member
# still not found -- verify that members exist, in-case somebody got here mistakenly
# (such as via super when trying to override __new__)
if not cls._member_map_:
raise TypeError("%r has no members defined" % cls)
#
Comment on lines +1117 to +1121
Copy link

@tyronexj tyronexj Oct 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it ok to move _member_map_ check after _missing_ hook?
I have a derived class has no members and hook _missing_, it raise exception here.
@ethanfurman

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, no. I tried to do that, but then the bug wasn't fixed.

What does your missing() hook do?

If you have no other alternative, you'll need to subclass EnumType and override the __call__ method.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the quick reply. here is an example:

from enum import Enum

class DynamicEnum(Enum):
    @classmethod
    def _missing_(cls, value):
        temp = object.__new__(cls)
        temp._name_ = f"{cls.__name__}_{value}"
        temp._value_ = value
        return temp

dynamic_enum = DynamicEnum(3)
print(dynamic_enum)
print(dynamic_enum.value)

which prints

DynamicEnum.DynamicEnum_3
3

before this change.

As my understanding, hook _missing_ handle the missing input, a dynamic value in the above case.
so I raise the question: hook _missing_ before empty check.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll chime in here as well. I have the same question and got hit by this change as well. We have a setup where we do like:

from enum import Enum

class Result(Enum):
    @classmethod
    def _missing_(cls, value):
        v = None
        for subclass in cls.__subclasses__():
            try:
                v = subclass(value)
            except:
                pass

        return v


class CommonResult(Result):
    OK = 0
    ERR_FOO = -0x1
    ERR_BAR = -0x2

Previously, Result(0) returned CommonResult.OK. Now throws. It was a nifty pattern to use, and it sort of breaks the combination of using the _missing_ and subclasses of Enum.

# still not found -- try _missing_ hook
try:
exc = None
Expand Down
Loading