summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEthan Furman <ethan@stoneleaf.us>2020-09-15 22:56:26 (GMT)
committerGitHub <noreply@github.com>2020-09-15 22:56:26 (GMT)
commitbff01f3a3aac0c15fe8fbe8b2f561f7927d117a1 (patch)
tree0b925d7fd3d5fcfd5569e26220e6def180c80a33
parent2e87774df1a0eaf2a1fe8cc4d958df60f7125b6e (diff)
downloadcpython-bff01f3a3aac0c15fe8fbe8b2f561f7927d117a1.zip
cpython-bff01f3a3aac0c15fe8fbe8b2f561f7927d117a1.tar.gz
cpython-bff01f3a3aac0c15fe8fbe8b2f561f7927d117a1.tar.bz2
bpo-39587: Enum - use correct mixed-in data type (GH-22263)
-rw-r--r--Lib/enum.py13
-rw-r--r--Lib/test/test_enum.py43
-rw-r--r--Misc/NEWS.d/next/Library/2020-09-15-14-56-13.bpo-39587.69xzuh.rst1
3 files changed, 56 insertions, 1 deletions
diff --git a/Lib/enum.py b/Lib/enum.py
index bc24f2a..5e0088e 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 138f572..a909c10 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), '<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):
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 0000000..e2f2b64
--- /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