Skip to content

Commit 3064dbf

Browse files
authored
bpo-41517: do not allow Enums to be extended (python#22271)
fix bug that let Enums be extended via multiple inheritance
1 parent 0705ec8 commit 3064dbf

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
@@ -124,10 +124,12 @@ class EnumMeta(type):
124124
"""Metaclass for Enum"""
125125
@classmethod
126126
def __prepare__(metacls, cls, bases):
127+
# check that previous enum members do not exist
128+
metacls._check_for_existing_members(cls, bases)
127129
# create the namespace dict
128130
enum_dict = _EnumDict()
129131
# inherit previous flags and _generate_next_value_ function
130-
member_type, first_enum = metacls._get_mixins_(bases)
132+
member_type, first_enum = metacls._get_mixins_(cls, bases)
131133
if first_enum is not None:
132134
enum_dict['_generate_next_value_'] = getattr(first_enum, '_generate_next_value_', None)
133135
return enum_dict
@@ -143,7 +145,7 @@ def __new__(metacls, cls, bases, classdict):
143145
ignore = classdict['_ignore_']
144146
for key in ignore:
145147
classdict.pop(key, None)
146-
member_type, first_enum = metacls._get_mixins_(bases)
148+
member_type, first_enum = metacls._get_mixins_(cls, bases)
147149
__new__, save_new, use_args = metacls._find_new_(classdict, member_type,
148150
first_enum)
149151

@@ -402,7 +404,7 @@ def _create_(cls, class_name, names, *, module=None, qualname=None, type=None, s
402404
"""
403405
metacls = cls.__class__
404406
bases = (cls, ) if type is None else (type, cls)
405-
_, first_enum = cls._get_mixins_(bases)
407+
_, first_enum = cls._get_mixins_(cls, bases)
406408
classdict = metacls.__prepare__(class_name, bases)
407409

408410
# special processing needed for names?
@@ -475,7 +477,14 @@ def _convert_(cls, name, module, filter, source=None):
475477
return cls
476478

477479
@staticmethod
478-
def _get_mixins_(bases):
480+
def _check_for_existing_members(class_name, bases):
481+
for chain in bases:
482+
for base in chain.__mro__:
483+
if issubclass(base, Enum) and base._member_names_:
484+
raise TypeError("%s: cannot extend enumeration %r" % (class_name, base.__name__))
485+
486+
@staticmethod
487+
def _get_mixins_(class_name, bases):
479488
"""Returns the type for creating enum members, and the first inherited
480489
enum class.
481490
@@ -500,7 +509,7 @@ def _find_data_type(bases):
500509
elif not issubclass(base, Enum):
501510
candidate = base
502511
if len(data_types) > 1:
503-
raise TypeError('too many data types: %r' % data_types)
512+
raise TypeError('%r: too many data types: %r' % (class_name, data_types))
504513
elif data_types:
505514
return data_types[0]
506515
else:

Lib/test/test_enum.py

+3
Original file line numberDiff line numberDiff line change
@@ -1009,6 +1009,9 @@ class MoreColor(Color):
10091009
cyan = 4
10101010
magenta = 5
10111011
yellow = 6
1012+
with self.assertRaisesRegex(TypeError, "EvenMoreColor: cannot extend enumeration 'Color'"):
1013+
class EvenMoreColor(Color, IntEnum):
1014+
chartruese = 7
10121015

10131016
def test_exclude_methods(self):
10141017
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)