diff options
author | Petr Viktorin <encukou@gmail.com> | 2024-12-20 19:40:58 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-12-20 19:40:58 (GMT) |
commit | 2a66dd33dfc0b845042da9bb54aaa4e890733f54 (patch) | |
tree | f1d64ee79cc6f670d53e8160128521d7007cebed /Lib | |
parent | 3879ca0100942ae15a09ac22889cbe3e46d424eb (diff) | |
download | cpython-2a66dd33dfc0b845042da9bb54aaa4e890733f54.zip cpython-2a66dd33dfc0b845042da9bb54aaa4e890733f54.tar.gz cpython-2a66dd33dfc0b845042da9bb54aaa4e890733f54.tar.bz2 |
gh-112328: Make EnumDict usable on its own and document it (GH-123669)
Co-authored-by: Rafi <rafi.promit@gmail.com>
Co-authored-by: Sviatoslav Sydorenko (Святослав Сидоренко) <wk.cvs.github@sydorenko.org.ua>
Co-authored-by: Ethan Furman <ethan@stoneleaf.us>
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/enum.py | 10 | ||||
-rw-r--r-- | Lib/test/test_enum.py | 33 |
2 files changed, 37 insertions, 6 deletions
diff --git a/Lib/enum.py b/Lib/enum.py index ccc1da4..0444347 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -342,12 +342,13 @@ class EnumDict(dict): EnumType will use the names found in self._member_names as the enumeration member names. """ - def __init__(self): + def __init__(self, cls_name=None): super().__init__() self._member_names = {} # use a dict -- faster look-up than a list, and keeps insertion order since 3.7 self._last_values = [] self._ignore = [] self._auto_called = False + self._cls_name = cls_name def __setitem__(self, key, value): """ @@ -358,7 +359,7 @@ class EnumDict(dict): Single underscore (sunder) names are reserved. """ - if _is_private(self._cls_name, key): + if self._cls_name is not None and _is_private(self._cls_name, key): # do nothing, name will be a normal attribute pass elif _is_sunder(key): @@ -406,7 +407,7 @@ class EnumDict(dict): value = value.value elif _is_descriptor(value): pass - elif _is_internal_class(self._cls_name, value): + elif self._cls_name is not None and _is_internal_class(self._cls_name, value): # do nothing, name will be a normal attribute pass else: @@ -478,8 +479,7 @@ class EnumType(type): # check that previous enum members do not exist metacls._check_for_existing_members_(cls, bases) # create the namespace dict - enum_dict = EnumDict() - enum_dict._cls_name = cls + enum_dict = EnumDict(cls) # inherit previous flags and _generate_next_value_ function member_type, first_enum = metacls._get_mixins_(cls, bases) if first_enum is not None: diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index b9e13fb..8884295 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -14,7 +14,7 @@ from datetime import date from enum import Enum, EnumMeta, IntEnum, StrEnum, EnumType, Flag, IntFlag, unique, auto from enum import STRICT, CONFORM, EJECT, KEEP, _simple_enum, _test_simple_enum from enum import verify, UNIQUE, CONTINUOUS, NAMED_FLAGS, ReprEnum -from enum import member, nonmember, _iter_bits_lsb +from enum import member, nonmember, _iter_bits_lsb, EnumDict from io import StringIO from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL from test import support @@ -5440,6 +5440,37 @@ class TestConvert(unittest.TestCase): self.assertEqual(format(test_type.CONVERT_STRING_TEST_NAME_A), '5') +class TestEnumDict(unittest.TestCase): + def test_enum_dict_in_metaclass(self): + """Test that EnumDict is usable as a class namespace""" + class Meta(type): + @classmethod + def __prepare__(metacls, cls, bases, **kwds): + return EnumDict(cls) + + class MyClass(metaclass=Meta): + a = 1 + + with self.assertRaises(TypeError): + a = 2 # duplicate + + with self.assertRaises(ValueError): + _a_sunder_ = 3 + + def test_enum_dict_standalone(self): + """Test that EnumDict is usable on its own""" + enumdict = EnumDict() + enumdict['a'] = 1 + + with self.assertRaises(TypeError): + enumdict['a'] = 'other value' + + # Only MutableMapping interface is overridden for now. + # If this stops passing, update the documentation. + enumdict |= {'a': 'other value'} + self.assertEqual(enumdict['a'], 'other value') + + # helpers def enum_dir(cls): |