Skip to content

Commit b0dfe48

Browse files
ethanfurmanmiss-islington
authored andcommitted
pythongh-108682: [Enum] raise TypeError if super().__new__ called in custom __new__ (pythonGH-108704)
When overriding the `__new__` method of an enum, the underlying data type should be created directly; i.e. . member = object.__new__(cls) member = int.__new__(cls, value) member = str.__new__(cls, value) Calling `super().__new__()` finds the lookup version of `Enum.__new__`, and will now raise an exception when detected. (cherry picked from commit d48760b) Co-authored-by: Ethan Furman <[email protected]>
1 parent bc42d6c commit b0dfe48

File tree

4 files changed

+260
-56
lines changed

4 files changed

+260
-56
lines changed

Doc/howto/enum.rst

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,10 +426,17 @@ enumeration, with the exception of special methods (:meth:`__str__`,
426426
:meth:`__add__`, etc.), descriptors (methods are also descriptors), and
427427
variable names listed in :attr:`_ignore_`.
428428

429-
Note: if your enumeration defines :meth:`__new__` and/or :meth:`__init__` then
429+
Note: if your enumeration defines :meth:`__new__` and/or :meth:`__init__`,
430430
any value(s) given to the enum member will be passed into those methods.
431431
See `Planet`_ for an example.
432432

433+
.. note::
434+
435+
The :meth:`__new__` method, if defined, is used during creation of the Enum
436+
members; it is then replaced by Enum's :meth:`__new__` which is used after
437+
class creation for lookup of existing members. See :ref:`new-vs-init` for
438+
more details.
439+
433440

434441
Restricted Enum subclassing
435442
---------------------------
@@ -895,6 +902,8 @@ Some rules:
895902
:meth:`__str__` method has been reset to their data types'
896903
:meth:`__str__` method.
897904

905+
.. _new-vs-init:
906+
898907
When to use :meth:`__new__` vs. :meth:`__init__`
899908
------------------------------------------------
900909

@@ -927,6 +936,11 @@ want one of them to be the value::
927936
>>> print(Coordinate(3))
928937
Coordinate.VY
929938

939+
.. warning::
940+
941+
*Do not* call ``super().__new__()``, as the lookup-only ``__new__`` is the one
942+
that is found; instead, use the data type directly.
943+
930944

931945
Finer Points
932946
^^^^^^^^^^^^
@@ -1353,6 +1367,13 @@ to handle any extra arguments::
13531367
members; it is then replaced by Enum's :meth:`__new__` which is used after
13541368
class creation for lookup of existing members.
13551369

1370+
.. warning::
1371+
1372+
*Do not* call ``super().__new__()``, as the lookup-only ``__new__`` is the one
1373+
that is found; instead, use the data type directly -- e.g.::
1374+
1375+
obj = int.__new__(cls, value)
1376+
13561377

13571378
OrderedEnum
13581379
^^^^^^^^^^^

Lib/enum.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -865,6 +865,8 @@ def _create_(cls, class_name, names, *, module=None, qualname=None, type=None, s
865865
value = first_enum._generate_next_value_(name, start, count, last_values[:])
866866
last_values.append(value)
867867
names.append((name, value))
868+
if names is None:
869+
names = ()
868870

869871
# Here, names is either an iterable of (name, value) or a mapping.
870872
for item in names:
@@ -1121,6 +1123,11 @@ def __new__(cls, value):
11211123
for member in cls._member_map_.values():
11221124
if member._value_ == value:
11231125
return member
1126+
# still not found -- verify that members exist, in-case somebody got here mistakenly
1127+
# (such as via super when trying to override __new__)
1128+
if not cls._member_map_:
1129+
raise TypeError("%r has no members defined" % cls)
1130+
#
11241131
# still not found -- try _missing_ hook
11251132
try:
11261133
exc = None

0 commit comments

Comments
 (0)