Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 304ec53

Browse files
bpo-44356: [Enum] allow multiple data-type mixins if they are all the same (GH-26649) (GH-26652)
This enables, for example, two base Enums to both inherit from `str`, and then both be mixed into the same final Enum: class Str1Enum(str, Enum): GH- some behavior here class Str2Enum(str, Enum): GH- some more behavior here class FinalStrEnum(Str1Enum, Str2Enum): GH- this now works (cherry picked from commit 8a4f085) Co-authored-by: Ethan Furman <[email protected]> Co-authored-by: Ethan Furman <[email protected]>
1 parent 175ebc6 commit 304ec53

File tree

3 files changed

+52
-4
lines changed

3 files changed

+52
-4
lines changed

Lib/enum.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -556,27 +556,27 @@ def _get_mixins_(class_name, bases):
556556
return object, Enum
557557

558558
def _find_data_type(bases):
559-
data_types = []
559+
data_types = set()
560560
for chain in bases:
561561
candidate = None
562562
for base in chain.__mro__:
563563
if base is object:
564564
continue
565565
elif issubclass(base, Enum):
566566
if base._member_type_ is not object:
567-
data_types.append(base._member_type_)
567+
data_types.add(base._member_type_)
568568
break
569569
elif '__new__' in base.__dict__:
570570
if issubclass(base, Enum):
571571
continue
572-
data_types.append(candidate or base)
572+
data_types.add(candidate or base)
573573
break
574574
else:
575575
candidate = base
576576
if len(data_types) > 1:
577577
raise TypeError('%r: too many data types: %r' % (class_name, data_types))
578578
elif data_types:
579-
return data_types[0]
579+
return data_types.pop()
580580
else:
581581
return None
582582

Lib/test/test_enum.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2072,6 +2072,53 @@ def __new__(cls, value):
20722072
return member
20732073
self.assertEqual(Fee.TEST, 2)
20742074

2075+
def test_miltuple_mixin_with_common_data_type(self):
2076+
class CaseInsensitiveStrEnum(str, Enum):
2077+
@classmethod
2078+
def _missing_(cls, value):
2079+
for member in cls._member_map_.values():
2080+
if member._value_.lower() == value.lower():
2081+
return member
2082+
return super()._missing_(value)
2083+
#
2084+
class LenientStrEnum(str, Enum):
2085+
def __init__(self, *args):
2086+
self._valid = True
2087+
@classmethod
2088+
def _missing_(cls, value):
2089+
# encountered an unknown value!
2090+
# Luckily I'm a LenientStrEnum, so I won't crash just yet.
2091+
# You might want to add a new case though.
2092+
unknown = cls._member_type_.__new__(cls, value)
2093+
unknown._valid = False
2094+
unknown._name_ = value.upper()
2095+
unknown._value_ = value
2096+
cls._member_map_[value] = unknown
2097+
return unknown
2098+
@property
2099+
def valid(self):
2100+
return self._valid
2101+
#
2102+
class JobStatus(CaseInsensitiveStrEnum, LenientStrEnum):
2103+
ACTIVE = "active"
2104+
PENDING = "pending"
2105+
TERMINATED = "terminated"
2106+
#
2107+
JS = JobStatus
2108+
self.assertEqual(list(JobStatus), [JS.ACTIVE, JS.PENDING, JS.TERMINATED])
2109+
self.assertEqual(JS.ACTIVE, 'active')
2110+
self.assertEqual(JS.ACTIVE.value, 'active')
2111+
self.assertIs(JS('Active'), JS.ACTIVE)
2112+
self.assertTrue(JS.ACTIVE.valid)
2113+
missing = JS('missing')
2114+
self.assertEqual(list(JobStatus), [JS.ACTIVE, JS.PENDING, JS.TERMINATED])
2115+
self.assertEqual(JS.ACTIVE, 'active')
2116+
self.assertEqual(JS.ACTIVE.value, 'active')
2117+
self.assertIs(JS('Active'), JS.ACTIVE)
2118+
self.assertTrue(JS.ACTIVE.valid)
2119+
self.assertTrue(isinstance(missing, JS))
2120+
self.assertFalse(missing.valid)
2121+
20752122
def test_empty_globals(self):
20762123
# bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
20772124
# when using compile and exec because f_globals is empty
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[Enum] Allow multiple data-type mixins if they are all the same.

0 commit comments

Comments
 (0)