Skip to content

Commit 8f8ebcc

Browse files
bpo-39587: Enum - use correct mixed-in data type (GH-22263)
(cherry picked from commit bff01f3) Co-authored-by: Ethan Furman <[email protected]>
1 parent 5fdc142 commit 8f8ebcc

File tree

3 files changed

+56
-1
lines changed

3 files changed

+56
-1
lines changed

‎Lib/enum.py‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -487,14 +487,25 @@ def _get_mixins_(bases):
487487
return object, Enum
488488

489489
def _find_data_type(bases):
490+
data_types = []
490491
for chain in bases:
492+
candidate = None
491493
for base in chain.__mro__:
492494
if base is object:
493495
continue
494496
elif '__new__' in base.__dict__:
495497
if issubclass(base, Enum):
496498
continue
497-
return base
499+
data_types.append(candidate or base)
500+
break
501+
elif not issubclass(base, Enum):
502+
candidate = base
503+
if len(data_types) > 1:
504+
raise TypeError('too many data types: %r' % data_types)
505+
elif data_types:
506+
return data_types[0]
507+
else:
508+
return None
498509

499510
# ensure final parent class is an Enum derivative, find any concrete
500511
# data type, and check that Enum has no members

‎Lib/test/test_enum.py‎

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,49 @@ def test_format_enum_str(self):
551551
self.assertFormatIsValue('{:>20}', Directional.WEST)
552552
self.assertFormatIsValue('{:<20}', Directional.WEST)
553553

554+
def test_enum_str_override(self):
555+
class MyStrEnum(Enum):
556+
def __str__(self):
557+
return 'MyStr'
558+
class MyMethodEnum(Enum):
559+
def hello(self):
560+
return 'Hello! My name is %s' % self.name
561+
class Test1Enum(MyMethodEnum, int, MyStrEnum):
562+
One = 1
563+
Two = 2
564+
self.assertEqual(str(Test1Enum.One), 'MyStr')
565+
#
566+
class Test2Enum(MyStrEnum, MyMethodEnum):
567+
One = 1
568+
Two = 2
569+
self.assertEqual(str(Test2Enum.One), 'MyStr')
570+
571+
def test_inherited_data_type(self):
572+
class HexInt(int):
573+
def __repr__(self):
574+
return hex(self)
575+
class MyEnum(HexInt, enum.Enum):
576+
A = 1
577+
B = 2
578+
C = 3
579+
self.assertEqual(repr(MyEnum.A), '<MyEnum.A: 0x1>')
580+
581+
def test_too_many_data_types(self):
582+
with self.assertRaisesRegex(TypeError, 'too many data types'):
583+
class Huh(str, int, Enum):
584+
One = 1
585+
586+
class MyStr(str):
587+
def hello(self):
588+
return 'hello, %s' % self
589+
class MyInt(int):
590+
def repr(self):
591+
return hex(self)
592+
with self.assertRaisesRegex(TypeError, 'too many data types'):
593+
class Huh(MyStr, MyInt, Enum):
594+
One = 1
595+
596+
554597
def test_hash(self):
555598
Season = self.Season
556599
dates = {}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
use the correct mix-in data type when constructing Enums

0 commit comments

Comments
 (0)