summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>2020-09-16 14:35:14 (GMT)
committerGitHub <noreply@github.com>2020-09-16 14:35:14 (GMT)
commit48f99250ff319e36b15b555128cd62e408d8165f (patch)
treeb2d3308cfff3bce8a0e83a999ad8b074baa99ce5 /Lib
parent6a39888c2c4bcfbcdc61a1953911ad30c62da1ef (diff)
downloadcpython-48f99250ff319e36b15b555128cd62e408d8165f.zip
cpython-48f99250ff319e36b15b555128cd62e408d8165f.tar.gz
cpython-48f99250ff319e36b15b555128cd62e408d8165f.tar.bz2
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 3064dbf5df1021e85b507366a7ea448c8895efe7) Co-authored-by: Ethan Furman <ethan@stoneleaf.us>
Diffstat (limited to 'Lib')
-rw-r--r--Lib/enum.py19
-rw-r--r--Lib/test/test_enum.py3
2 files changed, 17 insertions, 5 deletions
diff --git a/Lib/enum.py b/Lib/enum.py
index 8711558..bdbfbb6 100644
--- a/Lib/enum.py
+++ b/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:
diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py
index 0983513..0ecf641 100644
--- a/Lib/test/test_enum.py
+++ b/Lib/test/test_enum.py
@@ -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):