bpo-41517: do not allow Enums to be extended (GH-22271)
fix bug that let Enums be extended via multiple inheritance
(cherry picked from commit 3064dbf5df
)
Co-authored-by: Ethan Furman <ethan@stoneleaf.us>
This commit is contained in:
parent
6a39888c2c
commit
48f99250ff
19
Lib/enum.py
19
Lib/enum.py
|
@ -123,10 +123,12 @@ class EnumMeta(type):
|
|||
"""Metaclass for Enum"""
|
||||
@classmethod
|
||||
def __prepare__(metacls, cls, bases):
|
||||
# check that previous enum members do not exist
|
||||
metacls._check_for_existing_members(cls, bases)
|
||||
# create the namespace dict
|
||||
enum_dict = _EnumDict()
|
||||
# inherit previous flags and _generate_next_value_ function
|
||||
member_type, first_enum = metacls._get_mixins_(bases)
|
||||
member_type, first_enum = metacls._get_mixins_(cls, bases)
|
||||
if first_enum is not None:
|
||||
enum_dict['_generate_next_value_'] = getattr(first_enum, '_generate_next_value_', None)
|
||||
return enum_dict
|
||||
|
@ -142,7 +144,7 @@ class EnumMeta(type):
|
|||
ignore = classdict['_ignore_']
|
||||
for key in ignore:
|
||||
classdict.pop(key, None)
|
||||
member_type, first_enum = metacls._get_mixins_(bases)
|
||||
member_type, first_enum = metacls._get_mixins_(cls, bases)
|
||||
__new__, save_new, use_args = metacls._find_new_(classdict, member_type,
|
||||
first_enum)
|
||||
|
||||
|
@ -401,7 +403,7 @@ class EnumMeta(type):
|
|||
"""
|
||||
metacls = cls.__class__
|
||||
bases = (cls, ) if type is None else (type, cls)
|
||||
_, first_enum = cls._get_mixins_(bases)
|
||||
_, first_enum = cls._get_mixins_(cls, bases)
|
||||
classdict = metacls.__prepare__(class_name, bases)
|
||||
|
||||
# special processing needed for names?
|
||||
|
@ -474,7 +476,14 @@ class EnumMeta(type):
|
|||
return cls
|
||||
|
||||
@staticmethod
|
||||
def _get_mixins_(bases):
|
||||
def _check_for_existing_members(class_name, bases):
|
||||
for chain in bases:
|
||||
for base in chain.__mro__:
|
||||
if issubclass(base, Enum) and base._member_names_:
|
||||
raise TypeError("%s: cannot extend enumeration %r" % (class_name, base.__name__))
|
||||
|
||||
@staticmethod
|
||||
def _get_mixins_(class_name, bases):
|
||||
"""Returns the type for creating enum members, and the first inherited
|
||||
enum class.
|
||||
|
||||
|
@ -499,7 +508,7 @@ class EnumMeta(type):
|
|||
elif not issubclass(base, Enum):
|
||||
candidate = base
|
||||
if len(data_types) > 1:
|
||||
raise TypeError('too many data types: %r' % data_types)
|
||||
raise TypeError('%r: too many data types: %r' % (class_name, data_types))
|
||||
elif data_types:
|
||||
return data_types[0]
|
||||
else:
|
||||
|
|
|
@ -1001,6 +1001,9 @@ class TestEnum(unittest.TestCase):
|
|||
cyan = 4
|
||||
magenta = 5
|
||||
yellow = 6
|
||||
with self.assertRaisesRegex(TypeError, "EvenMoreColor: cannot extend enumeration 'Color'"):
|
||||
class EvenMoreColor(Color, IntEnum):
|
||||
chartruese = 7
|
||||
|
||||
def test_exclude_methods(self):
|
||||
class whatever(Enum):
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
fix bug allowing Enums to be extended via multiple inheritance
|
Loading…
Reference in New Issue