[Python-checkins] bpo-41517: do not allow Enums to be extended (#22271)

Ethan Furman webhook-mailer at python.org
Wed Sep 16 10:12:05 EDT 2020


https://github.com/python/cpython/commit/3064dbf5df1021e85b507366a7ea448c8895efe7
commit: 3064dbf5df1021e85b507366a7ea448c8895efe7
branch: master
author: Ethan Furman <ethan at stoneleaf.us>
committer: GitHub <noreply at github.com>
date: 2020年09月16日T07:11:57-07:00
summary:
bpo-41517: do not allow Enums to be extended (#22271)
fix bug that let Enums be extended via multiple inheritance
files:
A Misc/NEWS.d/next/Library/2020-09-15-22-43-30.bpo-41517.sLBH7g.rst
M Lib/enum.py
M Lib/test/test_enum.py
diff --git a/Lib/enum.py b/Lib/enum.py
index e72d306267461..0c2cf569fac88 100644
--- a/Lib/enum.py
+++ b/Lib/enum.py
@@ -124,10 +124,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
@@ -143,7 +145,7 @@ def __new__(metacls, cls, bases, classdict):
 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)
 
@@ -402,7 +404,7 @@ def _create_(cls, class_name, names, *, module=None, qualname=None, type=None, s
 """
 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?
@@ -475,7 +477,14 @@ def _convert_(cls, name, module, filter, source=None):
 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.
 
@@ -500,7 +509,7 @@ def _find_data_type(bases):
 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 865edf1d9cfc6..2fcd047989afb 100644
--- a/Lib/test/test_enum.py
+++ b/Lib/test/test_enum.py
@@ -1009,6 +1009,9 @@ class MoreColor(Color):
 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):
diff --git a/Misc/NEWS.d/next/Library/2020-09-15-22-43-30.bpo-41517.sLBH7g.rst b/Misc/NEWS.d/next/Library/2020-09-15-22-43-30.bpo-41517.sLBH7g.rst
new file mode 100644
index 0000000000000..e7654711062ce
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2020-09-15-22-43-30.bpo-41517.sLBH7g.rst
@@ -0,0 +1 @@
+fix bug allowing Enums to be extended via multiple inheritance


More information about the Python-checkins mailing list

AltStyle によって変換されたページ (->オリジナル) /