From c266736ec1f9ebef38b134ceb4832df015711b38 Mon Sep 17 00:00:00 2001 From: Ethan Furman Date: Mon, 7 Dec 2020 00:17:31 -0800 Subject: bpo-41889: [Enum] fix multiple-inheritance regression (GH-22487) --- Lib/enum.py | 11 ++++++--- Lib/test/test_enum.py | 26 ++++++++++++++++++++++ .../2020-10-01-16-17-11.bpo-41889.qLkNh8.rst | 1 + 3 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-10-01-16-17-11.bpo-41889.qLkNh8.rst diff --git a/Lib/enum.py b/Lib/enum.py index 40ff25b..d670ad7 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -146,8 +146,9 @@ class EnumMeta(type): for key in ignore: classdict.pop(key, None) member_type, first_enum = metacls._get_mixins_(cls, bases) - __new__, save_new, use_args = metacls._find_new_(classdict, member_type, - first_enum) + __new__, save_new, use_args = metacls._find_new_( + classdict, member_type, first_enum, + ) # save enum items into separate mapping so they don't get baked into # the new class @@ -501,12 +502,16 @@ class EnumMeta(type): for base in chain.__mro__: if base is object: continue + elif issubclass(base, Enum): + if base._member_type_ is not object: + data_types.append(base._member_type_) + break elif '__new__' in base.__dict__: if issubclass(base, Enum): continue data_types.append(candidate or base) break - elif not issubclass(base, Enum): + else: candidate = base if len(data_types) > 1: raise TypeError('%r: too many data types: %r' % (class_name, data_types)) diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index 3431040..d1dd2e7 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -2021,6 +2021,32 @@ class TestEnum(unittest.TestCase): REVERT_ALL = "REVERT_ALL" RETRY = "RETRY" + def test_multiple_mixin_inherited(self): + class MyInt(int): + def __new__(cls, value): + return super().__new__(cls, value) + + class HexMixin: + def __repr__(self): + return hex(self) + + class MyIntEnum(HexMixin, MyInt, enum.Enum): + pass + + class Foo(MyIntEnum): + TEST = 1 + self.assertTrue(isinstance(Foo.TEST, MyInt)) + self.assertEqual(repr(Foo.TEST), "0x1") + + class Fee(MyIntEnum): + TEST = 1 + def __new__(cls, value): + value += 1 + member = int.__new__(cls, value) + member._value_ = value + return member + self.assertEqual(Fee.TEST, 2) + def test_empty_globals(self): # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError # when using compile and exec because f_globals is empty diff --git a/Misc/NEWS.d/next/Library/2020-10-01-16-17-11.bpo-41889.qLkNh8.rst b/Misc/NEWS.d/next/Library/2020-10-01-16-17-11.bpo-41889.qLkNh8.rst new file mode 100644 index 0000000..768865a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-10-01-16-17-11.bpo-41889.qLkNh8.rst @@ -0,0 +1 @@ +Enum: fix regression involving inheriting a multiply-inherited enum -- cgit v0.12