diff options
author | orlnub123 <orlnub123@gmail.com> | 2018-09-12 17:28:53 (GMT) |
---|---|---|
committer | Ethan Furman <ethan@stoneleaf.us> | 2018-09-12 17:28:53 (GMT) |
commit | 0fb9fadd3b3e9e3698647e0b92d49b0b7aacd979 (patch) | |
tree | 0a53251ce3c6655e1a291d2c668e74bbb1318ea7 /Lib/enum.py | |
parent | f52237400b9960d434c5d0676a3479b8c1e8c869 (diff) | |
download | cpython-0fb9fadd3b3e9e3698647e0b92d49b0b7aacd979.zip cpython-0fb9fadd3b3e9e3698647e0b92d49b0b7aacd979.tar.gz cpython-0fb9fadd3b3e9e3698647e0b92d49b0b7aacd979.tar.bz2 |
bpo-34282: Fix Enum._convert shadowing members named _convert (GH-8568)
* Fix enum members getting shadowed by parent attributes
* Move Enum._convert to EnumMeta._convert_
* Deprecate _convert
Diffstat (limited to 'Lib/enum.py')
-rw-r--r-- | Lib/enum.py | 83 |
1 files changed, 45 insertions, 38 deletions
diff --git a/Lib/enum.py b/Lib/enum.py index 9d1aef3..0839671 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -165,9 +165,11 @@ class EnumMeta(type): enum_class._member_map_ = {} # name->value map enum_class._member_type_ = member_type - # save attributes from super classes so we know if we can take - # the shortcut of storing members in the class dict - base_attributes = {a for b in enum_class.mro() for a in b.__dict__} + # save DynamicClassAttribute attributes from super classes so we know + # if we can take the shortcut of storing members in the class dict + dynamic_attributes = {k for c in enum_class.mro() + for k, v in c.__dict__.items() + if isinstance(v, DynamicClassAttribute)} # Reverse value->name map for hashable values. enum_class._value2member_map_ = {} @@ -227,7 +229,7 @@ class EnumMeta(type): enum_class._member_names_.append(member_name) # performance boost for any member that would not shadow # a DynamicClassAttribute - if member_name not in base_attributes: + if member_name not in dynamic_attributes: setattr(enum_class, member_name, enum_member) # now add to _member_map_ enum_class._member_map_[member_name] = enum_member @@ -428,6 +430,45 @@ class EnumMeta(type): return enum_class + def _convert_(cls, name, module, filter, source=None): + """ + Create a new Enum subclass that replaces a collection of global constants + """ + # convert all constants from source (or module) that pass filter() to + # a new Enum called name, and export the enum and its members back to + # module; + # also, replace the __reduce_ex__ method so unpickling works in + # previous Python versions + module_globals = vars(sys.modules[module]) + if source: + source = vars(source) + else: + source = module_globals + # _value2member_map_ is populated in the same order every time + # for a consistent reverse mapping of number to name when there + # are multiple names for the same number. + members = [ + (name, value) + for name, value in source.items() + if filter(name)] + try: + # sort by value + members.sort(key=lambda t: (t[1], t[0])) + except TypeError: + # unless some values aren't comparable, in which case sort by name + members.sort(key=lambda t: t[0]) + cls = cls(name, members, module=module) + cls.__reduce_ex__ = _reduce_ex_by_name + module_globals.update(cls.__members__) + module_globals[name] = cls + return cls + + def _convert(cls, *args, **kwargs): + import warnings + warnings.warn("_convert is deprecated and will be removed in 3.9, use " + "_convert_ instead.", DeprecationWarning, stacklevel=2) + return cls._convert_(*args, **kwargs) + @staticmethod def _get_mixins_(bases): """Returns the type for creating enum members, and the first inherited @@ -613,40 +654,6 @@ class Enum(metaclass=EnumMeta): """The value of the Enum member.""" return self._value_ - @classmethod - def _convert(cls, name, module, filter, source=None): - """ - Create a new Enum subclass that replaces a collection of global constants - """ - # convert all constants from source (or module) that pass filter() to - # a new Enum called name, and export the enum and its members back to - # module; - # also, replace the __reduce_ex__ method so unpickling works in - # previous Python versions - module_globals = vars(sys.modules[module]) - if source: - source = vars(source) - else: - source = module_globals - # _value2member_map_ is populated in the same order every time - # for a consistent reverse mapping of number to name when there - # are multiple names for the same number. - members = [ - (name, value) - for name, value in source.items() - if filter(name)] - try: - # sort by value - members.sort(key=lambda t: (t[1], t[0])) - except TypeError: - # unless some values aren't comparable, in which case sort by name - members.sort(key=lambda t: t[0]) - cls = cls(name, members, module=module) - cls.__reduce_ex__ = _reduce_ex_by_name - module_globals.update(cls.__members__) - module_globals[name] = cls - return cls - class IntEnum(int, Enum): """Enum where members are also (and must be) ints""" |