bpo-41517: do not allow Enums to be extended (#22271)
fix bug that let Enums be extended via multiple inheritance
This commit is contained in:
parent
0705ec8a14
commit
3064dbf5df
19
Lib/enum.py
19
Lib/enum.py
|
@ -124,10 +124,12 @@ class EnumMeta(type):
|
||||||
"""Metaclass for Enum"""
|
"""Metaclass for Enum"""
|
||||||
@classmethod
|
@classmethod
|
||||||
def __prepare__(metacls, cls, bases):
|
def __prepare__(metacls, cls, bases):
|
||||||
|
# check that previous enum members do not exist
|
||||||
|
metacls._check_for_existing_members(cls, bases)
|
||||||
# create the namespace dict
|
# create the namespace dict
|
||||||
enum_dict = _EnumDict()
|
enum_dict = _EnumDict()
|
||||||
# inherit previous flags and _generate_next_value_ function
|
# 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:
|
if first_enum is not None:
|
||||||
enum_dict['_generate_next_value_'] = getattr(first_enum, '_generate_next_value_', None)
|
enum_dict['_generate_next_value_'] = getattr(first_enum, '_generate_next_value_', None)
|
||||||
return enum_dict
|
return enum_dict
|
||||||
|
@ -143,7 +145,7 @@ class EnumMeta(type):
|
||||||
ignore = classdict['_ignore_']
|
ignore = classdict['_ignore_']
|
||||||
for key in ignore:
|
for key in ignore:
|
||||||
classdict.pop(key, None)
|
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,
|
__new__, save_new, use_args = metacls._find_new_(classdict, member_type,
|
||||||
first_enum)
|
first_enum)
|
||||||
|
|
||||||
|
@ -402,7 +404,7 @@ class EnumMeta(type):
|
||||||
"""
|
"""
|
||||||
metacls = cls.__class__
|
metacls = cls.__class__
|
||||||
bases = (cls, ) if type is None else (type, cls)
|
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)
|
classdict = metacls.__prepare__(class_name, bases)
|
||||||
|
|
||||||
# special processing needed for names?
|
# special processing needed for names?
|
||||||
|
@ -475,7 +477,14 @@ class EnumMeta(type):
|
||||||
return cls
|
return cls
|
||||||
|
|
||||||
@staticmethod
|
@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
|
"""Returns the type for creating enum members, and the first inherited
|
||||||
enum class.
|
enum class.
|
||||||
|
|
||||||
|
@ -500,7 +509,7 @@ class EnumMeta(type):
|
||||||
elif not issubclass(base, Enum):
|
elif not issubclass(base, Enum):
|
||||||
candidate = base
|
candidate = base
|
||||||
if len(data_types) > 1:
|
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:
|
elif data_types:
|
||||||
return data_types[0]
|
return data_types[0]
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -1009,6 +1009,9 @@ class TestEnum(unittest.TestCase):
|
||||||
cyan = 4
|
cyan = 4
|
||||||
magenta = 5
|
magenta = 5
|
||||||
yellow = 6
|
yellow = 6
|
||||||
|
with self.assertRaisesRegex(TypeError, "EvenMoreColor: cannot extend enumeration 'Color'"):
|
||||||
|
class EvenMoreColor(Color, IntEnum):
|
||||||
|
chartruese = 7
|
||||||
|
|
||||||
def test_exclude_methods(self):
|
def test_exclude_methods(self):
|
||||||
class whatever(Enum):
|
class whatever(Enum):
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
fix bug allowing Enums to be extended via multiple inheritance
|
Loading…
Reference in New Issue