Skip to content

Commit 48f9925

Browse files
bpo-41517: do not allow Enums to be extended (pythonGH-22271)
fix bug that let Enums be extended via multiple inheritance (cherry picked from commit 3064dbf) Co-authored-by: Ethan Furman <ethan@stoneleaf.us>
1 parent 6a39888 commit 48f9925

File tree

3 files changed

+18
-5
lines changed

3 files changed

+18
-5
lines changed

Lib/enum.py

+14-5
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,12 @@ class EnumMeta(type):
123123
"""Metaclass for Enum"""
124124
@classmethod
125125
def __prepare__(metacls, cls, bases):
126+
# check that previous enum members do not exist
127+
metacls._check_for_existing_members(cls, bases)
126128
# create the namespace dict
127129
enum_dict = _EnumDict()
128130
# inherit previous flags and _generate_next_value_ function
129-
member_type, first_enum = metacls._get_mixins_(bases)
131+
member_type, first_enum = metacls._get_mixins_(cls, bases)
130132
if first_enum is not None:
131133
enum_dict['_generate_next_value_'] = getattr(first_enum, '_generate_next_value_', None)
132134
return enum_dict
@@ -142,7 +144,7 @@ def __new__(metacls, cls, bases, classdict):
142144
ignore = classdict['_ignore_']
143145
for key in ignore:
144146
classdict.pop(key, None)
145-
member_type, first_enum = metacls._get_mixins_(bases)
147+
member_type, first_enum = metacls._get_mixins_(cls, bases)
146148
__new__, save_new, use_args = metacls._find_new_(classdict, member_type,
147149
first_enum)
148150

@@ -401,7 +403,7 @@ def _create_(cls, class_name, names, *, module=None, qualname=None, type=None, s
401403
"""
402404
metacls = cls.__class__
403405
bases = (cls, ) if type is None else (type, cls)
404-
_, first_enum = cls._get_mixins_(bases)
406+
_, first_enum = cls._get_mixins_(cls, bases)
405407
classdict = metacls.__prepare__(class_name, bases)
406408

407409
# special processing needed for names?
@@ -474,7 +476,14 @@ def _convert_(cls, name, module, filter, source=None):
474476
return cls
475477

476478
@staticmethod
477-
def _get_mixins_(bases):
479+
def _check_for_existing_members(class_name, bases):
480+
for chain in bases:
481+
for base in chain.__mro__:
482+
if issubclass(base, Enum) and base._member_names_:
483+
raise TypeError("%s: cannot extend enumeration %r" % (class_name, base.__name__))
484+
485+
@staticmethod
486+
def _get_mixins_(class_name, bases):
478487
"""Returns the type for creating enum members, and the first inherited
479488
enum class.
480489
@@ -499,7 +508,7 @@ def _find_data_type(bases):
499508
elif not issubclass(base, Enum):
500509
candidate = base
501510
if len(data_types) > 1:
502-
raise TypeError('too many data types: %r' % data_types)
511+
raise TypeError('%r: too many data types: %r' % (class_name, data_types))
503512
elif data_types:
504513
return data_types[0]
505514
else:

Lib/test/test_enum.py

+3
Original file line numberDiff line numberDiff line change
@@ -1001,6 +1001,9 @@ class MoreColor(Color):
10011001
cyan = 4
10021002
magenta = 5
10031003
yellow = 6
1004+
with self.assertRaisesRegex(TypeError, "EvenMoreColor: cannot extend enumeration 'Color'"):
1005+
class EvenMoreColor(Color, IntEnum):
1006+
chartruese = 7
10041007

10051008
def test_exclude_methods(self):
10061009
class whatever(Enum):
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
fix bug allowing Enums to be extended via multiple inheritance

0 commit comments

Comments
 (0)