diff options
author | Ethan Furman <ethan@stoneleaf.us> | 2020-12-10 21:07:00 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-12-10 21:07:00 (GMT) |
commit | a65828717982e6a56382d7aff738478f5b5b25d0 (patch) | |
tree | c8148582ad4dc68cd969531dc64a1bee8274756b /Lib | |
parent | efb13be72cbf49edf591936fafb120fe1b7d59f7 (diff) | |
download | cpython-a65828717982e6a56382d7aff738478f5b5b25d0.zip cpython-a65828717982e6a56382d7aff738478f5b5b25d0.tar.gz cpython-a65828717982e6a56382d7aff738478f5b5b25d0.tar.bz2 |
bpo-34750: [Enum] add `_EnumDict.update()` support (GH-23725)
This allows easier Enum construction in unusual cases, such as including dynamic member definitions into a class definition:
# created dynamically
foo_defines = {'FOO_CAT': 'aloof', 'BAR_DOG': 'friendly', 'FOO_HORSE': 'big'}
class Foo(Enum):
vars().update({
k: v
for k, v in foo_defines.items()
if k.startswith('FOO_')
})
def upper(self):
# example method
return self.value.upper()
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/enum.py | 12 | ||||
-rw-r--r-- | Lib/test/test_enum.py | 28 |
2 files changed, 39 insertions, 1 deletions
diff --git a/Lib/enum.py b/Lib/enum.py index ed0c9ce..0070ebe 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -136,7 +136,7 @@ class _EnumDict(dict): key = '_order_' elif key in self._member_names: # descriptor overwriting an enum? - raise TypeError('Attempted to reuse key: %r' % key) + raise TypeError('%r already defined as: %r' % (key, self[key])) elif key in self._ignore: pass elif not _is_descriptor(value): @@ -157,6 +157,16 @@ class _EnumDict(dict): self._last_values.append(value) super().__setitem__(key, value) + def update(self, members, **more_members): + try: + for name in members.keys(): + self[name] = members[name] + except AttributeError: + for name, value in members: + self[name] = value + for name, value in more_members.items(): + self[name] = value + # Dummy value for Enum as EnumMeta explicitly checks for it, but of course # until EnumMeta finishes running the first time the Enum class doesn't exist. diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index f245eb6..a83241c 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -2186,6 +2186,34 @@ class TestEnum(unittest.TestCase): self.assertEqual([Strings.ONE, Strings.TWO], ['one', 'two']) + def test_dynamic_members_with_static_methods(self): + # + foo_defines = {'FOO_CAT': 'aloof', 'BAR_DOG': 'friendly', 'FOO_HORSE': 'big'} + class Foo(Enum): + vars().update({ + k: v + for k, v in foo_defines.items() + if k.startswith('FOO_') + }) + def upper(self): + return self.value.upper() + self.assertEqual(list(Foo), [Foo.FOO_CAT, Foo.FOO_HORSE]) + self.assertEqual(Foo.FOO_CAT.value, 'aloof') + self.assertEqual(Foo.FOO_HORSE.upper(), 'BIG') + # + with self.assertRaisesRegex(TypeError, "'FOO_CAT' already defined as: 'aloof'"): + class FooBar(Enum): + vars().update({ + k: v + for k, v in foo_defines.items() + if k.startswith('FOO_') + }, + **{'FOO_CAT': 'small'}, + ) + def upper(self): + return self.value.upper() + + class TestOrder(unittest.TestCase): def test_same_members(self): |