From a4001995e346d06b0c505dca77ef2155a8287e84 Mon Sep 17 00:00:00 2001 From: Ethan Furman Date: Tue, 15 Sep 2020 14:41:40 -0700 Subject: [PATCH 1/2] use correct mixed-in data type --- Lib/enum.py | 13 ++++++++++++- Lib/test/test_enum.py | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/Lib/enum.py b/Lib/enum.py index bc24f2ae2dfc01..5e0088ee89fee3 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -482,14 +482,25 @@ def _get_mixins_(bases): 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 b18f3b38a6619f..f2012d3c9a4788 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -558,6 +558,49 @@ def test_format_enum_str(self): 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 = {} From 06040694afa8fe047a29f04dedfba2f4643929e6 Mon Sep 17 00:00:00 2001 From: Ethan Furman Date: Tue, 15 Sep 2020 14:56:19 -0700 Subject: [PATCH 2/2] add news entry --- .../NEWS.d/next/Library/2020-09-15-14-56-13.bpo-39587.69xzuh.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2020-09-15-14-56-13.bpo-39587.69xzuh.rst 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 00000000000000..e2f2b64867bedb --- /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