bpo-39587: Enum - use correct mixed-in data type (GH-22263)

This commit is contained in:
Ethan Furman 2020-09-15 15:56:26 -07:00 committed by GitHub
parent 2e87774df1
commit bff01f3a3a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 56 additions and 1 deletions

View File

@ -482,14 +482,25 @@ class EnumMeta(type):
return object, Enum return object, Enum
def _find_data_type(bases): def _find_data_type(bases):
data_types = []
for chain in bases: for chain in bases:
candidate = None
for base in chain.__mro__: for base in chain.__mro__:
if base is object: if base is object:
continue continue
elif '__new__' in base.__dict__: elif '__new__' in base.__dict__:
if issubclass(base, Enum): if issubclass(base, Enum):
continue 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 # ensure final parent class is an Enum derivative, find any concrete
# data type, and check that Enum has no members # data type, and check that Enum has no members

View File

@ -560,6 +560,49 @@ class TestEnum(unittest.TestCase):
self.assertFormatIsValue('{:>20}', Directional.WEST) self.assertFormatIsValue('{:>20}', Directional.WEST)
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), '<MyEnum.A: 0x1>')
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): def test_hash(self):
Season = self.Season Season = self.Season
dates = {} dates = {}

View File

@ -0,0 +1 @@
use the correct mix-in data type when constructing Enums