summaryrefslogtreecommitdiffstats
path: root/Lib/enum.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/enum.py')
-rw-r--r--Lib/enum.py326
1 files changed, 7 insertions, 319 deletions
diff --git a/Lib/enum.py b/Lib/enum.py
index 742b99b..17deb4b 100644
--- a/Lib/enum.py
+++ b/Lib/enum.py
@@ -391,15 +391,13 @@ class EnumType(type):
)
return enum_dict
- def __new__(metacls, cls, bases, classdict, *, boundary=None, _simple=False, **kwds):
+ def __new__(metacls, cls, bases, classdict, boundary=None, **kwds):
# an Enum class is final once enumeration items have been defined; it
# cannot be mixed with other types (int, float, etc.) if it has an
# inherited __new__ unless a new __new__ is defined (or the resulting
# class will fail).
#
# remove any keys listed in _ignore_
- if _simple:
- return super().__new__(metacls, cls, bases, classdict, **kwds)
classdict.setdefault('_ignore_', []).append('_ignore_')
ignore = classdict['_ignore_']
for key in ignore:
@@ -697,7 +695,7 @@ class EnumType(type):
"""
member_map = cls.__dict__.get('_member_map_', {})
if name in member_map:
- raise AttributeError('Cannot reassign member %r.' % (name, ))
+ raise AttributeError('Cannot reassign members.')
super().__setattr__(name, value)
def _create_(cls, class_name, names, *, module=None, qualname=None, type=None, start=1, boundary=None):
@@ -752,8 +750,7 @@ class EnumType(type):
return metacls.__new__(metacls, class_name, bases, classdict, boundary=boundary)
- def _convert_(cls, name, module, filter, source=None, *, boundary=None):
-
+ def _convert_(cls, name, module, filter, source=None, boundary=None):
"""
Create a new Enum subclass that replaces a collection of global constants
"""
@@ -780,10 +777,7 @@ class EnumType(type):
except TypeError:
# unless some values aren't comparable, in which case sort by name
members.sort(key=lambda t: t[0])
- body = {t[0]: t[1] for t in members}
- body['__module__'] = module
- tmp_cls = type(name, (object, ), body)
- cls = _simple_enum(etype=cls, boundary=boundary or KEEP)(tmp_cls)
+ cls = cls(name, members, module=module, boundary=boundary or KEEP)
cls.__reduce_ex__ = _reduce_ex_by_name
global_enum(cls)
module_globals[name] = cls
@@ -861,7 +855,7 @@ class EnumType(type):
__new__ = classdict.get('__new__', None)
# should __new__ be saved as __new_member__ later?
- save_new = first_enum is not None and __new__ is not None
+ save_new = __new__ is not None
if __new__ is None:
# check all possibles for __new_member__ before falling back to
@@ -885,7 +879,7 @@ class EnumType(type):
# if a non-object.__new__ is used then whatever value/tuple was
# assigned to the enum member name will be passed to __new__ and to the
# new enum member's __init__
- if first_enum is None or __new__ in (Enum.__new__, object.__new__):
+ if __new__ is object.__new__:
use_args = False
else:
use_args = True
@@ -1195,7 +1189,7 @@ class Flag(Enum, boundary=STRICT):
pseudo_member = object.__new__(cls)
else:
pseudo_member = (__new__ or cls._member_type_.__new__)(cls, value)
- if not hasattr(pseudo_member, '_value_'):
+ if not hasattr(pseudo_member, 'value'):
pseudo_member._value_ = value
if member_value:
pseudo_member._name_ = '|'.join([
@@ -1389,309 +1383,3 @@ def global_enum(cls):
cls.__repr__ = global_enum_repr
sys.modules[cls.__module__].__dict__.update(cls.__members__)
return cls
-
-def _simple_enum(etype=Enum, *, boundary=None, use_args=None):
- """
- Class decorator that converts a normal class into an :class:`Enum`. No
- safety checks are done, and some advanced behavior (such as
- :func:`__init_subclass__`) is not available. Enum creation can be faster
- using :func:`simple_enum`.
-
- >>> from enum import Enum, _simple_enum
- >>> @_simple_enum(Enum)
- ... class Color:
- ... RED = auto()
- ... GREEN = auto()
- ... BLUE = auto()
- >>> Color
- <enum 'Color'>
- """
- def convert_class(cls):
- nonlocal use_args
- cls_name = cls.__name__
- if use_args is None:
- use_args = etype._use_args_
- __new__ = cls.__dict__.get('__new__')
- if __new__ is not None:
- new_member = __new__.__func__
- else:
- new_member = etype._member_type_.__new__
- attrs = {}
- body = {}
- if __new__ is not None:
- body['__new_member__'] = new_member
- body['_new_member_'] = new_member
- body['_use_args_'] = use_args
- body['_generate_next_value_'] = gnv = etype._generate_next_value_
- body['_member_names_'] = member_names = []
- body['_member_map_'] = member_map = {}
- body['_value2member_map_'] = value2member_map = {}
- body['_member_type_'] = member_type = etype._member_type_
- if issubclass(etype, Flag):
- body['_boundary_'] = boundary or etype._boundary_
- body['_flag_mask_'] = None
- body['_all_bits_'] = None
- body['_inverted_'] = None
- for name, obj in cls.__dict__.items():
- if name in ('__dict__', '__weakref__'):
- continue
- if _is_dunder(name) or _is_private(cls_name, name) or _is_sunder(name) or _is_descriptor(obj):
- body[name] = obj
- else:
- attrs[name] = obj
- if cls.__dict__.get('__doc__') is None:
- body['__doc__'] = 'An enumeration.'
- #
- # double check that repr and friends are not the mixin's or various
- # things break (such as pickle)
- # however, if the method is defined in the Enum itself, don't replace
- # it
- enum_class = type(cls_name, (etype, ), body, boundary=boundary, _simple=True)
- for name in ('__repr__', '__str__', '__format__', '__reduce_ex__'):
- if name in body:
- continue
- class_method = getattr(enum_class, name)
- obj_method = getattr(member_type, name, None)
- enum_method = getattr(etype, name, None)
- if obj_method is not None and obj_method is class_method:
- setattr(enum_class, name, enum_method)
- gnv_last_values = []
- if issubclass(enum_class, Flag):
- # Flag / IntFlag
- single_bits = multi_bits = 0
- for name, value in attrs.items():
- if isinstance(value, auto) and auto.value is _auto_null:
- value = gnv(name, 1, len(member_names), gnv_last_values)
- if value in value2member_map:
- # an alias to an existing member
- redirect = property()
- redirect.__set_name__(enum_class, name)
- setattr(enum_class, name, redirect)
- member_map[name] = value2member_map[value]
- else:
- # create the member
- if use_args:
- if not isinstance(value, tuple):
- value = (value, )
- member = new_member(enum_class, *value)
- value = value[0]
- else:
- member = new_member(enum_class)
- if __new__ is None:
- member._value_ = value
- member._name_ = name
- member.__objclass__ = enum_class
- member.__init__(value)
- redirect = property()
- redirect.__set_name__(enum_class, name)
- setattr(enum_class, name, redirect)
- member_map[name] = member
- member._sort_order_ = len(member_names)
- value2member_map[value] = member
- if _is_single_bit(value):
- # not a multi-bit alias, record in _member_names_ and _flag_mask_
- member_names.append(name)
- single_bits |= value
- else:
- multi_bits |= value
- gnv_last_values.append(value)
- enum_class._flag_mask_ = single_bits
- enum_class._all_bits_ = 2 ** ((single_bits|multi_bits).bit_length()) - 1
- # set correct __iter__
- member_list = [m._value_ for m in enum_class]
- if member_list != sorted(member_list):
- enum_class._iter_member_ = enum_class._iter_member_by_def_
- else:
- # Enum / IntEnum / StrEnum
- for name, value in attrs.items():
- if isinstance(value, auto):
- if value.value is _auto_null:
- value.value = gnv(name, 1, len(member_names), gnv_last_values)
- value = value.value
- if value in value2member_map:
- # an alias to an existing member
- redirect = property()
- redirect.__set_name__(enum_class, name)
- setattr(enum_class, name, redirect)
- member_map[name] = value2member_map[value]
- else:
- # create the member
- if use_args:
- if not isinstance(value, tuple):
- value = (value, )
- member = new_member(enum_class, *value)
- value = value[0]
- else:
- member = new_member(enum_class)
- if __new__ is None:
- member._value_ = value
- member._name_ = name
- member.__objclass__ = enum_class
- member.__init__(value)
- member._sort_order_ = len(member_names)
- redirect = property()
- redirect.__set_name__(enum_class, name)
- setattr(enum_class, name, redirect)
- member_map[name] = member
- value2member_map[value] = member
- member_names.append(name)
- gnv_last_values.append(value)
- if '__new__' in body:
- enum_class.__new_member__ = enum_class.__new__
- enum_class.__new__ = Enum.__new__
- return enum_class
- return convert_class
-
-def _test_simple_enum(checked_enum, simple_enum):
- """
- A function that can be used to test an enum created with :func:`_simple_enum`
- against the version created by subclassing :class:`Enum`::
-
- >>> from enum import Enum, _simple_enum, _test_simple_enum
- >>> @_simple_enum(Enum)
- ... class Color:
- ... RED = auto()
- ... GREEN = auto()
- ... BLUE = auto()
- >>> class CheckedColor(Enum):
- ... RED = auto()
- ... GREEN = auto()
- ... BLUE = auto()
- >>> _test_simple_enum(CheckedColor, Color)
-
- If differences are found, a :exc:`TypeError` is raised.
- """
- failed = []
- if checked_enum.__dict__ != simple_enum.__dict__:
- checked_dict = checked_enum.__dict__
- checked_keys = list(checked_dict.keys())
- simple_dict = simple_enum.__dict__
- simple_keys = list(simple_dict.keys())
- member_names = set(
- list(checked_enum._member_map_.keys())
- + list(simple_enum._member_map_.keys())
- )
- for key in set(checked_keys + simple_keys):
- if key in ('__module__', '_member_map_', '_value2member_map_'):
- # keys known to be different
- continue
- elif key in member_names:
- # members are checked below
- continue
- elif key not in simple_keys:
- failed.append("missing key: %r" % (key, ))
- elif key not in checked_keys:
- failed.append("extra key: %r" % (key, ))
- else:
- checked_value = checked_dict[key]
- simple_value = simple_dict[key]
- if callable(checked_value):
- continue
- if key == '__doc__':
- # remove all spaces/tabs
- compressed_checked_value = checked_value.replace(' ','').replace('\t','')
- compressed_simple_value = simple_value.replace(' ','').replace('\t','')
- if compressed_checked_value != compressed_simple_value:
- failed.append("%r:\n %s\n %s" % (
- key,
- "checked -> %r" % (checked_value, ),
- "simple -> %r" % (simple_value, ),
- ))
- elif checked_value != simple_value:
- failed.append("%r:\n %s\n %s" % (
- key,
- "checked -> %r" % (checked_value, ),
- "simple -> %r" % (simple_value, ),
- ))
- failed.sort()
- for name in member_names:
- failed_member = []
- if name not in simple_keys:
- failed.append('missing member from simple enum: %r' % name)
- elif name not in checked_keys:
- failed.append('extra member in simple enum: %r' % name)
- else:
- checked_member_dict = checked_enum[name].__dict__
- checked_member_keys = list(checked_member_dict.keys())
- simple_member_dict = simple_enum[name].__dict__
- simple_member_keys = list(simple_member_dict.keys())
- for key in set(checked_member_keys + simple_member_keys):
- if key in ('__module__', '__objclass__'):
- # keys known to be different
- continue
- elif key not in simple_member_keys:
- failed_member.append("missing key %r not in the simple enum member %r" % (key, name))
- elif key not in checked_member_keys:
- failed_member.append("extra key %r in simple enum member %r" % (key, name))
- else:
- checked_value = checked_member_dict[key]
- simple_value = simple_member_dict[key]
- if checked_value != simple_value:
- failed_member.append("%r:\n %s\n %s" % (
- key,
- "checked member -> %r" % (checked_value, ),
- "simple member -> %r" % (simple_value, ),
- ))
- if failed_member:
- failed.append('%r member mismatch:\n %s' % (
- name, '\n '.join(failed_member),
- ))
- for method in (
- '__str__', '__repr__', '__reduce_ex__', '__format__',
- '__getnewargs_ex__', '__getnewargs__', '__reduce_ex__', '__reduce__'
- ):
- if method in simple_keys and method in checked_keys:
- # cannot compare functions, and it exists in both, so we're good
- continue
- elif method not in simple_keys and method not in checked_keys:
- # method is inherited -- check it out
- checked_method = getattr(checked_enum, method, None)
- simple_method = getattr(simple_enum, method, None)
- if hasattr(checked_method, '__func__'):
- checked_method = checked_method.__func__
- simple_method = simple_method.__func__
- if checked_method != simple_method:
- failed.append("%r: %-30s %s" % (
- method,
- "checked -> %r" % (checked_method, ),
- "simple -> %r" % (simple_method, ),
- ))
- else:
- # if the method existed in only one of the enums, it will have been caught
- # in the first checks above
- pass
- if failed:
- raise TypeError('enum mismatch:\n %s' % '\n '.join(failed))
-
-def _old_convert_(etype, name, module, filter, source=None, *, boundary=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 = sys.modules[module].__dict__
- if source:
- source = source.__dict__
- 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 = etype(name, members, module=module, boundary=boundary or KEEP)
- cls.__reduce_ex__ = _reduce_ex_by_name
- cls.__repr__ = global_enum_repr
- return cls
-