diff --git a/Lib/enum.py b/Lib/enum.py index bc24f2ae2df..5e0088ee89f 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -482,14 +482,25 @@ class EnumMeta(type): return object, Enum def _find_data_type(bases): + data_types = [] for chain in bases: + candidate = None for base in chain.__mro__: if base is object: continue elif '__new__' in base.__dict__: if issubclass(base, Enum): continue - return base + data_types.append(candidate or base) + break + elif not issubclass(base, Enum): + candidate = base + if len(data_types) > 1: + raise TypeError('too many data types: %r' % data_types) + elif data_types: + return data_types[0] + else: + return None # ensure final parent class is an Enum derivative, find any concrete # data type, and check that Enum has no members diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index 138f572906a..a909c108833 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -560,6 +560,49 @@ class TestEnum(unittest.TestCase): self.assertFormatIsValue('{:>20}', Directional.WEST) self.assertFormatIsValue('{:<20}', Directional.WEST) + def test_enum_str_override(self): + class MyStrEnum(Enum): + def __str__(self): + return 'MyStr' + class MyMethodEnum(Enum): + def hello(self): + return 'Hello! My name is %s' % self.name + class Test1Enum(MyMethodEnum, int, MyStrEnum): + One = 1 + Two = 2 + self.assertEqual(str(Test1Enum.One), 'MyStr') + # + class Test2Enum(MyStrEnum, MyMethodEnum): + One = 1 + Two = 2 + self.assertEqual(str(Test2Enum.One), 'MyStr') + + def test_inherited_data_type(self): + class HexInt(int): + def __repr__(self): + return hex(self) + class MyEnum(HexInt, enum.Enum): + A = 1 + B = 2 + C = 3 + self.assertEqual(repr(MyEnum.A), '') + + def test_too_many_data_types(self): + with self.assertRaisesRegex(TypeError, 'too many data types'): + class Huh(str, int, Enum): + One = 1 + + class MyStr(str): + def hello(self): + return 'hello, %s' % self + class MyInt(int): + def repr(self): + return hex(self) + with self.assertRaisesRegex(TypeError, 'too many data types'): + class Huh(MyStr, MyInt, Enum): + One = 1 + + def test_hash(self): Season = self.Season dates = {} diff --git a/Misc/NEWS.d/next/Library/2020-09-15-14-56-13.bpo-39587.69xzuh.rst b/Misc/NEWS.d/next/Library/2020-09-15-14-56-13.bpo-39587.69xzuh.rst new file mode 100644 index 00000000000..e2f2b64867b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-09-15-14-56-13.bpo-39587.69xzuh.rst @@ -0,0 +1 @@ +use the correct mix-in data type when constructing Enums