diff options
author | Ethan Furman <ethan@stoneleaf.us> | 2021-06-10 20:30:41 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-06-10 20:30:41 (GMT) |
commit | 8a4f0850d75747af8c96ca0e7eef1f5c1abfba25 (patch) | |
tree | fde4b0f4a03765b96b3af92818fad1fe00d12b39 | |
parent | 42d5a4fc3b35e45cdd237d56a04e98894d0a31f5 (diff) | |
download | cpython-8a4f0850d75747af8c96ca0e7eef1f5c1abfba25.zip cpython-8a4f0850d75747af8c96ca0e7eef1f5c1abfba25.tar.gz cpython-8a4f0850d75747af8c96ca0e7eef1f5c1abfba25.tar.bz2 |
bpo-44356: [Enum] allow multiple data-type mixins if they are all the same (GH-26649)
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):
# some behavior here
class Str2Enum(str, Enum):
# some more behavior here
class FinalStrEnum(Str1Enum, Str2Enum):
# this now works
-rw-r--r-- | Lib/enum.py | 8 | ||||
-rw-r--r-- | Lib/test/test_enum.py | 47 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Library/2021-06-10-08-35-38.bpo-44356.6oDFhO.rst | 1 |
3 files changed, 52 insertions, 4 deletions
diff --git a/Lib/enum.py b/Lib/enum.py index f74cc8c..54633d8 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -819,7 +819,7 @@ class EnumType(type): return object, Enum def _find_data_type(bases): - data_types = [] + data_types = set() for chain in bases: candidate = None for base in chain.__mro__: @@ -827,19 +827,19 @@ class EnumType(type): continue elif issubclass(base, Enum): if base._member_type_ is not object: - data_types.append(base._member_type_) + data_types.add(base._member_type_) break elif '__new__' in base.__dict__: if issubclass(base, Enum): continue - data_types.append(candidate or base) + data_types.add(candidate or base) break else: candidate = base if len(data_types) > 1: raise TypeError('%r: too many data types: %r' % (class_name, data_types)) elif data_types: - return data_types[0] + return data_types.pop() else: return None diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index 34b190b..40794e3 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -2144,6 +2144,53 @@ class TestEnum(unittest.TestCase): return member self.assertEqual(Fee.TEST, 2) + def test_miltuple_mixin_with_common_data_type(self): + class CaseInsensitiveStrEnum(str, Enum): + @classmethod + def _missing_(cls, value): + for member in cls._member_map_.values(): + if member._value_.lower() == value.lower(): + return member + return super()._missing_(value) + # + class LenientStrEnum(str, Enum): + def __init__(self, *args): + self._valid = True + @classmethod + def _missing_(cls, value): + # encountered an unknown value! + # Luckily I'm a LenientStrEnum, so I won't crash just yet. + # You might want to add a new case though. + unknown = cls._member_type_.__new__(cls, value) + unknown._valid = False + unknown._name_ = value.upper() + unknown._value_ = value + cls._member_map_[value] = unknown + return unknown + @property + def valid(self): + return self._valid + # + class JobStatus(CaseInsensitiveStrEnum, LenientStrEnum): + ACTIVE = "active" + PENDING = "pending" + TERMINATED = "terminated" + # + JS = JobStatus + self.assertEqual(list(JobStatus), [JS.ACTIVE, JS.PENDING, JS.TERMINATED]) + self.assertEqual(JS.ACTIVE, 'active') + self.assertEqual(JS.ACTIVE.value, 'active') + self.assertIs(JS('Active'), JS.ACTIVE) + self.assertTrue(JS.ACTIVE.valid) + missing = JS('missing') + self.assertEqual(list(JobStatus), [JS.ACTIVE, JS.PENDING, JS.TERMINATED]) + self.assertEqual(JS.ACTIVE, 'active') + self.assertEqual(JS.ACTIVE.value, 'active') + self.assertIs(JS('Active'), JS.ACTIVE) + self.assertTrue(JS.ACTIVE.valid) + self.assertTrue(isinstance(missing, JS)) + self.assertFalse(missing.valid) + def test_empty_globals(self): # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError # when using compile and exec because f_globals is empty diff --git a/Misc/NEWS.d/next/Library/2021-06-10-08-35-38.bpo-44356.6oDFhO.rst b/Misc/NEWS.d/next/Library/2021-06-10-08-35-38.bpo-44356.6oDFhO.rst new file mode 100644 index 0000000..954a803 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-06-10-08-35-38.bpo-44356.6oDFhO.rst @@ -0,0 +1 @@ +[Enum] Allow multiple data-type mixins if they are all the same. |