aboutsummaryrefslogtreecommitdiff
path: root/venv/Lib/site-packages/aenum/__init__.py
diff options
context:
space:
mode:
Diffstat (limited to 'venv/Lib/site-packages/aenum/__init__.py')
-rw-r--r--venv/Lib/site-packages/aenum/__init__.py4111
1 files changed, 4111 insertions, 0 deletions
diff --git a/venv/Lib/site-packages/aenum/__init__.py b/venv/Lib/site-packages/aenum/__init__.py
new file mode 100644
index 00000000..26c504cc
--- /dev/null
+++ b/venv/Lib/site-packages/aenum/__init__.py
@@ -0,0 +1,4111 @@
+"""Python Advanced Enumerations & NameTuples"""
+from __future__ import print_function
+
+# imports
+import sys as _sys
+pyver = _sys.version_info[:2]
+PY2 = pyver < (3, )
+PY3 = pyver >= (3, )
+PY2_6 = (2, 6)
+PY3_3 = (3, 3)
+PY3_4 = (3, 4)
+PY3_5 = (3, 5)
+PY3_6 = (3, 6)
+PY3_11 = (3, 11)
+
+import re
+
+_bltin_property = property
+_bltin_bin = bin
+
+try:
+ from collections import OrderedDict
+except ImportError:
+ OrderedDict = dict
+from collections import defaultdict
+try:
+ import sqlite3
+except ImportError:
+ sqlite3 = None
+
+try:
+ RecursionError
+except NameError:
+ # python3.4
+ RecursionError = RuntimeError
+
+from operator import or_ as _or_, and_ as _and_, xor as _xor_, inv as _inv_
+from operator import abs as _abs_, add as _add_, floordiv as _floordiv_
+from operator import lshift as _lshift_, rshift as _rshift_, mod as _mod_
+from operator import mul as _mul_, neg as _neg_, pos as _pos_, pow as _pow_
+from operator import truediv as _truediv_, sub as _sub_
+
+if PY2:
+ from ._py2 import *
+if PY3:
+ from ._py3 import *
+
+obj_type = type
+
+__all__ = [
+ 'NamedConstant', 'constant', 'skip', 'nonmember', 'member', 'no_arg',
+ 'Enum', 'IntEnum', 'AutoNumberEnum', 'OrderedEnum', 'UniqueEnum',
+ 'StrEnum', 'UpperStrEnum', 'LowerStrEnum',
+ 'Flag', 'IntFlag',
+ 'AddValue', 'MagicValue', 'MultiValue', 'NoAlias', 'Unique',
+ 'AddValueEnum', 'MultiValueEnum', 'NoAliasEnum',
+ 'enum', 'extend_enum', 'unique', 'property',
+ 'NamedTuple', 'SqliteEnum',
+ 'FlagBoundary', 'STRICT', 'CONFORM', 'EJECT', 'KEEP',
+ 'add_stdlib_integration', 'remove_stdlib_integration'
+ ]
+
+if sqlite3 is None:
+ __all__.remove('SqliteEnum')
+
+version = 3, 1, 12, 1
+
+# shims
+try:
+ any
+except NameError:
+ def any(iterable):
+ for element in iterable:
+ if element:
+ return True
+ return False
+
+try:
+ unicode
+ unicode = unicode
+except NameError:
+ # In Python 3 unicode no longer exists (it's just str)
+ unicode = str
+
+try:
+ basestring
+ basestring = bytes, unicode
+except NameError:
+ # In Python 2 basestring is the ancestor of both str and unicode
+ # in Python 3 it's just str, but was missing in 3.1
+ basestring = str,
+
+try:
+ long
+ baseinteger = int, long
+except NameError:
+ baseinteger = int,
+ long = int
+# deprecated
+baseint = baseinteger
+
+try:
+ NoneType
+except NameError:
+ NoneType = type(None)
+
+try:
+ # derive from stdlib enum if possible
+ import enum
+ if hasattr(enum, 'version'):
+ raise ImportError('wrong version')
+ else:
+ from enum import EnumMeta as StdlibEnumMeta, Enum as StdlibEnum, IntEnum as StdlibIntEnum
+ StdlibFlag = StdlibIntFlag = StdlibStrEnum = StdlibReprEnum = None
+except ImportError:
+ StdlibEnumMeta = StdlibEnum = StdlibIntEnum = StdlibIntFlag = StdlibFlag = StdlibStrEnum = None
+
+if StdlibEnum:
+ try:
+ from enum import IntFlag as StdlibIntFlag, Flag as StdlibFlag
+ except ImportError:
+ pass
+ try:
+ from enum import StrEnum as StdlibStrEnum
+ except ImportError:
+ pass
+ try:
+ from enum import ReprEnum as StdlibReprEnum
+ except ImportError:
+ pass
+
+
+
+
+# helpers
+# will be exported later
+MagicValue = AddValue = MultiValue = NoAlias = Unique = None
+
+def _bit_count(num):
+ """
+ return number of set bits
+
+ Counting bits set, Brian Kernighan's way*
+
+ unsigned int v; // count the number of bits set in v
+ unsigned int c; // c accumulates the total bits set in v
+ for (c = 0; v; c++)
+ { v &= v - 1; } //clear the least significant bit set
+
+ This method goes through as many iterations as there are set bits. So if we
+ have a 32-bit word with only the high bit set, then it will only go once
+ through the loop.
+
+ * The C Programming Language 2nd Ed., Kernighan & Ritchie, 1988.
+
+ This works because each subtraction "borrows" from the lowest 1-bit. For
+ example:
+
+ loop pass 1 loop pass 2
+ ----------- -----------
+ 101000 100000
+ - 1 - 1
+ = 100111 = 011111
+ & 101000 & 100000
+ = 100000 = 0
+
+ It is an excellent technique for Python, since the size of the integer need
+ not be determined beforehand.
+
+ (from https://wiki.python.org/moin/BitManipulation)
+ """
+ count = 0
+ while num:
+ num &= num - 1
+ count += 1
+ return count
+
+def _is_single_bit(value):
+ """
+ True if only one bit set in value (should be an int)
+ """
+ if value == 0:
+ return False
+ value &= value - 1
+ return value == 0
+
+def _iter_bits_lsb(value):
+ """
+ Return each bit value one at a time.
+
+ >>> list(_iter_bits_lsb(6))
+ [2, 4]
+ """
+
+ while value:
+ bit = value & (~value + 1)
+ yield bit
+ value ^= bit
+
+def bin(value, max_bits=None):
+ """
+ Like built-in bin(), except negative values are represented in
+ twos-compliment, and the leading bit always indicates sign
+ (0=positive, 1=negative).
+
+ >>> bin(10)
+ '0b0 1010'
+ >>> bin(~10) # ~10 is -11
+ '0b1 0101'
+ """
+
+ ceiling = 2 ** (value).bit_length()
+ if value >= 0:
+ s = _bltin_bin(value + ceiling).replace('1', '0', 1)
+ else:
+ s = _bltin_bin(~value ^ (ceiling - 1) + ceiling)
+ sign = s[:3]
+ digits = s[3:]
+ if max_bits is not None:
+ if len(digits) < max_bits:
+ digits = (sign[-1] * max_bits + digits)[-max_bits:]
+ return "%s %s" % (sign, digits)
+
+
+try:
+ from types import DynamicClassAttribute
+ base = DynamicClassAttribute
+except ImportError:
+ base = object
+ DynamicClassAttribute = None
+
+class property(base):
+ """
+ This is a descriptor, used to define attributes that act differently
+ when accessed through an enum member and through an enum class.
+ Instance access is the same as property(), but access to an attribute
+ through the enum class will look in the class' _member_map_.
+ """
+
+ # inherit from DynamicClassAttribute if we can in order to get `inspect`
+ # support
+
+ def __init__(self, fget=None, fset=None, fdel=None, doc=None):
+ self.fget = fget
+ self.fset = fset
+ self.fdel = fdel
+ # next two lines make property act the same as _bltin_property
+ self.__doc__ = doc or fget.__doc__
+ self.overwrite_doc = doc is None
+ # support for abstract methods
+ self.__isabstractmethod__ = bool(getattr(fget, '__isabstractmethod__', False))
+ # names, if possible
+
+ def getter(self, fget):
+ fdoc = fget.__doc__ if self.overwrite_doc else None
+ result = type(self)(fget, self.fset, self.fdel, fdoc or self.__doc__)
+ result.overwrite_doc = self.__doc__ is None
+ return result
+
+ def setter(self, fset):
+ fdoc = fget.__doc__ if self.overwrite_doc else None
+ result = type(self)(self.fget, fset, self.fdel, self.__doc__)
+ result.overwrite_doc = self.__doc__ is None
+ return result
+
+ def deleter(self, fdel):
+ fdoc = fget.__doc__ if self.overwrite_doc else None
+ result = type(self)(self.fget, self.fset, fdel, self.__doc__)
+ result.overwrite_doc = self.__doc__ is None
+ return result
+
+ def __repr__(self):
+ member = self.ownerclass._member_map_.get(self.name)
+ func = self.fget or self.fset or self.fdel
+ strings = []
+ if member:
+ strings.append('%r' % member)
+ if func:
+ strings.append('function=%s' % func.__name__)
+ return 'property(%s)' % ', '.join(strings)
+
+ def __get__(self, instance, ownerclass=None):
+ if instance is None:
+ try:
+ return ownerclass._member_map_[self.name]
+ except KeyError:
+ raise AttributeError(
+ '%r has no attribute %r' % (ownerclass, self.name)
+ )
+ else:
+ if self.fget is not None:
+ return self.fget(instance)
+ else:
+ if self.fset is not None:
+ raise AttributeError(
+ 'cannot read attribute %r on %r' % (self.name, ownerclass)
+ )
+ else:
+ try:
+ return instance.__dict__[self.name]
+ except KeyError:
+ raise AttributeError(
+ '%r member has no attribute %r' % (ownerclass, self.name)
+ )
+
+ def __set__(self, instance, value):
+ if self.fset is None:
+ if self.fget is not None:
+ raise AttributeError(
+ "cannot set attribute %r on <aenum %r>" % (self.name, self.clsname)
+ )
+ else:
+ instance.__dict__[self.name] = value
+ else:
+ return self.fset(instance, value)
+
+ def __delete__(self, instance):
+ if self.fdel is None:
+ if self.fget or self.fset:
+ raise AttributeError(
+ "cannot delete attribute %r on <aenum %r>" % (self.name, self.clsname)
+ )
+ elif self.name in instance.__dict__:
+ del instance.__dict__[self.name]
+ else:
+ raise AttributeError(
+ "no attribute %r on <aenum %r> member" % (self.name, self.clsname)
+ )
+ else:
+ return self.fdel(instance)
+
+ def __set_name__(self, ownerclass, name):
+ self.name = name
+ self.clsname = ownerclass.__name__
+ self.ownerclass = ownerclass
+
+_RouteClassAttributeToGetattr = property
+if DynamicClassAttribute is None:
+ DynamicClassAttribute = property
+# deprecated
+enum_property = property
+
+class NonMember(object):
+ """
+ Protects item from becaming an Enum member during class creation.
+ """
+ def __init__(self, value):
+ self.value = value
+
+ def __get__(self, instance, ownerclass=None):
+ return self.value
+skip = nonmember = NonMember
+
+class Member(object):
+ """
+ Forces item to became an Enum member during class creation.
+ """
+ def __init__(self, value):
+ self.value = value
+member = Member
+
+class SentinelType(type):
+ def __repr__(cls):
+ return '<%s>' % cls.__name__
+Sentinel = SentinelType('Sentinel', (object, ), {})
+
+def _is_descriptor(obj):
+ """Returns True if obj is a descriptor, False otherwise."""
+ return (
+ hasattr(obj, '__get__') or
+ hasattr(obj, '__set__') or
+ hasattr(obj, '__delete__'))
+
+
+def _is_dunder(name):
+ """Returns True if a __dunder__ name, False otherwise."""
+ return (len(name) > 4 and
+ name[:2] == name[-2:] == '__' and
+ name[2] != '_' and
+ name[-3] != '_')
+
+
+def _is_sunder(name):
+ """Returns True if a _sunder_ name, False otherwise."""
+ return (len(name) > 2 and
+ name[0] == name[-1] == '_' and
+ name[1] != '_' and
+ name[-2] != '_')
+
+def _is_internal_class(cls_name, obj):
+ # only 3.3 and up, always return False in 3.2 and below
+ if pyver < PY3_3:
+ return False
+ else:
+ qualname = getattr(obj, '__qualname__', False)
+ return not _is_descriptor(obj) and qualname and re.search(r"\.?%s\.\w+$" % cls_name, qualname)
+
+def _is_private_name(cls_name, name):
+ pattern = r'^_%s__\w+[^_]_?$' % (cls_name, )
+ return re.search(pattern, name)
+
+def _power_of_two(value):
+ if value < 1:
+ return False
+ return value == 2 ** _high_bit(value)
+
+def bits(num):
+ if num in (0, 1):
+ return str(num)
+ negative = False
+ if num < 0:
+ negative = True
+ num = ~num
+ result = bits(num>>1) + str(num&1)
+ if negative:
+ result = '1' + ''.join(['10'[d=='1'] for d in result])
+ return result
+
+
+def bit_count(num):
+ """
+ return number of set bits
+
+ Counting bits set, Brian Kernighan's way*
+
+ unsigned int v; // count the number of bits set in v
+ unsigned int c; // c accumulates the total bits set in v
+ for (c = 0; v; c++)
+ { v &= v - 1; } //clear the least significant bit set
+
+ This method goes through as many iterations as there are set bits. So if we
+ have a 32-bit word with only the high bit set, then it will only go once
+ through the loop.
+
+ * The C Programming Language 2nd Ed., Kernighan & Ritchie, 1988.
+
+ This works because each subtraction "borrows" from the lowest 1-bit. For example:
+
+ loop pass 1 loop pass 2
+ ----------- -----------
+ 101000 100000
+ - 1 - 1
+ = 100111 = 011111
+ & 101000 & 100000
+ = 100000 = 0
+
+ It is an excellent technique for Python, since the size of the integer need not
+ be determined beforehand.
+ """
+ count = 0
+ while(num):
+ num &= num - 1
+ count += 1
+ return(count)
+
+def bit_len(num):
+ length = 0
+ while num:
+ length += 1
+ num >>= 1
+ return length
+
+def is_single_bit(num):
+ """
+ True if only one bit set in num (should be an int)
+ """
+ num &= num - 1
+ return num == 0
+
+def _make_class_unpicklable(obj):
+ """
+ Make the given obj un-picklable.
+
+ obj should be either a dictionary, on an Enum
+ """
+ def _break_on_call_reduce(self, proto):
+ raise TypeError('%r cannot be pickled' % self)
+ if isinstance(obj, dict):
+ obj['__reduce_ex__'] = _break_on_call_reduce
+ obj['__module__'] = '<unknown>'
+ else:
+ setattr(obj, '__reduce_ex__', _break_on_call_reduce)
+ setattr(obj, '__module__', '<unknown>')
+
+def _check_auto_args(method):
+ """check if new generate method supports *args and **kwds"""
+ if isinstance(method, staticmethod):
+ method = method.__get__(type)
+ method = getattr(method, 'im_func', method)
+ args, varargs, keywords, defaults = getargspec(method)
+ return varargs is not None and keywords is not None
+
+def _get_attr_from_chain(cls, attr):
+ sentinel = object()
+ for basecls in cls.mro():
+ obj = basecls.__dict__.get(attr, sentinel)
+ if obj is not sentinel:
+ return obj
+
+def _value(obj):
+ if isinstance(obj, (auto, constant)):
+ return obj.value
+ else:
+ return obj
+
+def enumsort(things):
+ """
+ sorts things by value if all same type; otherwise by name
+ """
+ if not things:
+ return things
+ sort_type = type(things[0])
+ if not issubclass(sort_type, tuple):
+ # direct sort or type error
+ if not all((type(v) is sort_type) for v in things[1:]):
+ raise TypeError('cannot sort items of different types')
+ return sorted(things)
+ else:
+ # expecting list of (name, value) tuples
+ sort_type = type(things[0][1])
+ try:
+ if all((type(v[1]) is sort_type) for v in things[1:]):
+ return sorted(things, key=lambda i: i[1])
+ else:
+ raise TypeError('try name sort instead')
+ except TypeError:
+ return sorted(things, key=lambda i: i[0])
+
+def export(collection, namespace=None):
+ """
+ export([collection,] namespace) -> Export members to target namespace.
+
+ If collection is not given, act as a decorator.
+ """
+ if namespace is None:
+ namespace = collection
+ def export_decorator(collection):
+ return export(collection, namespace)
+ return export_decorator
+ elif issubclass(collection, NamedConstant):
+ for n, c in collection.__dict__.items():
+ if isinstance(c, NamedConstant):
+ namespace[n] = c
+ elif issubclass(collection, Enum):
+ data = collection.__members__.items()
+ for n, m in data:
+ namespace[n] = m
+ else:
+ raise TypeError('%r is not a supported collection' % (collection,) )
+ return collection
+
+class _Addendum(object):
+ def __init__(self, dict, doc, ns):
+ # dict is the dict to update with functions
+ # doc is the docstring to put in the dict
+ # ns is the namespace to remove the function names from
+ self.dict = dict
+ self.ns = ns
+ self.added = set()
+ def __call__(self, func):
+ if isinstance(func, (staticmethod, classmethod)):
+ name = func.__func__.__name__
+ elif isinstance(func, (property, _bltin_property)):
+ name = (func.fget or func.fset or func.fdel).__name__
+ else:
+ name = func.__name__
+ self.dict[name] = func
+ self.added.add(name)
+ def resolve(self):
+ ns = self.ns
+ for name in self.added:
+ del ns[name]
+ return self.dict
+
+# Constant / NamedConstant
+
+class constant(object):
+ '''
+ Simple constant descriptor for NamedConstant and Enum use.
+ '''
+ def __init__(self, value, doc=None):
+ self.value = value
+ self.__doc__ = doc
+
+ def __get__(self, *args):
+ return self.value
+
+ def __repr__(self):
+ return '%s(%r)' % (self.__class__.__name__, self.value)
+
+ def __and__(self, other):
+ return _and_(self.value, _value(other))
+
+ def __rand__(self, other):
+ return _and_(_value(other), self.value)
+
+ def __invert__(self):
+ return _inv_(self.value)
+
+ def __or__(self, other):
+ return _or_(self.value, _value(other))
+
+ def __ror__(self, other):
+ return _or_(_value(other), self.value)
+
+ def __xor__(self, other):
+ return _xor_(self.value, _value(other))
+
+ def __rxor__(self, other):
+ return _xor_(_value(other), self.value)
+
+ def __abs__(self):
+ return _abs_(self.value)
+
+ def __add__(self, other):
+ return _add_(self.value, _value(other))
+
+ def __radd__(self, other):
+ return _add_(_value(other), self.value)
+
+ def __neg__(self):
+ return _neg_(self.value)
+
+ def __pos__(self):
+ return _pos_(self.value)
+
+ if PY2:
+ def __div__(self, other):
+ return _div_(self.value, _value(other))
+
+ def __rdiv__(self, other):
+ return _div_(_value(other), (self.value))
+
+ def __floordiv__(self, other):
+ return _floordiv_(self.value, _value(other))
+
+ def __rfloordiv__(self, other):
+ return _floordiv_(_value(other), self.value)
+
+ def __truediv__(self, other):
+ return _truediv_(self.value, _value(other))
+
+ def __rtruediv__(self, other):
+ return _truediv_(_value(other), self.value)
+
+ def __lshift__(self, other):
+ return _lshift_(self.value, _value(other))
+
+ def __rlshift__(self, other):
+ return _lshift_(_value(other), self.value)
+
+ def __rshift__(self, other):
+ return _rshift_(self.value, _value(other))
+
+ def __rrshift__(self, other):
+ return _rshift_(_value(other), self.value)
+
+ def __mod__(self, other):
+ return _mod_(self.value, _value(other))
+
+ def __rmod__(self, other):
+ return _mod_(_value(other), self.value)
+
+ def __mul__(self, other):
+ return _mul_(self.value, _value(other))
+
+ def __rmul__(self, other):
+ return _mul_(_value(other), self.value)
+
+ def __pow__(self, other):
+ return _pow_(self.value, _value(other))
+
+ def __rpow__(self, other):
+ return _pow_(_value(other), self.value)
+
+ def __sub__(self, other):
+ return _sub_(self.value, _value(other))
+
+ def __rsub__(self, other):
+ return _sub_(_value(other), self.value)
+
+ def __set_name__(self, ownerclass, name):
+ self.name = name
+ self.clsname = ownerclass.__name__
+
+
+NamedConstant = None
+
+class _NamedConstantDict(dict):
+ """Track constant order and ensure names are not reused.
+
+ NamedConstantMeta will use the names found in self._names as the
+ Constant names.
+ """
+ def __init__(self):
+ super(_NamedConstantDict, self).__init__()
+ self._names = []
+
+ def __setitem__(self, key, value):
+ """Changes anything not dundered or not a constant descriptor.
+
+ If an constant name is used twice, an error is raised; duplicate
+ values are not checked for.
+
+ Single underscore (sunder) names are reserved.
+ """
+ if _is_sunder(key):
+ raise ValueError(
+ '_sunder_ names, such as %r, are reserved for future NamedConstant use'
+ % (key, )
+ )
+ elif _is_dunder(key):
+ pass
+ elif key in self._names:
+ # overwriting an existing constant?
+ raise TypeError('attempt to reuse name: %r' % (key, ))
+ elif isinstance(value, constant) or not _is_descriptor(value):
+ if key in self:
+ # overwriting a descriptor?
+ raise TypeError('%s already defined as: %r' % (key, self[key]))
+ self._names.append(key)
+ super(_NamedConstantDict, self).__setitem__(key, value)
+
+
+class NamedConstantMeta(type):
+ """
+ Block attempts to reassign NamedConstant attributes.
+ """
+
+ @classmethod
+ def __prepare__(metacls, cls, bases, **kwds):
+ return _NamedConstantDict()
+
+ def __new__(metacls, cls, bases, clsdict):
+ if type(clsdict) is dict:
+ original_dict = clsdict
+ clsdict = _NamedConstantDict()
+ for k, v in original_dict.items():
+ clsdict[k] = v
+ newdict = {}
+ constants = {}
+ for name, obj in clsdict.items():
+ if name in clsdict._names:
+ constants[name] = obj
+ continue
+ elif isinstance(obj, nonmember):
+ obj = obj.value
+ newdict[name] = obj
+ newcls = super(NamedConstantMeta, metacls).__new__(metacls, cls, bases, newdict)
+ newcls._named_constant_cache_ = {}
+ newcls._members_ = {}
+ for name, obj in constants.items():
+ new_k = newcls.__new__(newcls, name, obj)
+ newcls._members_[name] = new_k
+ return newcls
+
+ def __bool__(cls):
+ return True
+
+ def __delattr__(cls, attr):
+ cur_obj = cls.__dict__.get(attr)
+ if NamedConstant is not None and isinstance(cur_obj, NamedConstant):
+ raise AttributeError('cannot delete constant <%s.%s>' % (cur_obj.__class__.__name__, cur_obj._name_))
+ super(NamedConstantMeta, cls).__delattr__(attr)
+
+ def __iter__(cls):
+ return (k for k in cls._members_.values())
+
+ def __reversed__(cls):
+ return (k for k in reversed(cls._members_.values()))
+
+ def __len__(cls):
+ return len(cls._members_)
+
+ __nonzero__ = __bool__
+
+ def __setattr__(cls, name, value):
+ """Block attempts to reassign NamedConstants.
+ """
+ cur_obj = cls.__dict__.get(name)
+ if NamedConstant is not None and isinstance(cur_obj, NamedConstant):
+ raise AttributeError('cannot rebind constant <%s.%s>' % (cur_obj.__class__.__name__, cur_obj._name_))
+ super(NamedConstantMeta, cls).__setattr__(name, value)
+
+constant_dict = _Addendum(
+ dict=NamedConstantMeta.__prepare__('NamedConstant', (object, )),
+ doc="NamedConstants protection.\n\n Derive from this class to lock NamedConstants.\n\n",
+ ns=globals(),
+ )
+
+@constant_dict
+def __new__(cls, name, value=None, doc=None):
+ if value is None:
+ # lookup, name is value
+ value = name
+ for name, obj in cls.__dict__.items():
+ if isinstance(obj, cls) and obj._value_ == value:
+ return obj
+ else:
+ raise ValueError('%r does not exist in %r' % (value, cls.__name__))
+ cur_obj = cls.__dict__.get(name)
+ if isinstance(cur_obj, NamedConstant):
+ raise AttributeError('cannot rebind constant <%s.%s>' % (cur_obj.__class__.__name__, cur_obj._name_))
+ elif isinstance(value, constant):
+ doc = doc or value.__doc__
+ value = value.value
+ metacls = cls.__class__
+ if isinstance(value, NamedConstant):
+ # constants from other classes are reduced to their actual value
+ value = value._value_
+ actual_type = type(value)
+ value_type = cls._named_constant_cache_.get(actual_type)
+ if value_type is None:
+ value_type = type(cls.__name__, (cls, type(value)), {})
+ cls._named_constant_cache_[type(value)] = value_type
+ obj = actual_type.__new__(value_type, value)
+ obj._name_ = name
+ obj._value_ = value
+ obj.__doc__ = doc
+ cls._members_[name] = obj
+ metacls.__setattr__(cls, name, obj)
+ return obj
+
+@constant_dict
+def __repr__(self):
+ return "<%s.%s: %r>" % (
+ self.__class__.__name__, self._name_, self._value_)
+
+@constant_dict
+def __reduce_ex__(self, proto):
+ return getattr, (self.__class__, self._name_)
+
+NamedConstant = NamedConstantMeta('NamedConstant', (object, ), constant_dict.resolve())
+Constant = NamedConstant
+del constant_dict
+
+# NamedTuple
+
+class _NamedTupleDict(OrderedDict):
+ """Track field order and ensure field names are not reused.
+
+ NamedTupleMeta will use the names found in self._field_names to translate
+ to indices.
+ """
+ def __init__(self, *args, **kwds):
+ self._field_names = []
+ super(_NamedTupleDict, self).__init__(*args, **kwds)
+
+ def __setitem__(self, key, value):
+ """Records anything not dundered or not a descriptor.
+
+ If a field name is used twice, an error is raised.
+
+ Single underscore (sunder) names are reserved.
+ """
+ if _is_sunder(key):
+ if key not in ('_size_', '_order_', '_fields_'):
+ raise ValueError(
+ '_sunder_ names, such as %r, are reserved for future NamedTuple use'
+ % (key, )
+ )
+ elif _is_dunder(key):
+ if key == '__order__':
+ key = '_order_'
+ elif key in self._field_names:
+ # overwriting a field?
+ raise TypeError('attempt to reuse field name: %r' % (key, ))
+ elif not _is_descriptor(value):
+ if key in self:
+ # field overwriting a descriptor?
+ raise TypeError('%s already defined as: %r' % (key, self[key]))
+ self._field_names.append(key)
+ super(_NamedTupleDict, self).__setitem__(key, value)
+
+
+class _TupleAttributeAtIndex(object):
+
+ def __init__(self, name, index, doc, default):
+ self.name = name
+ self.index = index
+ if doc is undefined:
+ doc = None
+ self.__doc__ = doc
+ self.default = default
+
+ def __get__(self, instance, owner):
+ if instance is None:
+ return self
+ if len(instance) <= self.index:
+ raise AttributeError('%s instance has no value for %s' % (instance.__class__.__name__, self.name))
+ return instance[self.index]
+
+ def __repr__(self):
+ return '%s(%d)' % (self.__class__.__name__, self.index)
+
+
+class undefined(object):
+ def __repr__(self):
+ return 'undefined'
+ def __bool__(self):
+ return False
+ __nonzero__ = __bool__
+undefined = undefined()
+
+
+class TupleSize(NamedConstant):
+ fixed = constant('fixed', 'tuple length is static')
+ minimum = constant('minimum', 'tuple must be at least x long (x is calculated during creation')
+ variable = constant('variable', 'tuple length can be anything')
+
+class NamedTupleMeta(type):
+ """Metaclass for NamedTuple"""
+
+ @classmethod
+ def __prepare__(metacls, cls, bases, size=undefined, **kwds):
+ return _NamedTupleDict()
+
+ def __init__(cls, *args , **kwds):
+ super(NamedTupleMeta, cls).__init__(*args)
+
+ def __new__(metacls, cls, bases, clsdict, size=undefined, **kwds):
+ if bases == (object, ):
+ bases = (tuple, object)
+ elif tuple not in bases:
+ if object in bases:
+ index = bases.index(object)
+ bases = bases[:index] + (tuple, ) + bases[index:]
+ else:
+ bases = bases + (tuple, )
+ # include any fields from base classes
+ base_dict = _NamedTupleDict()
+ namedtuple_bases = []
+ for base in bases:
+ if isinstance(base, NamedTupleMeta):
+ namedtuple_bases.append(base)
+ i = 0
+ if namedtuple_bases:
+ for name, index, doc, default in metacls._convert_fields(*namedtuple_bases):
+ base_dict[name] = index, doc, default
+ i = max(i, index)
+ # construct properly ordered dict with normalized indexes
+ for k, v in clsdict.items():
+ base_dict[k] = v
+ original_dict = base_dict
+ if size is not undefined and '_size_' in original_dict:
+ raise TypeError('_size_ cannot be set if "size" is passed in header')
+ add_order = isinstance(clsdict, _NamedTupleDict)
+ clsdict = _NamedTupleDict()
+ clsdict.setdefault('_size_', size or TupleSize.fixed)
+ unnumbered = OrderedDict()
+ numbered = OrderedDict()
+ _order_ = original_dict.pop('_order_', [])
+ if _order_ :
+ _order_ = _order_.replace(',',' ').split()
+ add_order = False
+ # and process this class
+ for k, v in original_dict.items():
+ if k not in original_dict._field_names:
+ clsdict[k] = v
+ else:
+ # TODO:normalize v here
+ if isinstance(v, baseinteger):
+ # assume an offset
+ v = v, undefined, undefined
+ i = v[0] + 1
+ target = numbered
+ elif isinstance(v, basestring):
+ # assume a docstring
+ if add_order:
+ v = i, v, undefined
+ i += 1
+ target = numbered
+ else:
+ v = undefined, v, undefined
+ target = unnumbered
+ elif isinstance(v, tuple) and len(v) in (2, 3) and isinstance(v[0], baseinteger) and isinstance(v[1], (basestring, NoneType)):
+ # assume an offset, a docstring, and (maybe) a default
+ if len(v) == 2:
+ v = v + (undefined, )
+ v = v
+ i = v[0] + 1
+ target = numbered
+ elif isinstance(v, tuple) and len(v) in (1, 2) and isinstance(v[0], (basestring, NoneType)):
+ # assume a docstring, and (maybe) a default
+ if len(v) == 1:
+ v = v + (undefined, )
+ if add_order:
+ v = (i, ) + v
+ i += 1
+ target = numbered
+ else:
+ v = (undefined, ) + v
+ target = unnumbered
+ else:
+ # refuse to guess further
+ raise ValueError('not sure what to do with %s=%r (should be OFFSET [, DOC [, DEFAULT]])' % (k, v))
+ target[k] = v
+ # all index values have been normalized
+ # deal with _order_ (or lack thereof)
+ fields = []
+ aliases = []
+ seen = set()
+ max_len = 0
+ if not _order_:
+ if unnumbered:
+ raise ValueError("_order_ not specified and OFFSETs not declared for %r" % (unnumbered.keys(), ))
+ for name, (index, doc, default) in sorted(numbered.items(), key=lambda nv: (nv[1][0], nv[0])):
+ if index in seen:
+ aliases.append(name)
+ else:
+ fields.append(name)
+ seen.add(index)
+ max_len = max(max_len, index + 1)
+ offsets = numbered
+ else:
+ # check if any unnumbered not in _order_
+ missing = set(unnumbered) - set(_order_)
+ if missing:
+ raise ValueError("unable to order fields: %s (use _order_ or specify OFFSET" % missing)
+ offsets = OrderedDict()
+ # if any unnumbered, number them from their position in _order_
+ i = 0
+ for k in _order_:
+ try:
+ index, doc, default = unnumbered.pop(k, None) or numbered.pop(k)
+ except IndexError:
+ raise ValueError('%s (from _order_) not found in %s' % (k, cls))
+ if index is not undefined:
+ i = index
+ if i in seen:
+ aliases.append(k)
+ else:
+ fields.append(k)
+ seen.add(i)
+ offsets[k] = i, doc, default
+ i += 1
+ max_len = max(max_len, i)
+ # now handle anything in numbered
+ for k, (index, doc, default) in sorted(numbered.items(), key=lambda nv: (nv[1][0], nv[0])):
+ if index in seen:
+ aliases.append(k)
+ else:
+ fields.append(k)
+ seen.add(index)
+ offsets[k] = index, doc, default
+ max_len = max(max_len, index+1)
+
+ # at this point fields and aliases should be ordered lists, offsets should be an
+ # OrdededDict with each value an int, str or None or undefined, default or None or undefined
+ assert len(fields) + len(aliases) == len(offsets), "number of fields + aliases != number of offsets"
+ assert set(fields) & set(offsets) == set(fields), "some fields are not in offsets: %s" % set(fields) & set(offsets)
+ assert set(aliases) & set(offsets) == set(aliases), "some aliases are not in offsets: %s" % set(aliases) & set(offsets)
+ for name, (index, doc, default) in offsets.items():
+ assert isinstance(index, baseinteger), "index for %s is not an int (%s:%r)" % (name, type(index), index)
+ assert isinstance(doc, (basestring, NoneType)) or doc is undefined, "doc is not a str, None, nor undefined (%s:%r)" % (name, type(doc), doc)
+
+ # create descriptors for fields
+ for name, (index, doc, default) in offsets.items():
+ clsdict[name] = _TupleAttributeAtIndex(name, index, doc, default)
+ clsdict['__slots__'] = ()
+
+ # create our new NamedTuple type
+ namedtuple_class = super(NamedTupleMeta, metacls).__new__(metacls, cls, bases, clsdict)
+ namedtuple_class._fields_ = fields
+ namedtuple_class._aliases_ = aliases
+ namedtuple_class._defined_len_ = max_len
+ return namedtuple_class
+
+ @staticmethod
+ def _convert_fields(*namedtuples):
+ "create list of index, doc, default triplets for cls in namedtuples"
+ all_fields = []
+ for cls in namedtuples:
+ base = len(all_fields)
+ for field in cls._fields_:
+ desc = getattr(cls, field)
+ all_fields.append((field, base+desc.index, desc.__doc__, desc.default))
+ return all_fields
+
+ def __add__(cls, other):
+ "A new NamedTuple is created by concatenating the _fields_ and adjusting the descriptors"
+ if not isinstance(other, NamedTupleMeta):
+ return NotImplemented
+ return NamedTupleMeta('%s%s' % (cls.__name__, other.__name__), (cls, other), {})
+
+ def __call__(cls, *args, **kwds):
+ """Creates a new NamedTuple class or an instance of a NamedTuple subclass.
+
+ NamedTuple should have args of (class_name, names, module)
+
+ `names` can be:
+
+ * A string containing member names, separated either with spaces or
+ commas. Values are auto-numbered from 1.
+ * An iterable of member names. Values are auto-numbered from 1.
+ * An iterable of (member name, value) pairs.
+ * A mapping of member name -> value.
+
+ `module`, if set, will be stored in the new class' __module__ attribute;
+
+ Note: if `module` is not set this routine will attempt to discover the
+ calling module by walking the frame stack; if this is unsuccessful
+ the resulting class will not be pickleable.
+
+ subclass should have whatever arguments and/or keywords will be used to create an
+ instance of the subclass
+ """
+ if cls is NamedTuple:
+ original_args = args
+ original_kwds = kwds.copy()
+ # create a new subclass
+ try:
+ if 'class_name' in kwds:
+ class_name = kwds.pop('class_name')
+ else:
+ class_name, args = args[0], args[1:]
+ if 'names' in kwds:
+ names = kwds.pop('names')
+ else:
+ names, args = args[0], args[1:]
+ if 'module' in kwds:
+ module = kwds.pop('module')
+ elif args:
+ module, args = args[0], args[1:]
+ else:
+ module = None
+ if 'type' in kwds:
+ type = kwds.pop('type')
+ elif args:
+ type, args = args[0], args[1:]
+ else:
+ type = None
+
+ except IndexError:
+ raise TypeError('too few arguments to NamedTuple: %s, %s' % (original_args, original_kwds))
+ if args or kwds:
+ raise TypeError('too many arguments to NamedTuple: %s, %s' % (original_args, original_kwds))
+ if PY2:
+ # if class_name is unicode, attempt a conversion to ASCII
+ if isinstance(class_name, unicode):
+ try:
+ class_name = class_name.encode('ascii')
+ except UnicodeEncodeError:
+ raise TypeError('%r is not representable in ASCII' % (class_name, ))
+ # quick exit if names is a NamedTuple
+ if isinstance(names, NamedTupleMeta):
+ names.__name__ = class_name
+ if type is not None and type not in names.__bases__:
+ names.__bases__ = (type, ) + names.__bases__
+ return names
+
+ metacls = cls.__class__
+ bases = (cls, )
+ clsdict = metacls.__prepare__(class_name, bases)
+
+ # special processing needed for names?
+ if isinstance(names, basestring):
+ names = names.replace(',', ' ').split()
+ if isinstance(names, (tuple, list)) and isinstance(names[0], basestring):
+ names = [(e, i) for (i, e) in enumerate(names)]
+ # Here, names is either an iterable of (name, index) or (name, index, doc, default) or a mapping.
+ item = None # in case names is empty
+ for item in names:
+ if isinstance(item, basestring):
+ # mapping
+ field_name, field_index = item, names[item]
+ else:
+ # non-mapping
+ if len(item) == 2:
+ field_name, field_index = item
+ else:
+ field_name, field_index = item[0], item[1:]
+ clsdict[field_name] = field_index
+ if type is not None:
+ if not isinstance(type, tuple):
+ type = (type, )
+ bases = type + bases
+ namedtuple_class = metacls.__new__(metacls, class_name, bases, clsdict)
+
+ # TODO: replace the frame hack if a blessed way to know the calling
+ # module is ever developed
+ if module is None:
+ try:
+ module = _sys._getframe(1).f_globals['__name__']
+ except (AttributeError, ValueError, KeyError):
+ pass
+ if module is None:
+ _make_class_unpicklable(namedtuple_class)
+ else:
+ namedtuple_class.__module__ = module
+
+ return namedtuple_class
+ else:
+ # instantiate a subclass
+ namedtuple_instance = cls.__new__(cls, *args, **kwds)
+ if isinstance(namedtuple_instance, cls):
+ namedtuple_instance.__init__(*args, **kwds)
+ return namedtuple_instance
+
+ @_bltin_property
+ def __fields__(cls):
+ return list(cls._fields_)
+ # collections.namedtuple compatibility
+ _fields = __fields__
+
+ @_bltin_property
+ def __aliases__(cls):
+ return list(cls._aliases_)
+
+ def __repr__(cls):
+ return "<NamedTuple %r>" % (cls.__name__, )
+
+namedtuple_dict = _Addendum(
+ dict=NamedTupleMeta.__prepare__('NamedTuple', (object, )),
+ doc="NamedTuple base class.\n\n Derive from this class to define new NamedTuples.\n\n",
+ ns=globals(),
+ )
+
+@namedtuple_dict
+def __new__(cls, *args, **kwds):
+ if cls._size_ is TupleSize.fixed and len(args) > cls._defined_len_:
+ raise TypeError('%d fields expected, %d received' % (cls._defined_len_, len(args)))
+ unknown = set(kwds) - set(cls._fields_) - set(cls._aliases_)
+ if unknown:
+ raise TypeError('unknown fields: %r' % (unknown, ))
+ final_args = list(args) + [undefined] * (len(cls.__fields__) - len(args))
+ for field, value in kwds.items():
+ index = getattr(cls, field).index
+ if final_args[index] != undefined:
+ raise TypeError('field %s specified more than once' % field)
+ final_args[index] = value
+ missing = []
+ for index, value in enumerate(final_args):
+ if value is undefined:
+ # look for default values
+ name = cls.__fields__[index]
+ default = getattr(cls, name).default
+ if default is undefined:
+ missing.append(name)
+ else:
+ final_args[index] = default
+ if missing:
+ if cls._size_ in (TupleSize.fixed, TupleSize.minimum):
+ raise TypeError('values not provided for field(s): %s' % ', '.join(missing))
+ while final_args and final_args[-1] is undefined:
+ final_args.pop()
+ missing.pop()
+ if cls._size_ is not TupleSize.variable or undefined in final_args:
+ raise TypeError('values not provided for field(s): %s' % ', '.join(missing))
+ return tuple.__new__(cls, tuple(final_args))
+
+@namedtuple_dict
+def __reduce_ex__(self, proto):
+ return self.__class__, tuple(getattr(self, f) for f in self._fields_)
+
+@namedtuple_dict
+def __repr__(self):
+ if len(self) == len(self._fields_):
+ return "%s(%s)" % (
+ self.__class__.__name__, ', '.join(['%s=%r' % (f, o) for f, o in zip(self._fields_, self)])
+ )
+ else:
+ return '%s(%s)' % (self.__class__.__name__, ', '.join([repr(o) for o in self]))
+
+@namedtuple_dict
+def __str__(self):
+ return "%s(%s)" % (
+ self.__class__.__name__, ', '.join(['%r' % (getattr(self, f), ) for f in self._fields_])
+ )
+
+@namedtuple_dict
+@_bltin_property
+def _fields_(self):
+ return list(self.__class__._fields_)
+
+ # compatibility methods with stdlib namedtuple
+@namedtuple_dict
+@_bltin_property
+def __aliases__(self):
+ return list(self.__class__._aliases_)
+
+@namedtuple_dict
+@_bltin_property
+def _fields(self):
+ return list(self.__class__._fields_)
+
+@namedtuple_dict
+@classmethod
+def _make(cls, iterable, new=None, len=None):
+ return cls.__new__(cls, *iterable)
+
+@namedtuple_dict
+def _asdict(self):
+ return OrderedDict(zip(self._fields_, self))
+
+@namedtuple_dict
+def _replace(self, **kwds):
+ current = self._asdict()
+ current.update(kwds)
+ return self.__class__(**current)
+
+NamedTuple = NamedTupleMeta('NamedTuple', (object, ), namedtuple_dict.resolve())
+del namedtuple_dict
+
+
+# Enum
+
+ # _init_ and value and AddValue
+ # -----------------------------
+ # by default, when defining a member everything after the = is "the value", everything is
+ # passed to __new__, everything is passed to __init__
+ #
+ # if _init_ is present then
+ # if `value` is not in _init_, everything is "the value", defaults apply
+ # if `value` is in _init_, only the first thing after the = is the value, and the rest will
+ # be passed to __init__
+ # if fewer values are present for member assignment than _init_ calls for, _generate_next_value_
+ # will be called in an attempt to generate them
+ #
+ # if AddValue is present then
+ # _generate_next_value_ is always called, and any generated values are prepended to provided
+ # values (custom _gnv_s can change that)
+ # default _init_ rules apply
+
+
+ # Constants used in Enum
+
+@export(globals())
+class EnumConstants(NamedConstant):
+ AddValue = constant('addvalue', 'prepends value(s) from _generate_next_value_ to each member')
+ MagicValue = constant('magicvalue', 'calls _generate_next_value_ when no arguments are given')
+ MultiValue = constant('multivalue', 'each member can have several values')
+ NoAlias = constant('noalias', 'duplicate valued members are distinct, not aliased')
+ Unique = constant('unique', 'duplicate valued members are not allowed')
+ def __repr__(self):
+ return self._name_
+
+
+ # Dummy value for Enum as EnumType explicity checks for it, but of course until
+ # EnumType finishes running the first time the Enum class doesn't exist. This
+ # is also why there are checks in EnumType like `if Enum is not None`.
+ #
+ # Ditto for Flag.
+
+Enum = ReprEnum = IntEnum = StrEnum = Flag = IntFlag = EJECT = KEEP = None
+
+class enum(object):
+ """
+ Helper class to track args, kwds.
+ """
+ def __init__(self, *args, **kwds):
+ self._args = args
+ self._kwds = dict(kwds.items())
+ self._hash = hash(args)
+ self.name = None
+
+ @_bltin_property
+ def args(self):
+ return self._args
+
+ @_bltin_property
+ def kwds(self):
+ return self._kwds.copy()
+
+ def __hash__(self):
+ return self._hash
+
+ def __eq__(self, other):
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return self.args == other.args and self.kwds == other.kwds
+
+ def __ne__(self, other):
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return self.args != other.args or self.kwds != other.kwds
+
+ def __repr__(self):
+ final = []
+ args = ', '.join(['%r' % (a, ) for a in self.args])
+ if args:
+ final.append(args)
+ kwds = ', '.join([('%s=%r') % (k, v) for k, v in enumsort(list(self.kwds.items()))])
+ if kwds:
+ final.append(kwds)
+ return '%s(%s)' % (self.__class__.__name__, ', '.join(final))
+
+_auto_null = SentinelType('no_value', (object, ), {})
+class auto(enum):
+ """
+ Instances are replaced with an appropriate value in Enum class suites.
+ """
+ enum_member = _auto_null
+ _value = _auto_null
+ _operations = []
+
+ def __and__(self, other):
+ new_auto = self.__class__()
+ new_auto._operations = self._operations[:]
+ new_auto._operations.append((_and_, (self, other)))
+ return new_auto
+
+ def __rand__(self, other):
+ new_auto = self.__class__()
+ new_auto._operations = self._operations[:]
+ new_auto._operations.append((_and_, (other, self)))
+ return new_auto
+
+ def __invert__(self):
+ new_auto = self.__class__()
+ new_auto._operations = self._operations[:]
+ new_auto._operations.append((_inv_, (self,)))
+ return new_auto
+
+ def __or__(self, other):
+ new_auto = self.__class__()
+ new_auto._operations = self._operations[:]
+ new_auto._operations.append((_or_, (self, other)))
+ return new_auto
+
+ def __ror__(self, other):
+ new_auto = self.__class__()
+ new_auto._operations = self._operations[:]
+ new_auto._operations.append((_or_, (other, self)))
+ return new_auto
+
+ def __xor__(self, other):
+ new_auto = self.__class__()
+ new_auto._operations = self._operations[:]
+ new_auto._operations.append((_xor_, (self, other)))
+ return new_auto
+
+ def __rxor__(self, other):
+ new_auto = self.__class__()
+ new_auto._operations = self._operations[:]
+ new_auto._operations.append((_xor_, (other, self)))
+ return new_auto
+
+ def __abs__(self):
+ new_auto = self.__class__()
+ new_auto._operations = self._operations[:]
+ new_auto._operations.append((_abs_, (self, )))
+ return new_auto
+
+ def __add__(self, other):
+ new_auto = self.__class__()
+ new_auto._operations = self._operations[:]
+ new_auto._operations.append((_add_, (self, other)))
+ return new_auto
+
+ def __radd__(self, other):
+ new_auto = self.__class__()
+ new_auto._operations = self._operations[:]
+ new_auto._operations.append((_add_, (other, self)))
+ return new_auto
+
+ def __neg__(self):
+ new_auto = self.__class__()
+ new_auto._operations = self._operations[:]
+ new_auto._operations.append((_neg_, (self, )))
+ return new_auto
+
+ def __pos__(self):
+ new_auto = self.__class__()
+ new_auto._operations = self._operations[:]
+ new_auto._operations.append((_pos_, (self, )))
+ return new_auto
+
+ if PY2:
+ def __div__(self, other):
+ new_auto = self.__class__()
+ new_auto._operations = self._operations[:]
+ new_auto._operations.append((_div_, (self, other)))
+ return new_auto
+
+ def __rdiv__(self, other):
+ new_auto = self.__class__()
+ new_auto._operations = self._operations[:]
+ new_auto._operations.append((_div_, (other, self)))
+ return new_auto
+
+ def __floordiv__(self, other):
+ new_auto = self.__class__()
+ new_auto._operations = self._operations[:]
+ new_auto._operations.append((_floordiv_, (self, other)))
+ return new_auto
+
+ def __rfloordiv__(self, other):
+ new_auto = self.__class__()
+ new_auto._operations = self._operations[:]
+ new_auto._operations.append((_floordiv_, (other, self)))
+ return new_auto
+
+ def __truediv__(self, other):
+ new_auto = self.__class__()
+ new_auto._operations = self._operations[:]
+ new_auto._operations.append((_truediv_, (self, other)))
+ return new_auto
+
+ def __rtruediv__(self, other):
+ new_auto = self.__class__()
+ new_auto._operations = self._operations[:]
+ new_auto._operations.append((_truediv_, (other, self)))
+ return new_auto
+
+ def __lshift__(self, other):
+ new_auto = self.__class__()
+ new_auto._operations = self._operations[:]
+ new_auto._operations.append((_lshift_, (self, other)))
+ return new_auto
+
+ def __rlshift__(self, other):
+ new_auto = self.__class__()
+ new_auto._operations = self._operations[:]
+ new_auto._operations.append((_lshift_, (other, self)))
+ return new_auto
+
+ def __rshift__(self, other):
+ new_auto = self.__class__()
+ new_auto._operations = self._operations[:]
+ new_auto._operations.append((_rshift_, (self, other)))
+ return new_auto
+
+ def __rrshift__(self, other):
+ new_auto = self.__class__()
+ new_auto._operations = self._operations[:]
+ new_auto._operations.append((_rshift_, (other, self)))
+ return new_auto
+
+ def __mod__(self, other):
+ new_auto = self.__class__()
+ new_auto._operations = self._operations[:]
+ new_auto._operations.append((_mod_, (self, other)))
+ return new_auto
+
+ def __rmod__(self, other):
+ new_auto = self.__class__()
+ new_auto._operations = self._operations[:]
+ new_auto._operations.append((_mod_, (other, self)))
+ return new_auto
+
+ def __mul__(self, other):
+ new_auto = self.__class__()
+ new_auto._operations = self._operations[:]
+ new_auto._operations.append((_mul_, (self, other)))
+ return new_auto
+
+ def __rmul__(self, other):
+ new_auto = self.__class__()
+ new_auto._operations = self._operations[:]
+ new_auto._operations.append((_mul_, (other, self)))
+ return new_auto
+
+ def __pow__(self, other):
+ new_auto = self.__class__()
+ new_auto._operations = self._operations[:]
+ new_auto._operations.append((_pow_, (self, other)))
+ return new_auto
+
+ def __rpow__(self, other):
+ new_auto = self.__class__()
+ new_auto._operations = self._operations[:]
+ new_auto._operations.append((_pow_, (other, self)))
+ return new_auto
+
+ def __sub__(self, other):
+ new_auto = self.__class__()
+ new_auto._operations = self._operations[:]
+ new_auto._operations.append((_sub_, (self, other)))
+ return new_auto
+
+ def __rsub__(self, other):
+ new_auto = self.__class__()
+ new_auto._operations = self._operations[:]
+ new_auto._operations.append((_sub_, (other, self)))
+ return new_auto
+
+ def __repr__(self):
+ if self._operations:
+ return 'auto(...)'
+ else:
+ return 'auto(%r, *%r, **%r)' % (self._value, self._args, self._kwds)
+
+ @_bltin_property
+ def value(self):
+ if self._value is not _auto_null and self._operations:
+ raise TypeError('auto() object out of sync')
+ elif self._value is _auto_null and not self._operations:
+ return self._value
+ elif self._value is not _auto_null:
+ return self._value
+ else:
+ return self._resolve()
+
+ @value.setter
+ def value(self, value):
+ if self._operations:
+ value = self._resolve(value)
+ self._value = value
+
+ def _resolve(self, base_value=None):
+ cls = self.__class__
+ for op, params in self._operations:
+ values = []
+ for param in params:
+ if isinstance(param, cls):
+ if param.value is _auto_null:
+ if base_value is None:
+ return _auto_null
+ else:
+ values.append(base_value)
+ else:
+ values.append(param.value)
+ else:
+ values.append(param)
+ value = op(*values)
+ self._operations[:] = []
+ self._value = value
+ return value
+
+
+class _EnumArgSpec(NamedTuple):
+ args = 0, 'all args except *args and **kwds'
+ varargs = 1, 'the name of the *args variable'
+ keywords = 2, 'the name of the **kwds variable'
+ defaults = 3, 'any default values'
+ required = 4, 'number of required values (no default available)'
+
+ def __new__(cls, _new_func):
+ argspec = getargspec(_new_func)
+ args, varargs, keywords, defaults = argspec
+ if defaults:
+ reqs = args[1:-len(defaults)]
+ else:
+ reqs = args[1:]
+ return tuple.__new__(_EnumArgSpec, (args, varargs, keywords, defaults, reqs))
+
+
+class _proto_member:
+ """
+ intermediate step for enum members between class execution and final creation
+ """
+
+ def __init__(self, value):
+ self.value = value
+
+ def __set_name__(self, enum_class, member_name):
+ """
+ convert each quasi-member into an instance of the new enum class
+ """
+ # first step: remove ourself from enum_class
+ delattr(enum_class, member_name)
+ # second step: create member based on enum_class
+ value = self.value
+ kwds = {}
+ args = ()
+ init_args = ()
+ extra_mv_args = ()
+ multivalue = None
+ if isinstance(value, tuple) and value and isinstance(value[0], auto):
+ multivalue = value
+ value = value[0]
+ if isinstance(value, auto) and value.value is _auto_null:
+ args = value.args
+ kwds = value.kwds
+ elif isinstance(value, auto):
+ kwds = value.kwds
+ args = (value.value, ) + value.args
+ value = value.value
+ elif isinstance(value, enum):
+ args = value.args
+ kwds = value.kwds
+ elif isinstance(value, Member):
+ value = value.value
+ args = (value, )
+ elif not isinstance(value, tuple):
+ args = (value, )
+ else:
+ args = value
+ if multivalue is not None:
+ value = (value, ) + multivalue[1:]
+ kwds = {}
+ args = value
+ del multivalue
+ # possibilities
+ #
+ # - no init, multivalue -> __new__[0], __init__(*[:]), extra=[1:]
+ # - init w/o value, multivalue -> __new__[0], __init__(*[:]), extra=[1:]
+ #
+ # - init w/value, multivalue -> __new__[0], __init__(*[1:]), extra=[1:]
+ #
+ # - init w/value, no multivalue -> __new__[0], __init__(*[1:]), extra=[]
+ #
+ # - init w/o value, no multivalue -> __new__[:], __init__(*[:]), extra=[]
+ # - no init, no multivalue -> __new__[:], __init__(*[:]), extra=[]
+ if enum_class._multivalue_ or 'value' in enum_class._creating_init_:
+ if enum_class._multivalue_:
+ # when multivalue is True, creating_init can be anything
+ mv_arg = args[0]
+ extra_mv_args = args[1:]
+ if 'value' in enum_class._creating_init_:
+ init_args = args[1:]
+ else:
+ init_args = args
+ args = args[0:1]
+ value = args[0]
+ else:
+ # 'value' is definitely in creating_init
+ if enum_class._auto_init_ and enum_class._new_args_:
+ # we have a custom __new__ and an auto __init__
+ # divvy up according to number of params in each
+ init_args = args[-len(enum_class._creating_init_)+1:]
+ if not enum_class._auto_args_:
+ args = args[:len(enum_class._new_args_.args)]
+ value = args[0]
+ elif enum_class._auto_init_:
+ # don't pass in value
+ init_args = args[1:]
+ args = args[0:1]
+ value = args[0]
+ elif enum_class._new_args_:
+ # do not modify args
+ value = args[0]
+ else:
+ # keep all args for user-defined __init__
+ # keep value as-is
+ init_args = args
+ else:
+ # either no creating_init, or it doesn't have 'value'
+ init_args = args
+ if enum_class._member_type_ is tuple: # special case for tuple enums
+ args = (args, ) # wrap it one more time
+ if not enum_class._use_args_:
+ enum_member = enum_class._new_member_(enum_class)
+ if not hasattr(enum_member, '_value_'):
+ enum_member._value_ = value
+ else:
+ enum_member = enum_class._new_member_(enum_class, *args, **kwds)
+ if not hasattr(enum_member, '_value_'):
+ if enum_class._member_type_ is object:
+ enum_member._value_ = value
+ else:
+ try:
+ enum_member._value_ = enum_class._member_type_(*args, **kwds)
+ except Exception:
+ te = TypeError('_value_ not set in __new__, unable to create it')
+ te.__cause__ = None
+ raise te
+ value = enum_member._value_
+ enum_member._name_ = member_name
+ enum_member.__objclass__ = enum_class
+ enum_member.__init__(*init_args, **kwds)
+ enum_member._sort_order_ = len(enum_class._member_names_)
+ # If another member with the same value was already defined, the
+ # new member becomes an alias to the existing one.
+ if enum_class._noalias_:
+ # unless NoAlias was specified
+ enum_class._member_names_.append(member_name)
+ else:
+ nonunique = defaultdict(list)
+ try:
+ try:
+ # try to do a fast lookup to avoid the quadratic loop
+ enum_member = enum_class._value2member_map_[value]
+ if enum_class._unique_:
+ nonunique[enum_member.name].append(member_name)
+ except TypeError:
+ # unhashable members are stored elsewhere
+ for unhashable_value, canonical_member in enum_class._value2member_seq_:
+ name = canonical_member.name
+ if unhashable_value == enum_member._value_:
+ if enum_class._unique_:
+ nonunique[name].append(member_name)
+ enum_member = canonical_member
+ break
+ else:
+ raise KeyError
+ except KeyError:
+ # this could still be an alias if the value is multi-bit and the
+ # class is a flag class
+ if (
+ Flag is None
+ or not issubclass(enum_class, Flag)
+ ):
+ # no other instances found, record this member in _member_names_
+ enum_class._member_names_.append(member_name)
+ elif (
+ Flag is not None
+ and issubclass(enum_class, Flag)
+ and _is_single_bit(value)
+ ):
+ # no other instances found, record this member in _member_names_
+ enum_class._member_names_.append(member_name)
+ if nonunique:
+ # duplicates not allowed if Unique specified
+ message = []
+ for name, aliases in nonunique.items():
+ bad_aliases = ','.join(aliases)
+ message.append('%s --> %s [%r]' % (name, bad_aliases, enum_class[name].value))
+ raise ValueError(
+ '%s: duplicate names found: %s' %
+ (enum_class.__name__, '; '.join(message))
+ )
+ # if self.value is an `auto()`, replace the value attribute with the new enum member
+ if isinstance(self.value, auto):
+ self.value.enum_member = enum_member
+ # get redirect in place before adding to _member_map_
+ # but check for other instances in parent classes first
+ need_override = False
+ descriptor = None
+ descriptor_property = None
+ for base in enum_class.__mro__[1:]:
+ descriptor = base.__dict__.get(member_name)
+ if descriptor is not None:
+ if isinstance(descriptor, (property, DynamicClassAttribute)):
+ break
+ else:
+ need_override = True
+ if isinstance(descriptor, _bltin_property) and descriptor_property is None:
+ descriptor_property = descriptor
+ # keep looking for an enum.property
+ descriptor = descriptor or descriptor_property
+ if descriptor and not need_override:
+ # previous enum.property found, no further action needed
+ pass
+ else:
+ redirect = property()
+ redirect.__set_name__(enum_class, member_name)
+ if descriptor and need_override:
+ # previous enum.property found, but some other inherited
+ # attribute is in the way; copy fget, fset, fdel to this one
+ redirect.fget = descriptor.fget
+ redirect.fset = descriptor.fset
+ redirect.fdel = descriptor.fdel
+ setattr(enum_class, member_name, redirect)
+ # now add to _member_map_ (even aliases)
+ enum_class._member_map_[member_name] = enum_member
+ #
+ # process (possible) MultiValues
+ values = (value, ) + extra_mv_args
+ if enum_class._multivalue_ and mv_arg not in values:
+ values += (mv_arg, )
+ enum_member._values_ = values
+ for value in values:
+ # first check if value has already been used
+ if enum_class._multivalue_ and (
+ value in enum_class._value2member_map_
+ or any(v == value for (v, m) in enum_class._value2member_seq_)
+ ):
+ raise ValueError('%r has already been used' % (value, ))
+ try:
+ # This may fail if value is not hashable. We can't add the value
+ # to the map, and by-value lookups for this value will be
+ # linear.
+ if enum_class._noalias_:
+ raise TypeError('cannot use dict to store value')
+ enum_class._value2member_map_[value] = enum_member
+ except TypeError:
+ enum_class._value2member_seq_ += ((value, enum_member), )
+
+
+class _EnumDict(dict):
+ """Track enum member order and ensure member names are not reused.
+
+ EnumType will use the names found in self._member_names as the
+ enumeration member names.
+ """
+ def __init__(self, cls_name, settings, start, constructor_init, constructor_start, constructor_boundary):
+ super(_EnumDict, self).__init__()
+ self._cls_name = cls_name
+ self._constructor_init = constructor_init
+ self._constructor_start = constructor_start
+ self._constructor_boundary = constructor_boundary
+ self._generate_next_value = None
+ self._member_names = []
+ self._member_names_set = set()
+ self._settings = settings
+ self._addvalue = addvalue = AddValue in settings
+ self._magicvalue = MagicValue in settings
+ self._multivalue = MultiValue in settings
+ if self._addvalue and self._magicvalue:
+ raise TypeError('%r: AddValue and MagicValue are mutually exclusive' % cls_name)
+ if self._multivalue and self._magicvalue:
+ raise TypeError('%r: MultiValue and MagicValue are mutually exclusive' % cls_name)
+ self._start = start
+ self._addvalue_value = start
+ self._new_args = ()
+ self._auto_args = False
+ # when the magic turns off
+ self._locked = MagicValue not in settings
+ # if init fields are specified
+ self._init = []
+ # list of temporary names
+ self._ignore = []
+ if self._magicvalue:
+ self._ignore = ['property', 'staticmethod', 'classmethod']
+ self._ignore_init_done = False
+ # if _sunder_ values can be changed via the class body
+ self._allow_init = True
+ self._last_values = []
+
+ def __getitem__(self, key):
+ if key == self._cls_name and self._cls_name not in self:
+ return enum
+ elif (
+ self._locked
+ or key in self
+ or key in self._ignore
+ or _is_sunder(key)
+ or _is_dunder(key)
+ ):
+ return super(_EnumDict, self).__getitem__(key)
+ elif self._magicvalue:
+ value = self._generate_next_value(key, self._start, len(self._member_names), self._last_values[:])
+ self.__setitem__(key, value)
+ return value
+ else:
+ raise Exception('Magic is not set -- why am I here?')
+
+ def __setitem__(self, key, value):
+ """Changes anything not sundured, dundered, nor a descriptor.
+
+ If an enum member name is used twice, an error is raised; duplicate
+ values are not checked for.
+
+ Single underscore (sunder) names are reserved.
+ """
+ # Flag classes that have MagicValue and __new__ will get a generated _gnv_
+ if _is_internal_class(self._cls_name, value):
+ pass
+ elif _is_private_name(self._cls_name, key):
+ pass
+ elif _is_sunder(key):
+ if key not in (
+ '_init_', '_settings_', '_order_', '_ignore_', '_start_',
+ '_create_pseudo_member_', '_create_pseudo_member_values_',
+ '_generate_next_value_', '_boundary_', '_numeric_repr_',
+ '_missing_', '_missing_value_', '_missing_name_',
+ '_iter_member_', '_iter_member_by_value_', '_iter_member_by_def_',
+ ):
+ raise ValueError('%r: _sunder_ names, such as %r, are reserved for future Enum use'
+ % (self._cls_name, key)
+ )
+ elif not self._allow_init and key not in (
+ 'create_pseudo_member_', '_missing_', '_missing_value_', '_missing_name_',
+ ):
+ # sunder is used during creation, must be specified first
+ raise ValueError('%r: cannot set %r after init phase' % (self._cls_name, key))
+ elif key == '_ignore_':
+ if self._ignore_init_done:
+ raise TypeError('%r: ignore can only be specified once' % self._cls_name)
+ if isinstance(value, basestring):
+ value = value.split()
+ else:
+ value = list(value)
+ self._ignore = value
+ already = set(value) & self._member_names_set
+ if already:
+ raise ValueError('%r: _ignore_ cannot specify already set names %s' % (
+ self._cls_name,
+ ', '.join(repr(a) for a in already)
+ ))
+ self._ignore_init_done = True
+ elif key == '_boundary_':
+ if self._constructor_boundary:
+ raise TypeError('%r: boundary specified in constructor and class body' % self._cls_name)
+ elif key == '_start_':
+ if self._constructor_start:
+ raise TypeError('%r: start specified in constructor and class body' % self._cls_name)
+ self._start = value
+ elif key == '_settings_':
+ if not isinstance(value, (set, tuple)):
+ value = (value, )
+ if not isinstance(value, set):
+ value = set(value)
+ self._settings |= value
+ if NoAlias in value and Unique in value:
+ raise TypeError('%r: NoAlias and Unique are mutually exclusive' % self._cls_name)
+ elif MultiValue in value and NoAlias in value:
+ raise TypeError('cannot specify both MultiValue and NoAlias' % self._cls_name)
+ allowed_settings = dict.fromkeys(['addvalue', 'magicvalue', 'noalias', 'unique', 'multivalue'])
+ for arg in self._settings:
+ if arg not in allowed_settings:
+ raise TypeError('%r: unknown qualifier %r (from %r)' % (self._cls_name, arg, value))
+ allowed_settings[arg] = True
+ self._multivalue = allowed_settings['multivalue']
+ self._addvalue = allowed_settings['addvalue']
+ self._magicvalue = allowed_settings['magicvalue']
+ self._locked = not self._magicvalue
+ if self._magicvalue and not self._ignore_init_done:
+ self._ignore = ['property', 'classmethod', 'staticmethod']
+ if self._addvalue and self._init and 'value' not in self._init:
+ self._init.insert(0, 'value')
+ value = tuple(self._settings)
+ elif key == '_init_':
+ if self._constructor_init:
+ raise TypeError('%r: init specified in constructor and in class body' % self._cls_name)
+ _init_ = value
+ if isinstance(_init_, basestring):
+ _init_ = _init_.replace(',',' ').split()
+ if self._addvalue and 'value' not in self._init:
+ self._init.insert(0, 'value')
+ if self._magicvalue:
+ raise TypeError("%r: _init_ and MagicValue are mutually exclusive" % self._cls_name)
+ self._init = _init_
+ value = _init_
+ elif key == '_generate_next_value_':
+ gnv = value
+ if value is not None:
+ if isinstance(value, staticmethod):
+ gnv = value.__func__
+ elif isinstance(value, classmethod):
+ raise TypeError('%r: _generate_next_value must be a staticmethod, not a classmethod' % self._cls_name)
+ else:
+ gnv = value
+ value = staticmethod(value)
+ self._auto_args = _check_auto_args(value)
+ setattr(self, '_generate_next_value', gnv)
+ elif _is_dunder(key):
+ if key == '__order__':
+ key = '_order_'
+ if not self._allow_init:
+ # _order_ is used during creation, must be specified first
+ raise ValueError('%r: cannot set %r after init phase' % (self._cls_name, key))
+ elif key == '__new__': # and self._new_to_init:
+ if isinstance(value, staticmethod):
+ value = value.__func__
+ self._new_args = _EnumArgSpec(value)
+ elif key == '__init_subclass__':
+ if not isinstance(value, classmethod):
+ value = classmethod(value)
+ if _is_descriptor(value):
+ self._locked = True
+ elif key in self._member_names_set:
+ # descriptor overwriting an enum?
+ raise TypeError('%r: attempt to reuse name: %r' % (self._cls_name, key))
+ elif key in self._ignore:
+ pass
+ elif not _is_descriptor(value):
+ self._allow_init = False
+ if key in self:
+ # enum overwriting a descriptor?
+ raise TypeError('%r: %s already defined as %r' % (self._cls_name, key, self[key]))
+ if type(value) is enum:
+ value.name = key
+ if self._addvalue:
+ raise TypeError('%r: enum() and AddValue are incompatible' % self._cls_name)
+ elif self._addvalue and not self._multivalue:
+ # generate a value
+ value = self._gnv(key, value)
+ elif self._multivalue:
+ # make sure it's a tuple
+ if not isinstance(value, tuple):
+ value = (value, )
+ if isinstance(value[0], auto):
+ value = (self._convert_auto(key, value[0]), ) + value[1:]
+ if self._addvalue:
+ value = self._gnv(key, value)
+ elif isinstance(value, auto):
+ value = self._convert_auto(key, value)
+ elif isinstance(value, tuple) and value and isinstance(value[0], auto):
+ value = (self._convert_auto(key, value[0]), ) + value[1:]
+ elif not isinstance(value, auto):
+ # call generate maybe if
+ # - init is specified; or
+ # - __new__ is specified;
+ # and either of them call for more values than are present
+ new_args = () or self._new_args and self._new_args.required
+ target_len = len(self._init or new_args)
+ if isinstance(value, tuple):
+ source_len = len(value)
+ else:
+ source_len = 1
+ multi_args = len(self._init) > 1 or new_args
+ if source_len < target_len :
+ value = self._gnv(key, value)
+ else:
+ pass
+ if self._init:
+ if isinstance(value, auto):
+ test_value = value.args
+ elif not isinstance(value, tuple):
+ test_value = (value, )
+ else:
+ test_value = value
+ if len(self._init) != len(test_value):
+ raise TypeError(
+ '%s.%s: number of fields provided do not match init [%r != %r]'
+ % (self._cls_name, key, self._init, test_value)
+ )
+ self._member_names.append(key)
+ self._member_names_set.add(key)
+ else:
+ # not a new member, turn off the autoassign magic
+ self._locked = True
+ self._allow_init = False
+ if not (_is_sunder(key) or _is_dunder(key) or _is_private_name(self._cls_name, key) or _is_descriptor(value)):
+ if isinstance(value, auto):
+ self._last_values.append(value.value)
+ elif isinstance(value, tuple) and value and isinstance(value[0], auto):
+ self._last_values.append(value[0].value)
+ elif isinstance(value, tuple):
+ if value:
+ self._last_values.append(value[0])
+ else:
+ self._last_values.append(value)
+ super(_EnumDict, self).__setitem__(key, value)
+
+ def _convert_auto(self, key, value):
+ # if auto.args or auto.kwds, compare to _init_ and __new__ -- if lacking, call gnv
+ # if not auto.args|kwds but auto.value is _auto_null -- call gnv
+ if value.args or value.kwds or value.value is _auto_null:
+ if value.args or value.kwds:
+ values = value.args
+ else:
+ values = ()
+ new_args = () or self._new_args and self._new_args.required
+ target_len = len(self._init or new_args) or 1
+ if isinstance(values, tuple):
+ source_len = len(values)
+ else:
+ source_len = 1
+ multi_args = len(self._init) > 1 or new_args
+ if source_len < target_len :
+ values = self._gnv(key, values)
+ if value.args:
+ value._args = values
+ else:
+ value.value = values
+ return value
+
+ def _gnv(self, key, value):
+ # generate a value
+ if self._auto_args:
+ if not isinstance(value, tuple):
+ value = (value, )
+ value = self._generate_next_value(key, self._start, len(self._member_names), self._last_values[:], *value)
+ else:
+ value = self._generate_next_value(key, self._start, len(self._member_names), self._last_values[:])
+ if isinstance(value, tuple) and len(value) == 1:
+ value = value[0]
+ return value
+
+
+no_arg = SentinelType('no_arg', (object, ), {})
+class EnumType(type):
+ """Metaclass for Enum"""
+
+ @classmethod
+ def __prepare__(metacls, cls, bases, init=None, start=None, settings=(), boundary=None, **kwds):
+ metacls._check_for_existing_members_(cls, bases)
+ if Flag is None and cls == 'Flag':
+ initial_flag = True
+ else:
+ initial_flag = False
+ # settings are a combination of current and all past settings
+ constructor_init = init is not None
+ constructor_start = start is not None
+ constructor_boundary = boundary is not None
+ if not isinstance(settings, tuple):
+ settings = settings,
+ settings = set(settings)
+ generate = None
+ order = None
+ # inherit previous flags
+ member_type, first_enum = metacls._get_mixins_(cls, bases)
+ if first_enum is not None:
+ generate = getattr(first_enum, '_generate_next_value_', None)
+ generate = getattr(generate, 'im_func', generate)
+ settings |= metacls._get_settings_(bases)
+ init = init or first_enum._auto_init_[:]
+ order = first_enum._order_function_
+ if start is None:
+ start = first_enum._start_
+ else:
+ # first time through -- creating Enum itself
+ start = 1
+ # check for custom settings
+ if AddValue in settings and init and 'value' not in init:
+ if isinstance(init, list):
+ init.insert(0, 'value')
+ else:
+ init = 'value ' + init
+ if NoAlias in settings and Unique in settings:
+ raise TypeError('%r: NoAlias and Unique are mutually exclusive' % cls)
+ if MultiValue in settings and NoAlias in settings:
+ raise TypeError('%r: MultiValue and NoAlias are mutually exclusive' % cls)
+ allowed_settings = dict.fromkeys(['addvalue', 'magicvalue', 'noalias', 'unique', 'multivalue'])
+ for arg in settings:
+ if arg not in allowed_settings:
+ raise TypeError('%r: unknown qualifier %r' % (cls, arg))
+ enum_dict = _EnumDict(cls_name=cls, settings=settings, start=start, constructor_init=constructor_init, constructor_start=constructor_start, constructor_boundary=constructor_boundary)
+ enum_dict._member_type = member_type
+ enum_dict._base_type = ('enum', 'flag')[
+ Flag is None and cls == 'Flag'
+ or
+ Flag is not None and any(issubclass(b, Flag) for b in bases)
+ ]
+ if Flag is not None and any(b is Flag for b in bases) and member_type not in (baseinteger + (object, )):
+ if Flag in bases:
+ # when a non-int data type is mixed in with Flag, we end up
+ # needing two values for two `__new__`s:
+ # - the integer value for the Flag itself; and
+ # - the mix-in value for the mix-in
+ #
+ # we provide a default `_generate_next_value_` to supply the int
+ # argument, and a default `__new__` to keep the two straight
+ def _generate_next_value_(name, start, count, values, *args, **kwds):
+ return (2 ** count, ) + args
+ enum_dict['_generate_next_value_'] = staticmethod(_generate_next_value_)
+ def __new__(cls, flag_value, type_value):
+ obj = member_type.__new__(cls, type_value)
+ obj._value_ = flag_value
+ return obj
+ enum_dict['__new__'] = __new__
+ else:
+ try:
+ enum_dict._new_args = _EnumArgSpec(first_enum.__new_member__)
+ except TypeError:
+ pass
+ elif not initial_flag:
+ if hasattr(first_enum, '__new_member__'):
+ enum_dict._new_args = _EnumArgSpec(first_enum.__new_member__)
+ if generate:
+ enum_dict['_generate_next_value_'] = generate
+ enum_dict._inherited_gnv = True
+ if init is not None:
+ if isinstance(init, basestring):
+ init = init.replace(',',' ').split()
+ enum_dict._init = init
+ elif hasattr(first_enum, '__new_member__'):
+ enum_dict._new_args = _EnumArgSpec(first_enum.__new_member__)
+ if order is not None:
+ enum_dict['_order_'] = staticmethod(order)
+ return enum_dict
+
+ def __init__(cls, *args , **kwds):
+ pass
+
+ def __new__(metacls, cls, bases, clsdict, init=None, start=None, settings=(), boundary=None, **kwds):
+ # handle py2 case first
+ if type(clsdict) is not _EnumDict:
+ # py2 and/or functional API gyrations
+ init = clsdict.pop('_init_', None)
+ start = clsdict.pop('_start_', None)
+ settings = clsdict.pop('_settings_', ())
+ _order_ = clsdict.pop('_order_', clsdict.pop('__order__', None))
+ _ignore_ = clsdict.pop('_ignore_', None)
+ _create_pseudo_member_ = clsdict.pop('_create_pseudo_member_', None)
+ _create_pseudo_member_values_ = clsdict.pop('_create_pseudo_member_values_', None)
+ _generate_next_value_ = clsdict.pop('_generate_next_value_', None)
+ _missing_ = clsdict.pop('_missing_', None)
+ _missing_value_ = clsdict.pop('_missing_value_', None)
+ _missing_name_ = clsdict.pop('_missing_name_', None)
+ _boundary_ = clsdict.pop('_boundary_', None)
+ _iter_member_ = clsdict.pop('_iter_member_', None)
+ _iter_member_by_value_ = clsdict.pop('_iter_member_by_value_', None)
+ _iter_member_by_def_ = clsdict.pop('_iter_member_by_def_', None)
+ __new__ = clsdict.pop('__new__', None)
+ __new__ = getattr(__new__, 'im_func', __new__)
+ __new__ = getattr(__new__, '__func__', __new__)
+ enum_members = dict([
+ (k, v) for (k, v) in clsdict.items()
+ if not (_is_sunder(k) or _is_dunder(k) or _is_private_name(cls, k) or _is_descriptor(v))
+ ])
+ original_dict = clsdict
+ clsdict = metacls.__prepare__(cls, bases, init=init, start=start)
+ if settings:
+ clsdict['_settings_'] = settings
+ init = init or clsdict._init
+ if _order_ is None:
+ _order_ = clsdict.get('_order_')
+ if _order_ is not None:
+ _order_ = _order_.__get__(cls)
+ if isinstance(original_dict, OrderedDict):
+ calced_order = original_dict
+ elif _order_ is None:
+ calced_order = [name for (name, value) in enumsort(list(enum_members.items()))]
+ elif isinstance(_order_, basestring):
+ calced_order = _order_ = _order_.replace(',', ' ').split()
+ elif callable(_order_):
+ if init:
+ if not isinstance(init, basestring):
+ init = ' '.join(init)
+ member = NamedTuple('member', init and 'name ' + init or ['name', 'value'])
+ calced_order = []
+ for name, value in enum_members.items():
+ if init:
+ if not isinstance(value, tuple):
+ value = (value, )
+ name_value = (name, ) + value
+ else:
+ name_value = tuple((name, value))
+ if member._defined_len_ != len(name_value):
+ raise TypeError('%d values expected (%s), %d received (%s)' % (
+ member._defined_len_,
+ ', '.join(member._fields_),
+ len(name_value),
+ ', '.join([repr(v) for v in name_value]),
+ ))
+ calced_order.append(member(*name_value))
+ calced_order = [m.name for m in sorted(calced_order, key=_order_)]
+ else:
+ calced_order = _order_
+ for name in (
+ '_missing_', '_missing_value_', '_missing_name_',
+ '_ignore_', '_create_pseudo_member_', '_create_pseudo_member_values_',
+ '_generate_next_value_', '_order_', '__new__',
+ '_missing_', '_missing_value_', '_missing_name_',
+ '_boundary_',
+ '_iter_member_', '_iter_member_by_value_', '_iter_member_by_def_',
+ ):
+ attr = locals()[name]
+ if attr is not None:
+ clsdict[name] = attr
+ # now add members
+ for k in calced_order:
+ try:
+ clsdict[k] = original_dict[k]
+ except KeyError:
+ # this error will be handled when _order_ is checked
+ pass
+ for k, v in original_dict.items():
+ if k not in calced_order:
+ clsdict[k] = v
+ del _order_, _ignore_, _create_pseudo_member_, _create_pseudo_member_values_,
+ del _generate_next_value_, _missing_, _missing_value_, _missing_name_
+ #
+ # resume normal path
+ clsdict._locked = True
+ #
+ # check for illegal enum names (any others?)
+ member_names = clsdict._member_names
+ invalid_names = set(member_names) & set(['mro', ''])
+ if invalid_names:
+ raise ValueError('invalid enum member name(s): %s' % (
+ ', '.join(invalid_names), ))
+ _order_ = clsdict.pop('_order_', None)
+ if isinstance(_order_, basestring):
+ _order_ = _order_.replace(',',' ').split()
+ init = clsdict._init
+ start = clsdict._start
+ settings = clsdict._settings
+ creating_init = []
+ new_args = clsdict._new_args
+ auto_args = clsdict._auto_args
+ auto_init = False
+ if init is not None:
+ auto_init = True
+ creating_init = init[:]
+ if 'value' in creating_init and creating_init[0] != 'value':
+ raise TypeError("'value', if specified, must be the first item in 'init'")
+ magicvalue = MagicValue in settings
+ multivalue = MultiValue in settings
+ noalias = NoAlias in settings
+ unique = Unique in settings
+ # an Enum class 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).
+ # an Enum class is final once enumeration items have been defined;
+ #
+ # remove any keys listed in _ignore_
+ clsdict.setdefault('_ignore_', []).append('_ignore_')
+ ignore = clsdict['_ignore_']
+ for key in ignore:
+ clsdict.pop(key, None)
+ #
+ boundary = boundary or clsdict.pop('_boundary_', None)
+ # convert to regular dict
+ clsdict = dict(clsdict.items())
+ member_type, first_enum = metacls._get_mixins_(cls, bases)
+ # get the method to create enum members
+ __new__, save_new, new_uses_args = metacls._find_new_(
+ clsdict,
+ member_type,
+ first_enum,
+ )
+ clsdict['_new_member_'] = staticmethod(__new__)
+ clsdict['_use_args_'] = new_uses_args
+ #
+ # convert future enum members into temporary _proto_members
+ # and record integer values in case this will be a Flag
+ flag_mask = 0
+ for name in member_names:
+ value = test_value = clsdict[name]
+ if isinstance(value, auto) and value.value is not _auto_null:
+ test_value = value.value
+ if isinstance(test_value, baseinteger):
+ flag_mask |= test_value
+ if isinstance(test_value, tuple) and test_value and isinstance(test_value[0], baseinteger):
+ flag_mask |= test_value[0]
+ clsdict[name] = _proto_member(value)
+ #
+ # temp stuff
+ clsdict['_creating_init_'] = creating_init
+ clsdict['_multivalue_'] = multivalue
+ clsdict['_magicvalue_'] = magicvalue
+ clsdict['_noalias_'] = noalias
+ clsdict['_unique_'] = unique
+ #
+ # house-keeping structures
+ clsdict['_member_names_'] = []
+ clsdict['_member_map_'] = OrderedDict()
+ clsdict['_member_type_'] = member_type
+ clsdict['_value2member_map_'] = {}
+ clsdict['_value2member_seq_'] = ()
+ clsdict['_settings_'] = settings
+ clsdict['_start_'] = start
+ clsdict['_auto_init_'] = init
+ clsdict['_new_args_'] = new_args
+ clsdict['_auto_args_'] = auto_args
+ clsdict['_order_function_'] = None
+ # now set the __repr__ for the value
+ clsdict['_value_repr_'] = metacls._find_data_repr_(cls, bases)
+ #
+ # Flag structures (will be removed if final class is not a Flag
+ clsdict['_boundary_'] = (
+ boundary
+ or getattr(first_enum, '_boundary_', None)
+ )
+ clsdict['_flag_mask_'] = flag_mask
+ clsdict['_all_bits_'] = 2 ** ((flag_mask).bit_length()) - 1
+ clsdict['_inverted_'] = None
+ #
+ # move skipped values out of the descriptor
+ for name, obj in clsdict.items():
+ if isinstance(obj, nonmember):
+ clsdict[name] = obj.value
+ #
+ # If a custom type is mixed into the Enum, and it does not know how
+ # to pickle itself, pickle.dumps will succeed but pickle.loads will
+ # fail. Rather than have the error show up later and possibly far
+ # from the source, sabotage the pickle protocol for this class so
+ # that pickle.dumps also fails.
+ #
+ # However, if the new class implements its own __reduce_ex__, do not
+ # sabotage -- it's on them to make sure it works correctly. We use
+ # __reduce_ex__ instead of any of the others as it is preferred by
+ # pickle over __reduce__, and it handles all pickle protocols.
+ unpicklable = False
+ if '__reduce_ex__' not in clsdict:
+ if member_type is not object:
+ methods = ('__getnewargs_ex__', '__getnewargs__',
+ '__reduce_ex__', '__reduce__')
+ if not any(m in member_type.__dict__ for m in methods):
+ _make_class_unpicklable(clsdict)
+ unpicklable = True
+ #
+ # create a default docstring if one has not been provided
+ if '__doc__' not in clsdict:
+ clsdict['__doc__'] = 'An enumeration.'
+ #
+ # create our new Enum type
+ try:
+ exc = None
+ enum_class = type.__new__(metacls, cls, bases, clsdict)
+ except RuntimeError as e:
+ # any exceptions raised by _proto_member (aka member.__new__) will get converted to
+ # a RuntimeError, so get that original exception back and raise
+ # it instead
+ exc = e.__cause__ or e
+ if exc is not None:
+ raise exc
+ #
+ # if Python 3.5 or ealier, implement the __set_name__ and
+ # __init_subclass__ protocols
+ if pyver < PY3_6:
+ for name in member_names:
+ enum_class.__dict__[name].__set_name__(enum_class, name)
+ for name, obj in enum_class.__dict__.items():
+ if name in member_names:
+ continue
+ if hasattr(obj, '__set_name__'):
+ obj.__set_name__(enum_class, name)
+ if Enum is not None:
+ super(enum_class, enum_class).__init_subclass__()
+ #
+ # double check that repr and friends are not the mixin's or various
+ # things break (such as pickle)
+ #
+ # Also, special handling for ReprEnum
+ if ReprEnum is not None and ReprEnum in bases:
+ if member_type is object:
+ raise TypeError(
+ 'ReprEnum subclasses must be mixed with a data type (i.e.'
+ ' int, str, float, etc.)'
+ )
+ if '__format__' not in clsdict:
+ enum_class.__format__ = member_type.__format__
+ clsdict['__format__'] = enum_class.__format__
+ if '__str__' not in clsdict:
+ method = member_type.__str__
+ if method is object.__str__:
+ # if member_type does not define __str__, object.__str__ will use
+ # its __repr__ instead, so we'll also use its __repr__
+ method = member_type.__repr__
+ enum_class.__str__ = method
+ clsdict['__str__'] = enum_class.__str__
+
+ for name in ('__repr__', '__str__', '__format__', '__reduce_ex__'):
+ if name in clsdict:
+ # class has defined/imported/copied the method
+ continue
+ class_method = getattr(enum_class, name)
+ obj_method = getattr(member_type, name, None)
+ enum_method = getattr(first_enum, name, None)
+ if obj_method is not None and obj_method == class_method:
+ if name == '__reduce_ex__' and unpicklable:
+ continue
+ setattr(enum_class, name, enum_method)
+ clsdict[name] = enum_method
+ #
+ # for Flag, add __or__, __and__, __xor__, and __invert__
+ if Flag is not None and issubclass(enum_class, Flag):
+ for name in (
+ '__or__', '__and__', '__xor__',
+ '__ror__', '__rand__', '__rxor__',
+ '__invert__'
+ ):
+ if name not in clsdict:
+ setattr(enum_class, name, getattr(Flag, name))
+ clsdict[name] = enum_method
+ #
+ # method resolution and int's are not playing nice
+ # Python's less than 2.6 use __cmp__
+ if pyver < PY2_6:
+ #
+ if issubclass(enum_class, int):
+ setattr(enum_class, '__cmp__', getattr(int, '__cmp__'))
+ #
+ elif PY2:
+ #
+ if issubclass(enum_class, int):
+ for method in (
+ '__le__',
+ '__lt__',
+ '__gt__',
+ '__ge__',
+ '__eq__',
+ '__ne__',
+ '__hash__',
+ ):
+ setattr(enum_class, method, getattr(int, method))
+ #
+ # replace any other __new__ with our own (as long as Enum is not None,
+ # anyway) -- again, this is to support pickle
+ if Enum is not None:
+ # if the user defined their own __new__, save it before it gets
+ # clobbered in case they subclass later
+ if save_new:
+ setattr(enum_class, '__new_member__', enum_class.__dict__['__new__'])
+ setattr(enum_class, '__new__', Enum.__dict__['__new__'])
+ #
+ # _order_ checking is spread out into three/four steps
+ # - ensure _order_ is a list, not a string nor a function
+ # - if enum_class is a Flag:
+ # - remove any non-single-bit flags from _order_
+ # - remove any aliases from _order_
+ # - check that _order_ and _member_names_ match
+ #
+ # _order_ step 1: ensure _order_ is a list
+ if _order_:
+ if isinstance(_order_, staticmethod):
+ _order_ = _order_.__func__
+ if callable(_order_):
+ # save order for future subclasses
+ enum_class._order_function_ = staticmethod(_order_)
+ # create ordered list for comparison
+ _order_ = [m.name for m in sorted(enum_class, key=_order_)]
+ #
+ # remove Flag structures if final class is not a Flag
+ if (
+ Flag is None and cls != 'Flag'
+ or Flag is not None and not issubclass(enum_class, Flag)
+ ):
+ delattr(enum_class, '_boundary_')
+ delattr(enum_class, '_flag_mask_')
+ delattr(enum_class, '_all_bits_')
+ delattr(enum_class, '_inverted_')
+ elif Flag is not None and issubclass(enum_class, Flag):
+ # ensure _all_bits_ is correct and there are no missing flags
+ single_bit_total = 0
+ multi_bit_total = 0
+ for flag in enum_class._member_map_.values():
+ if _is_single_bit(flag._value_):
+ single_bit_total |= flag._value_
+ else:
+ # multi-bit flags are considered aliases
+ multi_bit_total |= flag._value_
+ if enum_class._boundary_ is not KEEP:
+ missed = list(_iter_bits_lsb(multi_bit_total & ~single_bit_total))
+ if missed:
+ raise TypeError(
+ 'invalid Flag %r -- missing values: %s'
+ % (cls, ', '.join((str(i) for i in missed)))
+ )
+ enum_class._flag_mask_ = single_bit_total
+ enum_class._all_bits_ = 2 ** ((single_bit_total).bit_length()) - 1
+ #
+ # set correct __iter__
+ if [m._value_ for m in enum_class] != sorted([m._value_ for m in enum_class]):
+ enum_class._iter_member_ = enum_class._iter_member_by_def_
+ if _order_:
+ # _order_ step 2: remove any items from _order_ that are not single-bit
+ _order_ = [
+ o
+ for o in _order_
+ if o not in enum_class._member_map_ or _is_single_bit(enum_class[o]._value_)
+ ]
+ #
+ # check for constants with auto() values
+ for k, v in enum_class.__dict__.items():
+ if isinstance(v, constant) and isinstance(v.value, auto):
+ v.value = enum_class(v.value.value)
+ #
+ if _order_:
+ # _order_ step 3: remove aliases from _order_
+ _order_ = [
+ o
+ for o in _order_
+ if (
+ o not in enum_class._member_map_
+ or
+ (o in enum_class._member_map_ and o in enum_class._member_names_)
+ )]
+ # _order_ step 4: verify that _order_ and _member_names_ match
+ if _order_ != enum_class._member_names_:
+ raise TypeError(
+ 'member order does not match _order_:\n%r\n%r'
+ % (enum_class._member_names_, _order_)
+ )
+ return enum_class
+
+ def __bool__(cls):
+ """
+ classes/types should always be True.
+ """
+ return True
+
+ def __call__(cls, value=no_arg, names=None, module=None, qualname=None, type=None, start=1, boundary=None):
+ """Either returns an existing member, or creates a new enum class.
+
+ This method is used both when an enum class is given a value to match
+ to an enumeration member (i.e. Color(3)) and for the functional API
+ (i.e. Color = Enum('Color', names='red green blue')).
+
+ When used for the functional API: `module`, if set, will be stored in
+ the new class' __module__ attribute; `type`, if set, will be mixed in
+ as the first base class.
+
+ Note: if `module` is not set this routine will attempt to discover the
+ calling module by walking the frame stack; if this is unsuccessful
+ the resulting class will not be pickleable.
+ """
+ if names is None: # simple value lookup
+ return cls.__new__(cls, value)
+ # otherwise, functional API: we're creating a new Enum type
+ return cls._create_(value, names, module=module, qualname=qualname, type=type, start=start, boundary=boundary)
+
+ def __contains__(cls, member):
+ if not isinstance(member, Enum):
+ raise TypeError("%r (%r) is not an <aenum 'Enum'>" % (member, type(member)))
+ if not isinstance(member, cls):
+ return False
+ return True
+
+ def __delattr__(cls, attr):
+ # nicer error message when someone tries to delete an attribute
+ # (see issue19025).
+ if attr in cls._member_map_:
+ raise AttributeError(
+ "%s: cannot delete Enum member %r." % (cls.__name__, attr),
+ )
+ found_attr = _get_attr_from_chain(cls, attr)
+ if isinstance(found_attr, constant):
+ raise AttributeError(
+ "%s: cannot delete constant %r" % (cls.__name__, attr),
+ )
+ elif isinstance(found_attr, property):
+ raise AttributeError(
+ "%s: cannot delete property %r" % (cls.__name__, attr),
+ )
+ super(EnumType, cls).__delattr__(attr)
+
+ def __dir__(cls):
+ interesting = set(cls._member_names_ + [
+ '__class__', '__contains__', '__doc__', '__getitem__',
+ '__iter__', '__len__', '__members__', '__module__',
+ '__name__',
+ ])
+ if cls._new_member_ is not object.__new__:
+ interesting.add('__new__')
+ if cls.__init_subclass__ is not Enum.__init_subclass__:
+ interesting.add('__init_subclass__')
+ if hasattr(object, '__qualname__'):
+ interesting.add('__qualname__')
+ for method in ('__init__', '__format__', '__repr__', '__str__'):
+ if getattr(cls, method) not in (getattr(Enum, method), getattr(Flag, method)):
+ interesting.add(method)
+ if cls._member_type_ is object:
+ return sorted(interesting)
+ else:
+ # return whatever mixed-in data type has
+ return sorted(set(dir(cls._member_type_)) | interesting)
+
+ @_bltin_property
+ def __members__(cls):
+ """Returns a mapping of member name->value.
+
+ This mapping lists all enum members, including aliases. Note that this
+ is a copy of the internal mapping.
+ """
+ return cls._member_map_.copy()
+
+ def __getitem__(cls, name):
+ try:
+ return cls._member_map_[name]
+ except KeyError:
+ exc = _sys.exc_info()[1]
+ if Flag is not None and issubclass(cls, Flag) and '|' in name:
+ try:
+ # may be an __or__ed name
+ result = cls(0)
+ for n in name.split('|'):
+ result |= cls[n]
+ return result
+ except KeyError:
+ raise exc
+ result = cls._missing_name_(name)
+ if isinstance(result, cls):
+ return result
+ else:
+ raise exc
+
+ def __iter__(cls):
+ return (cls._member_map_[name] for name in cls._member_names_)
+
+ def __reversed__(cls):
+ return (cls._member_map_[name] for name in reversed(cls._member_names_))
+
+ def __len__(cls):
+ return len(cls._member_names_)
+
+ __nonzero__ = __bool__
+
+ def __repr__(cls):
+ return "<aenum %r>" % (cls.__name__, )
+
+ def __setattr__(cls, name, value):
+ """Block attempts to reassign Enum members/constants.
+
+ A simple assignment to the class namespace only changes one of the
+ several possible ways to get an Enum member from the Enum class,
+ resulting in an inconsistent Enumeration.
+ """
+ member_map = cls.__dict__.get('_member_map_', {})
+ if name in member_map:
+ raise AttributeError(
+ '%s: cannot rebind member %r.' % (cls.__name__, name),
+ )
+ found_attr = _get_attr_from_chain(cls, name)
+ if isinstance(found_attr, constant):
+ raise AttributeError(
+ "%s: cannot rebind constant %r" % (cls.__name__, name),
+ )
+ elif isinstance(found_attr, property):
+ raise AttributeError(
+ "%s: cannot rebind property %r" % (cls.__name__, name),
+ )
+ super(EnumType, cls).__setattr__(name, value)
+
+ def _convert(cls, *args, **kwds):
+ import warnings
+ warnings.warn("_convert is deprecated and will be removed, use"
+ " _convert_ instead.", DeprecationWarning, stacklevel=2)
+ return cls._convert_(*args, **kwds)
+
+ def _convert_(cls, name, module, filter, source=None, boundary=None, as_global=False):
+ """
+ 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
+ members = [(key, source[key]) for key in source.keys() if filter(key)]
+ try:
+ # sort by value, name
+ members.sort(key=lambda t: (t[1], t[0]))
+ except TypeError:
+ # unless some values aren't comparable, in which case sort by just name
+ members.sort(key=lambda t: t[0])
+ cls = cls(name, members, module=module, boundary=boundary or KEEP)
+ cls.__reduce_ex__ = _reduce_ex_by_name
+ if as_global:
+ global_enum(cls)
+ else:
+ module_globals.update(cls.__members__)
+ module_globals[name] = cls
+ return cls
+
+ def _create_(cls, class_name, names, module=None, qualname=None, type=None, start=1, boundary=None):
+ """Convenience method to create a new Enum class.
+
+ `names` can be:
+
+ * A string containing member names, separated either with spaces or
+ commas. Values are auto-numbered from 1.
+ * An iterable of member names. Values are auto-numbered from 1.
+ * An iterable of (member name, value) pairs.
+ * A mapping of member name -> value.
+ """
+ if PY2:
+ # if class_name is unicode, attempt a conversion to ASCII
+ if isinstance(class_name, unicode):
+ try:
+ class_name = class_name.encode('ascii')
+ except UnicodeEncodeError:
+ raise TypeError('%r is not representable in ASCII' % (class_name, ))
+ metacls = cls.__class__
+ if type is None:
+ bases = (cls, )
+ else:
+ bases = (type, cls)
+ _, first_enum = cls._get_mixins_(class_name, bases)
+ generate = getattr(first_enum, '_generate_next_value_', None)
+ generate = getattr(generate, 'im_func', generate)
+ # special processing needed for names?
+ if isinstance(names, basestring):
+ names = names.replace(',', ' ').split()
+ if isinstance(names, (tuple, list)) and names and isinstance(names[0], basestring):
+ original_names, names = names, []
+ last_values = []
+ for count, name in enumerate(original_names):
+ value = generate(name, start, count, last_values[:])
+ last_values.append(value)
+ names.append((name, value))
+ # Here, names is either an iterable of (name, value) or a mapping.
+ item = None # in case names is empty
+ clsdict = None
+ for item in names:
+ if clsdict is None:
+ # first time initialization
+ if isinstance(item, basestring):
+ clsdict = {}
+ else:
+ # remember the order
+ clsdict = metacls.__prepare__(class_name, bases)
+ if isinstance(item, basestring):
+ member_name, member_value = item, names[item]
+ else:
+ member_name, member_value = item
+ clsdict[member_name] = member_value
+ if clsdict is None:
+ # in case names was empty
+ clsdict = metacls.__prepare__(class_name, bases)
+ enum_class = metacls.__new__(metacls, class_name, bases, clsdict, boundary=boundary)
+ # TODO: replace the frame hack if a blessed way to know the calling
+ # module is ever developed
+ if module is None:
+ try:
+ module = _sys._getframe(2).f_globals['__name__']
+ except (AttributeError, KeyError):
+ pass
+ if module is None:
+ _make_class_unpicklable(enum_class)
+ else:
+ enum_class.__module__ = module
+ if qualname is not None:
+ enum_class.__qualname__ = qualname
+ return enum_class
+
+ @classmethod
+ def _check_for_existing_members_(mcls, class_name, bases):
+ if Enum is None:
+ return
+ for chain in bases:
+ for base in chain.__mro__:
+ if issubclass(base, Enum) and base._member_names_:
+ raise TypeError(
+ "<aenum %r> cannot extend %r"
+ % (class_name, base)
+ )
+ @classmethod
+ def _get_mixins_(mcls, class_name, bases):
+ """Returns the type for creating enum members, and the first inherited
+ enum class.
+
+ bases: the tuple of bases that was given to __new__
+ """
+ if not bases or Enum is None:
+ return object, Enum
+
+ mcls._check_for_existing_members_(class_name, bases)
+
+ # ensure final parent class is an Enum derivative, find any concrete
+ # data type, and check that Enum has no members
+ first_enum = bases[-1]
+ if not issubclass(first_enum, Enum):
+ raise TypeError("new enumerations should be created as "
+ "`EnumName([mixin_type, ...] [data_type,] enum_type)`")
+ member_type = mcls._find_data_type_(class_name, bases) or object
+ if first_enum._member_names_:
+ raise TypeError("cannot extend enumerations via subclassing")
+ #
+ return member_type, first_enum
+
+ @classmethod
+ def _find_data_repr_(mcls, class_name, bases):
+ for chain in bases:
+ for base in chain.__mro__:
+ if base is object:
+ continue
+ elif issubclass(base, Enum):
+ # if we hit an Enum, use it's _value_repr_
+ return base._value_repr_
+ elif '__repr__' in base.__dict__:
+ # this is our data repr
+ return base.__dict__['__repr__']
+ return None
+
+ @classmethod
+ def _find_data_type_(mcls, class_name, bases):
+ data_types = set()
+ for chain in bases:
+ candidate = None
+ for base in chain.__mro__:
+ if base is object or base is StdlibEnum or base is StdlibFlag:
+ continue
+ elif issubclass(base, Enum):
+ if base._member_type_ is not object:
+ data_types.add(base._member_type_)
+ elif '__new__' in base.__dict__:
+ if issubclass(base, Enum):
+ continue
+ elif StdlibFlag is not None and issubclass(base, StdlibFlag):
+ continue
+ data_types.add(candidate or base)
+ break
+ else:
+ candidate = candidate or base
+ if len(data_types) > 1:
+ raise TypeError('%r: too many data types: %r' % (class_name, data_types))
+ elif data_types:
+ return data_types.pop()
+ else:
+ return None
+
+ @staticmethod
+ def _get_settings_(bases):
+ """Returns the combined _settings_ of all Enum base classes
+
+ bases: the tuple of bases given to __new__
+ """
+ settings = set()
+ for chain in bases:
+ for base in chain.__mro__:
+ if issubclass(base, Enum):
+ for s in base._settings_:
+ settings.add(s)
+ return settings
+
+ @classmethod
+ def _find_new_(mcls, clsdict, member_type, first_enum):
+ """Returns the __new__ to be used for creating the enum members.
+
+ clsdict: the class dictionary given to __new__
+ member_type: the data type whose __new__ will be used by default
+ first_enum: enumeration to check for an overriding __new__
+ """
+ # now find the correct __new__, checking to see of one was defined
+ # by the user; also check earlier enum classes in case a __new__ was
+ # saved as __new_member__
+ __new__ = clsdict.get('__new__', None)
+ #
+ # should __new__ be saved as __new_member__ later?
+ save_new = first_enum is not None and __new__ is not None
+ #
+ if __new__ is None:
+ # check all possibles for __new_member__ before falling back to
+ # __new__
+ for method in ('__new_member__', '__new__'):
+ for possible in (member_type, first_enum):
+ target = getattr(possible, method, None)
+ if target not in (
+ None,
+ None.__new__,
+ object.__new__,
+ Enum.__new__,
+ StdlibEnum.__new__,
+ ):
+ __new__ = target
+ break
+ if __new__ is not None:
+ break
+ else:
+ __new__ = object.__new__
+ # 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 __new__ is object.__new__:
+ new_uses_args = False
+ else:
+ new_uses_args = True
+ #
+ return __new__, save_new, new_uses_args
+
+
+ # In order to support Python 2 and 3 with a single
+ # codebase we have to create the Enum methods separately
+ # and then use the `type(name, bases, dict)` method to
+ # create the class.
+
+EnumMeta = EnumType
+
+enum_dict = _Addendum(
+ dict=EnumType.__prepare__('Enum', (object, )),
+ doc="Generic enumeration.\n\n Derive from this class to define new enumerations.\n\n",
+ ns=globals(),
+ )
+
+@enum_dict
+def __init__(self, *args, **kwds):
+ # auto-init method
+ _auto_init_ = self._auto_init_
+ if _auto_init_ is None:
+ return
+ if 'value' in _auto_init_:
+ # remove 'value' from _auto_init_ as it has already been handled
+ _auto_init_ = _auto_init_[1:]
+ if _auto_init_:
+ if len(_auto_init_) < len(args):
+ raise TypeError('%d arguments expected (%s), %d received (%s)'
+ % (len(_auto_init_), _auto_init_, len(args), args))
+ for name, arg in zip(_auto_init_, args):
+ setattr(self, name, arg)
+ if len(args) < len(_auto_init_):
+ remaining_args = _auto_init_[len(args):]
+ for name in remaining_args:
+ value = kwds.pop(name, undefined)
+ if value is undefined:
+ raise TypeError('missing value for: %r' % (name, ))
+ setattr(self, name, value)
+ if kwds:
+ # too many keyword arguments
+ raise TypeError('invalid keyword(s): %s' % ', '.join(kwds.keys()))
+
+@enum_dict
+def __new__(cls, value):
+ # all enum instances are actually created during class construction
+ # without calling this method; this method is called by the metaclass'
+ # __call__ (i.e. Color(3) ), and by pickle
+ if NoAlias in cls._settings_:
+ raise TypeError('NoAlias enumerations cannot be looked up by value')
+ if type(value) is cls:
+ # For lookups like Color(Color.red)
+ # value = value.value
+ return value
+ # by-value search for a matching enum member
+ # see if it's in the reverse mapping (for hashable values)
+ try:
+ if value in cls._value2member_map_:
+ return cls._value2member_map_[value]
+ except TypeError:
+ # not there, now do long search -- O(n) behavior
+ for name, member in cls._value2member_seq_:
+ if name == value:
+ return member
+ # still not found -- try _missing_ hook
+ try:
+ exc = None
+ result = cls._missing_value_(value)
+ except Exception as e:
+ exc = e
+ result = None
+ if isinstance(result, cls) or getattr(cls, '_boundary_', None) is EJECT:
+ return result
+ else:
+ if value is no_arg:
+ ve_exc = ValueError('%s() should be called with a value' % (cls.__name__, ))
+ else:
+ ve_exc = ValueError("%r is not a valid %s" % (value, cls.__name__))
+ if result is None and exc is None:
+ raise ve_exc
+ elif exc is None:
+ exc = TypeError(
+ 'error in %s._missing_: returned %r instead of None or a valid member'
+ % (cls.__name__, result)
+ )
+ if not isinstance(exc, ValueError):
+ exc.__cause__ = ve_exc
+ raise exc
+
+@enum_dict
+@classmethod
+def __init_subclass__(cls, **kwds):
+ if pyver < PY3_6:
+ # end of the line
+ if kwds:
+ raise TypeError('unconsumed keyword arguments: %r' % (kwds, ))
+ else:
+ super(Enum, cls).__init_subclass__(**kwds)
+
+@enum_dict
+@staticmethod
+def _generate_next_value_(name, start, count, last_values, *args, **kwds):
+ for last_value in reversed(last_values):
+ try:
+ new_value = last_value + 1
+ break
+ except TypeError:
+ pass
+ else:
+ new_value = start
+ if args:
+ return (new_value, ) + args
+ else:
+ return new_value
+
+@enum_dict
+@classmethod
+def _missing_(cls, value):
+ "deprecated, use _missing_value_ instead"
+ return None
+
+@enum_dict
+@classmethod
+def _missing_value_(cls, value):
+ "used for failed value access"
+ return cls._missing_(value)
+
+@enum_dict
+@classmethod
+def _missing_name_(cls, name):
+ "used for failed item access"
+ return None
+
+@enum_dict
+def __repr__(self):
+ v_repr = self.__class__._value_repr_ or self._value_.__class__.__repr__
+ return "<%s.%s: %s>" % (self.__class__.__name__, self._name_, v_repr(self._value_))
+
+@enum_dict
+def __str__(self):
+ return "%s.%s" % (self.__class__.__name__, self._name_)
+
+if PY3:
+ @enum_dict
+ def __dir__(self):
+ """
+ Returns all members and all public methods
+ """
+ if self.__class__._member_type_ is object:
+ interesting = set(['__class__', '__doc__', '__eq__', '__hash__', '__module__', 'name', 'value'])
+ else:
+ interesting = set(object.__dir__(self))
+ for name in getattr(self, '__dict__', []):
+ if name[0] != '_':
+ interesting.add(name)
+ for cls in self.__class__.mro():
+ for name, obj in cls.__dict__.items():
+ if name[0] == '_':
+ continue
+ if isinstance(obj, property):
+ # that's an enum.property
+ if obj.fget is not None or name not in self._member_map_:
+ interesting.add(name)
+ else:
+ # in case it was added by `dir(self)`
+ interesting.discard(name)
+ else:
+ interesting.add(name)
+ return sorted(interesting)
+
+@enum_dict
+def __format__(self, format_spec):
+ # mixed-in Enums should use the mixed-in type's __format__, otherwise
+ # we can get strange results with the Enum name showing up instead of
+ # the value
+
+ # pure Enum branch / overridden __str__ branch
+ overridden_str = self.__class__.__str__ != Enum.__str__
+ if self._member_type_ is object or overridden_str:
+ cls = str
+ val = str(self)
+ # mix-in branch
+ else:
+ cls = self._member_type_
+ val = self.value
+ return cls.__format__(val, format_spec)
+
+@enum_dict
+def __hash__(self):
+ return hash(self._name_)
+
+@enum_dict
+def __reduce_ex__(self, proto):
+ return self.__class__, (self._value_, )
+
+
+####################################
+# Python's less than 2.6 use __cmp__
+
+if pyver < PY2_6:
+
+ @enum_dict
+ def __cmp__(self, other):
+ if type(other) is self.__class__:
+ if self is other:
+ return 0
+ return -1
+ return NotImplemented
+ raise TypeError("unorderable types: %s() and %s()" % (self.__class__.__name__, other.__class__.__name__))
+
+else:
+
+ @enum_dict
+ def __le__(self, other):
+ raise TypeError("unorderable types: %s() <= %s()" % (self.__class__.__name__, other.__class__.__name__))
+
+ @enum_dict
+ def __lt__(self, other):
+ raise TypeError("unorderable types: %s() < %s()" % (self.__class__.__name__, other.__class__.__name__))
+
+ @enum_dict
+ def __ge__(self, other):
+ raise TypeError("unorderable types: %s() >= %s()" % (self.__class__.__name__, other.__class__.__name__))
+
+ @enum_dict
+ def __gt__(self, other):
+ raise TypeError("unorderable types: %s() > %s()" % (self.__class__.__name__, other.__class__.__name__))
+
+
+@enum_dict
+def __eq__(self, other):
+ if type(other) is self.__class__:
+ return self is other
+ return NotImplemented
+
+@enum_dict
+def __ne__(self, other):
+ if type(other) is self.__class__:
+ return self is not other
+ return NotImplemented
+
+@enum_dict
+def __hash__(self):
+ return hash(self._name_)
+
+@enum_dict
+def __reduce_ex__(self, proto):
+ return self.__class__, (self._value_, )
+
+
+# enum.property is used to provide access to the `name`, `value', etc.,
+# properties of enum members while keeping some measure of protection
+# from modification, while still allowing for an enumeration to have
+# members named `name`, `value`, etc.. This works because enumeration
+# members are not set directly on the enum class -- enum.property will
+# look them up in _member_map_.
+
+@enum_dict
+@property
+def name(self):
+ return self._name_
+
+@enum_dict
+@property
+def value(self):
+ return self._value_
+
+@enum_dict
+@property
+def values(self):
+ return self._values_
+
+def _reduce_ex_by_name(self, proto):
+ return self.name
+
+Enum = EnumType('Enum', (object, ), enum_dict.resolve())
+del enum_dict
+
+ # Enum has now been created
+
+class ReprEnum(Enum):
+ """
+ Only changes the repr(), leaving str() and format() to the mixed-in type.
+ """
+
+
+class IntEnum(int, ReprEnum):
+ """
+ Enum where members are also (and must be) ints
+ """
+
+
+class StrEnum(str, ReprEnum):
+ """
+ Enum where members are also (and must already be) strings
+
+ default value is member name, lower-cased
+ """
+
+ def __new__(cls, *values, **kwds):
+ if kwds:
+ raise TypeError('%r: keyword arguments not supported' % (cls.__name__))
+ if values:
+ if not isinstance(values[0], str):
+ raise TypeError('%s: values must be str [%r is a %r]' % (cls.__name__, values[0], type(values[0])))
+ value = str(*values)
+ member = str.__new__(cls, value)
+ member._value_ = value
+ return member
+
+ __str__ = str.__str__
+
+ def _generate_next_value_(name, start, count, last_values):
+ """
+ Return the lower-cased version of the member name.
+ """
+ return name.lower()
+
+
+class LowerStrEnum(StrEnum):
+ """
+ Enum where members are also (and must already be) lower-case strings
+
+ default value is member name, lower-cased
+ """
+
+ def __new__(cls, value, *args, **kwds):
+ obj = StrEnum.__new_member__(cls, value, *args, **kwds)
+ if value != value.lower():
+ raise ValueError('%r is not lower-case' % value)
+ return obj
+
+
+class UpperStrEnum(StrEnum):
+ """
+ Enum where members are also (and must already be) upper-case strings
+
+ default value is member name, upper-cased
+ """
+
+ def __new__(cls, value, *args, **kwds):
+ obj = StrEnum.__new_member__(cls, value, *args, **kwds)
+ if value != value.upper():
+ raise ValueError('%r is not upper-case' % value)
+ return obj
+
+ def _generate_next_value_(name, start, count, last_values, *args, **kwds):
+ return name.upper()
+
+
+if PY3:
+ class AutoEnum(Enum):
+ """
+ automatically use _generate_next_value_ when values are missing (Python 3 only)
+ """
+ _settings_ = MagicValue
+
+
+class AutoNumberEnum(Enum):
+ """
+ Automatically assign increasing values to members.
+
+ Py3: numbers match creation order
+ Py2: numbers are assigned alphabetically by member name
+ (unless `_order_` is specified)
+ """
+
+ def __new__(cls, *args, **kwds):
+ value = len(cls.__members__) + 1
+ if cls._member_type_ is int:
+ obj = int.__new__(cls, value)
+ elif cls._member_type_ is long:
+ obj = long.__new__(cls, value)
+ else:
+ obj = object.__new__(cls)
+ obj._value_ = value
+ return obj
+
+
+class AddValueEnum(Enum):
+ _settings_ = AddValue
+
+
+class MultiValueEnum(Enum):
+ """
+ Multiple values can map to each member.
+ """
+ _settings_ = MultiValue
+
+
+class NoAliasEnum(Enum):
+ """
+ Duplicate value members are distinct, but cannot be looked up by value.
+ """
+ _settings_ = NoAlias
+
+
+class OrderedEnum(Enum):
+ """
+ Add ordering based on values of Enum members.
+ """
+
+ def __ge__(self, other):
+ if self.__class__ is other.__class__:
+ return self._value_ >= other._value_
+ return NotImplemented
+
+ def __gt__(self, other):
+ if self.__class__ is other.__class__:
+ return self._value_ > other._value_
+ return NotImplemented
+
+ def __le__(self, other):
+ if self.__class__ is other.__class__:
+ return self._value_ <= other._value_
+ return NotImplemented
+
+ def __lt__(self, other):
+ if self.__class__ is other.__class__:
+ return self._value_ < other._value_
+ return NotImplemented
+
+
+if sqlite3:
+ class SqliteEnum(Enum):
+ def __conform__(self, protocol):
+ if protocol is sqlite3.PrepareProtocol:
+ return self.name
+
+
+class UniqueEnum(Enum):
+ """
+ Ensure no duplicate values exist.
+ """
+ _settings_ = Unique
+
+
+def convert(enum, name, module, filter, source=None):
+ """
+ Create a new Enum subclass that replaces a collection of global constants
+
+ enum: Enum, IntEnum, ...
+ name: name of new Enum
+ module: name of module (__name__ in global context)
+ filter: function that returns True if name should be converted to Enum member
+ source: namespace to check (defaults to 'module')
+ """
+ # 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
+ members = dict((name, value) for name, value in source.items() if filter(name))
+ enum = enum(name, members, module=module)
+ enum.__reduce_ex__ = _reduce_ex_by_name
+ module_globals.update(enum.__members__)
+ module_globals[name] = enum
+
+def extend_enum(enumeration, name, *args, **kwds):
+ """
+ Add a new member to an existing Enum.
+ """
+ # there are four possibilities:
+ # - extending an aenum Enum or 3.11+ enum Enum
+ # - extending an aenum Flag or 3.11+ enum Flag
+ # - extending a pre-3.11 stdlib Enum Flag
+ # - extending a 3.11+ stdlib Flag
+ #
+ # fail early if name is already in the enumeration
+ if (
+ name in enumeration.__dict__
+ or name in enumeration._member_map_
+ or name in [t[1] for t in getattr(enumeration, '_value2member_seq_', ())]
+ ):
+ raise TypeError('%r already in use as %r' % (name, enumeration.__dict__.get(name, enumeration[name])))
+ # and check for other instances in parent classes
+ descriptor = None
+ for base in enumeration.__mro__[1:]:
+ descriptor = base.__dict__.get(name)
+ if descriptor is not None:
+ if isinstance(descriptor, (property, DynamicClassAttribute)):
+ break
+ else:
+ raise TypeError('%r already in use in superclass %r' % (name, base.__name__))
+ try:
+ _member_map_ = enumeration._member_map_
+ _member_names_ = enumeration._member_names_
+ _member_type_ = enumeration._member_type_
+ _value2member_map_ = enumeration._value2member_map_
+ base_attributes = set([a for b in enumeration.mro() for a in b.__dict__])
+ except AttributeError:
+ raise TypeError('%r is not a supported Enum' % (enumeration, ))
+ try:
+ _value2member_seq_ = enumeration._value2member_seq_
+ _multi_value_ = MultiValue in enumeration._settings_
+ _no_alias_ = NoAlias in enumeration._settings_
+ _unique_ = Unique in enumeration._settings_
+ _auto_init_ = enumeration._auto_init_ or []
+ except AttributeError:
+ # standard Enum
+ _value2member_seq_ = []
+ _multi_value_ = False
+ _no_alias_ = False
+ _unique_ = False
+ _auto_init_ = []
+ if _multi_value_ and not args:
+ # must specify values for multivalue enums
+ raise ValueError('no values specified for MultiValue enum %r' % enumeration.__name__)
+ mt_new = _member_type_.__new__
+ _new = getattr(enumeration, '__new_member__', mt_new)
+ if not args:
+ last_values = [m.value for m in enumeration]
+ count = len(enumeration)
+ start = getattr(enumeration, '_start_', None)
+ if start is None:
+ start = last_values and (last_values[-1] + 1) or 1
+ _gnv = getattr(enumeration, '_generate_next_value_', None)
+ if _gnv is not None:
+ args = ( _gnv(name, start, count, last_values), )
+ else:
+ # must be a 3.4 or 3.5 Enum
+ args = (start, )
+ if _new is object.__new__:
+ new_uses_args = False
+ else:
+ new_uses_args = True
+ if len(args) == 1:
+ [value] = args
+ else:
+ value = args
+ more_values = ()
+ kwds = {}
+ if isinstance(value, enum):
+ args = value.args
+ kwds = value.kwds
+ if not isinstance(value, tuple):
+ args = (value, )
+ else:
+ args = value
+ # tease value out of auto-init if specified
+ if 'value' in _auto_init_:
+ if 'value' in kwds:
+ value = kwds.pop('value')
+ else:
+ value, args = args[0], args[1:]
+ elif _multi_value_:
+ value, more_values, args = args[0], args[1:], ()
+ if new_uses_args:
+ args = (value, )
+ if _member_type_ is tuple:
+ args = (args, )
+ if not new_uses_args:
+ new_member = _new(enumeration)
+ if not hasattr(new_member, '_value_'):
+ new_member._value_ = value
+ else:
+ new_member = _new(enumeration, *args, **kwds)
+ if not hasattr(new_member, '_value_'):
+ new_member._value_ = _member_type_(*args)
+ value = new_member._value_
+ if _multi_value_:
+ if 'value' in _auto_init_:
+ args = more_values
+ else:
+ # put all the values back into args for the init call
+ args = (value, ) + more_values
+ new_member._name_ = name
+ new_member.__objclass__ = enumeration.__class__
+ new_member.__init__(*args)
+ new_member._values_ = (value, ) + more_values
+ # do final checks before modifying enum structures:
+ # - is new member a flag?
+ # - does the new member fit in the enum's declared _boundary_?
+ # - is new member an alias?
+ #
+ _all_bits_ = _flag_mask_ = None
+ if hasattr(enumeration, '_all_bits_'):
+ _all_bits_ = enumeration._all_bits_ | value
+ _flag_mask_ = enumeration._flag_mask_ | value
+ if enumeration._boundary_ != 'keep':
+ missed = list(_iter_bits_lsb(_flag_mask_ & ~_all_bits_))
+ if missed:
+ raise TypeError(
+ 'invalid Flag %r -- missing values: %s'
+ % (cls, ', '.join((str(i) for i in missed)))
+ )
+ # If another member with the same value was already defined, the
+ # new member becomes an alias to the existing one.
+ if _no_alias_:
+ # unless NoAlias was specified
+ return _finalize_extend_enum(enumeration, new_member, bits=_all_bits_, mask=_flag_mask_)
+ else:
+ # handle "normal" aliases
+ new_values = new_member._values_
+ for canonical_member in _member_map_.values():
+ canonical_values_ = getattr(canonical_member, '_values_', [canonical_member._value_])
+ for canonical_value in canonical_values_:
+ for new_value in new_values:
+ if canonical_value == new_value:
+ # name is an alias
+ if _unique_ or _multi_value_:
+ # aliases not allowed in Unique and MultiValue enums
+ raise ValueError('%r is a duplicate of %r' % (new_member, canonical_member))
+ else:
+ # aliased name can be added, remaining checks irrelevant
+ # aliases don't appear in member names (only in __members__ and _member_map_).
+ return _finalize_extend_enum(enumeration, canonical_member, name=name, bits=_all_bits_, mask=_flag_mask_, is_alias=True)
+ # not a standard alias, but maybe a flag alias
+ if pyver < PY3_6:
+ flag_bases = Flag,
+ else:
+ flag_bases = Flag, StdlibFlag
+ if issubclass(enumeration, flag_bases) and hasattr(enumeration, '_all_bits_'):
+ # handle the new flag type
+ if _is_single_bit(value):
+ # a new member! (an aliase would have been discovered in the previous loop)
+ return _finalize_extend_enum(enumeration, new_member, bits=_all_bits_, mask=_flag_mask_)
+ else:
+ # might be an 3.11 Flag alias
+ if value & enumeration._flag_mask_ == value and _value2member_map_.get(value) is not None:
+ # yup, it's an alias to existing members... and its an alias of an alias
+ canonical = _value2member_map_.get(value)
+ return _finalize_extend_enum(enumeration, canonical, name=name, bits=_all_bits_, mask=_flag_mask_, is_alias=True)
+ else:
+ return _finalize_extend_enum(enumeration, new_member, bits=_all_bits_, mask=_flag_mask_, is_alias=True)
+ else:
+ # if we get here, we have a brand new member
+ return _finalize_extend_enum(enumeration, new_member)
+
+def _finalize_extend_enum(enumeration, new_member, name=None, bits=None, mask=None, is_alias=False):
+ name = name or new_member.name
+ descriptor = None
+ for base in enumeration.__mro__[1:]:
+ descriptor = base.__dict__.get(name)
+ if descriptor is not None:
+ if isinstance(descriptor, (property, DynamicClassAttribute)):
+ break
+ else:
+ raise TypeError('%r already in use in superclass %r' % (name, base.__name__))
+ if not descriptor:
+ # get redirect in place before adding to _member_map_
+ redirect = property()
+ redirect.__set_name__(enumeration, name)
+ setattr(enumeration, name, redirect)
+ if not is_alias:
+ enumeration._member_names_.append(name)
+ enumeration._member_map_[name] = new_member
+ for v in getattr(new_member, '_values_', [new_member._value_]):
+ try:
+ enumeration._value2member_map_[v] = new_member
+ except TypeError:
+ enumeration._value2member_seq_ += ((v, new_member), )
+ if bits:
+ enumeration._all_bits_ = bits
+ enumeration._flag_mask_ = mask
+ return new_member
+
+def unique(enumeration):
+ """
+ Class decorator that ensures only unique members exist in an enumeration.
+ """
+ duplicates = []
+ for name, member in enumeration.__members__.items():
+ if name != member.name:
+ duplicates.append((name, member.name))
+ if duplicates:
+ duplicate_names = ', '.join(
+ ["%s -> %s" % (alias, name) for (alias, name) in duplicates]
+ )
+ raise ValueError('duplicate names found in %r: %s' %
+ (enumeration, duplicate_names)
+ )
+ return enumeration
+
+# Flag
+
+@export(globals())
+class FlagBoundary(StrEnum):
+ """
+ control how out of range values are handled
+ "strict" -> error is raised [default]
+ "conform" -> extra bits are discarded
+ "eject" -> lose flag status (becomes a normal integer)
+ """
+ STRICT = auto()
+ CONFORM = auto()
+ EJECT = auto()
+ KEEP = auto()
+assert FlagBoundary.STRICT == 'strict', (FlagBoundary.STRICT, FlagBoundary.CONFORM)
+
+class Flag(Enum):
+ """
+ Generic flag enumeration.
+
+ Derive from this class to define new flag enumerations.
+ """
+
+ _boundary_ = STRICT
+ _numeric_repr_ = repr
+
+
+ def _generate_next_value_(name, start, count, last_values, *args, **kwds):
+ """
+ Generate the next value when not given.
+
+ name: the name of the member
+ start: the initital start value or None
+ count: the number of existing members
+ last_value: the last value assigned or None
+ """
+ if not count:
+ if args:
+ return ((1, start)[start is not None], ) + args
+ else:
+ return (1, start)[start is not None]
+ else:
+ last_value = max(last_values)
+ try:
+ high_bit = _high_bit(last_value)
+ result = 2 ** (high_bit+1)
+ if args:
+ return (result,) + args
+ else:
+ return result
+ except Exception:
+ pass
+ raise TypeError('invalid Flag value: %r' % last_value)
+
+ @classmethod
+ def _iter_member_by_value_(cls, value):
+ """
+ Extract all members from the value in definition (i.e. increasing value) order.
+ """
+ for val in _iter_bits_lsb(value & cls._flag_mask_):
+ yield cls._value2member_map_.get(val)
+
+ _iter_member_ = _iter_member_by_value_
+
+ @classmethod
+ def _iter_member_by_def_(cls, value):
+ """
+ Extract all members from the value in definition order.
+ """
+ members = list(cls._iter_member_by_value_(value))
+ members.sort(key=lambda m: m._sort_order_)
+ for member in members:
+ yield member
+
+ @classmethod
+ def _missing_(cls, value):
+ """
+ return a member matching the given value, or None
+ """
+ return cls._create_pseudo_member_(value)
+
+ @classmethod
+ def _create_pseudo_member_(cls, *values):
+ """
+ Create a composite member.
+ """
+ value = values[0]
+ if not isinstance(value, baseinteger):
+ raise ValueError(
+ "%r is not a valid %s" % (value, getattr(cls, '__qualname__', cls.__name__))
+ )
+ # check boundaries
+ # - value must be in range (e.g. -16 <-> +15, i.e. ~15 <-> 15)
+ # - value must not include any skipped flags (e.g. if bit 2 is not
+ # defined, then 0d10 is invalid)
+ neg_value = None
+ if (
+ not ~cls._all_bits_ <= value <= cls._all_bits_
+ or value & (cls._all_bits_ ^ cls._flag_mask_)
+ ):
+ if cls._boundary_ is STRICT:
+ max_bits = max(value.bit_length(), cls._flag_mask_.bit_length())
+ raise ValueError(
+ "%s: invalid value: %r\n given %s\n allowed %s"
+ % (cls.__name__, value, bin(value, max_bits), bin(cls._flag_mask_, max_bits))
+ )
+ elif cls._boundary_ is CONFORM:
+ value = value & cls._flag_mask_
+ elif cls._boundary_ is EJECT:
+ return value
+ elif cls._boundary_ is KEEP:
+ if value < 0:
+ value = (
+ max(cls._all_bits_+1, 2**(value.bit_length()))
+ + value
+ )
+ else:
+ raise ValueError(
+ 'unknown flag boundary: %r' % (cls._boundary_, )
+ )
+ if value < 0:
+ neg_value = value
+ value = cls._all_bits_ + 1 + value
+ # get members and unknown
+ unknown = value & ~cls._flag_mask_
+ members = list(cls._iter_member_(value))
+ if unknown and cls._boundary_ is not KEEP:
+ raise ValueError(
+ '%s(%r) --> unknown values %r [%s]'
+ % (cls.__name__, value, unknown, bin(unknown))
+ )
+ # let class adjust values
+ values = cls._create_pseudo_member_values_(members, *values)
+ __new__ = getattr(cls, '__new_member__', None)
+ if cls._member_type_ is object and not __new__:
+ # construct a singleton enum pseudo-member
+ pseudo_member = object.__new__(cls)
+ else:
+ pseudo_member = (__new__ or cls._member_type_.__new__)(cls, *values)
+ if not hasattr(pseudo_member, 'value'):
+ pseudo_member._value_ = value
+ if members:
+ pseudo_member._name_ = '|'.join([m._name_ for m in members])
+ if unknown:
+ pseudo_member._name_ += '|%s' % cls._numeric_repr_(unknown)
+ else:
+ pseudo_member._name_ = None
+ # use setdefault in case another thread already created a composite
+ # with this value, but only if all members are known
+ # note: zero is a special case -- add it
+ if not unknown:
+ pseudo_member = cls._value2member_map_.setdefault(value, pseudo_member)
+ if neg_value is not None:
+ cls._value2member_map_[neg_value] = pseudo_member
+ return pseudo_member
+
+
+ @classmethod
+ def _create_pseudo_member_values_(cls, members, *values):
+ """
+ Return values to be fed to __new__ to create new member.
+ """
+ if cls._member_type_ in (baseinteger + (object, )):
+ return values
+ elif len(values) < 2:
+ return values + (cls._member_type_(), )
+ else:
+ return values
+
+ def __contains__(self, other):
+ """
+ Returns True if self has at least the same flags set as other.
+ """
+ if not isinstance(other, self.__class__):
+ raise TypeError(
+ "unsupported operand type(s) for 'in': '%s' and '%s'" % (
+ type(other).__name__, self.__class__.__name__))
+ if other._value_ == 0 or self._value_ == 0:
+ return False
+ return other._value_ & self._value_ == other._value_
+
+ def __iter__(self):
+ """
+ Returns flags in definition order.
+ """
+ for member in self._iter_member_(self._value_):
+ yield member
+
+ def __len__(self):
+ return _bit_count(self._value_)
+
+ def __repr__(self):
+ cls = self.__class__
+ if self._name_ is None:
+ # only zero is unnamed by default
+ return '<%s: %r>' % (cls.__name__, self._value_)
+ else:
+ return '<%s.%s: %r>' % (cls.__name__, self._name_, self._value_)
+
+ def __str__(self):
+ cls = self.__class__
+ if self._name_ is None:
+ return '%s(%s)' % (cls.__name__, self._value_)
+ else:
+ return '%s.%s' % (cls.__name__, self._name_)
+
+ if PY2:
+ def __nonzero__(self):
+ return bool(self._value_)
+ else:
+ def __bool__(self):
+ return bool(self._value_)
+
+ def __or__(self, other):
+ if isinstance(other, self.__class__):
+ other_value = other._value_
+ elif self._member_type_ is not object and isinstance(other, self._member_type_):
+ other_value = other
+ else:
+ return NotImplemented
+ return self.__class__(self._value_ | other_value)
+
+ def __and__(self, other):
+ if isinstance(other, self.__class__):
+ other_value = other._value_
+ elif self._member_type_ is not object and isinstance(other, self._member_type_):
+ other_value = other
+ else:
+ return NotImplemented
+ return self.__class__(self._value_ & other_value)
+
+ def __xor__(self, other):
+ if isinstance(other, self.__class__):
+ other_value = other._value_
+ elif self._member_type_ is not object and isinstance(other, self._member_type_):
+ other_value = other
+ else:
+ return NotImplemented
+ return self.__class__(self._value_ ^ other_value)
+
+ def __invert__(self):
+ if self._inverted_ is None:
+ if self._boundary_ is KEEP:
+ # use all bits
+ self._inverted_ = self.__class__(~self._value_)
+ else:
+ # calculate flags not in this member
+ self._inverted_ = self.__class__(self._flag_mask_ ^ self._value_)
+ self._inverted_._inverted_ = self
+ return self._inverted_
+
+ __ror__ = __or__
+ __rand__ = __and__
+ __rxor__ = __xor__
+
+
+
+class IntFlag(int, ReprEnum, Flag):
+ """Support for integer-based Flags"""
+
+ _boundary_ = EJECT
+
+
+def _high_bit(value):
+ """returns index of highest bit, or -1 if value is zero or negative"""
+ return value.bit_length() - 1
+
+def global_enum_repr(self):
+ """
+ use module.enum_name instead of class.enum_name
+
+ the module is the last module in case of a multi-module name
+ """
+ module = self.__class__.__module__.split('.')[-1]
+ return '%s.%s' % (module, self._name_)
+
+def global_flag_repr(self):
+ """
+ use module.flag_name instead of class.flag_name
+
+ the module is the last module in case of a multi-module name
+ """
+ module = self.__class__.__module__.split('.')[-1]
+ cls_name = self.__class__.__name__
+ if self._name_ is None:
+ return "%s.%s(%r)" % (module, cls_name, self._value_)
+ if _is_single_bit(self):
+ return '%s.%s' % (module, self._name_)
+ if self._boundary_ is not FlagBoundary.KEEP:
+ return '|'.join(['%s.%s' % (module, name) for name in self.name.split('|')])
+ else:
+ name = []
+ for n in self._name_.split('|'):
+ if n[0].isdigit():
+ name.append(n)
+ else:
+ name.append('%s.%s' % (module, n))
+ return '|'.join(name)
+
+def global_str(self):
+ """
+ use enum_name instead of class.enum_name
+ """
+ if self._name_ is None:
+ return "%s(%r)" % (cls_name, self._value_)
+ else:
+ return self._name_
+
+def global_enum(cls, update_str=False):
+ """
+ decorator that makes the repr() of an enum member reference its module
+ instead of its class; also exports all members to the enum's module's
+ global namespace
+ """
+ if issubclass(cls, Flag):
+ cls.__repr__ = global_flag_repr
+ else:
+ cls.__repr__ = global_enum_repr
+ if not issubclass(cls, ReprEnum) or update_str:
+ cls.__str__ = global_str
+ _sys.modules[cls.__module__].__dict__.update(cls.__members__)
+ return cls
+
+
+class module(object):
+
+ def __init__(self, cls, *args):
+ self.__name__ = cls.__name__
+ self._parent_module = cls.__module__
+ self.__all__ = []
+ all_objects = cls.__dict__
+ if not args:
+ args = [k for k, v in all_objects.items() if isinstance(v, (NamedConstant, Enum))]
+ for name in args:
+ self.__dict__[name] = all_objects[name]
+ self.__all__.append(name)
+
+ def register(self):
+ _sys.modules["%s.%s" % (self._parent_module, self.__name__)] = self
+
+if StdlibEnumMeta:
+
+ from _weakrefset import WeakSet
+
+ def __subclasscheck__(cls, subclass):
+ """
+ Override for issubclass(subclass, cls).
+ """
+ if not isinstance(subclass, type):
+ raise TypeError('issubclass() arg 1 must be a class (got %r)' % (subclass, ))
+ # Check cache
+ try:
+ cls.__dict__['_subclass_cache_']
+ except KeyError:
+ cls._subclass_cache_ = WeakSet()
+ cls._subclass_negative_cache_ = WeakSet()
+ except RecursionError:
+ import sys
+ exc, cls, tb = sys.exc_info()
+ exc = RecursionError('possible causes for endless recursion:\n - __getattribute__ is not ignoring __dunder__ attibutes\n - __instancecheck__ and/or __subclasscheck_ are (mutually) recursive\n see `aenum.remove_stdlib_integration` for temporary work-around')
+ raise_from_none(exc)
+ if subclass in cls._subclass_cache_:
+ return True
+ # Check negative cache
+ elif subclass in cls._subclass_negative_cache_:
+ return False
+ if cls is subclass:
+ cls._subclass_cache_.add(subclass)
+ return True
+ # Check if it's a direct subclass
+ if cls in getattr(subclass, '__mro__', ()):
+ cls._subclass_cache_.add(subclass)
+ return True
+ # Check if it's an aenum.Enum|IntEnum|IntFlag|Flag subclass
+ if cls is StdlibIntFlag and issubclass(subclass, IntFlag):
+ cls._subclass_cache_.add(subclass)
+ return True
+ elif cls is StdlibFlag and issubclass(subclass, Flag):
+ cls._subclass_cache_.add(subclass)
+ return True
+ elif cls is StdlibIntEnum and issubclass(subclass, IntEnum):
+ cls._subclass_cache_.add(subclass)
+ return True
+ if cls is StdlibEnum and issubclass(subclass, Enum):
+ cls._subclass_cache_.add(subclass)
+ return True
+ # No dice; update negative cache
+ cls._subclass_negative_cache_.add(subclass)
+ return False
+
+ def __instancecheck__(cls, instance):
+ subclass = instance.__class__
+ try:
+ return cls.__subclasscheck__(subclass)
+ except RecursionError:
+ import sys
+ exc, cls, tb = sys.exc_info()
+ exc = RecursionError('possible causes for endless recursion:\n - __getattribute__ is not ignoring __dunder__ attibutes\n - __instancecheck__ and/or __subclasscheck_ are (mutually) recursive\n see `aenum.remove_stdlib_integration` for temporary work-around')
+ raise_from_none(exc)
+
+ StdlibEnumMeta.__subclasscheck__ = __subclasscheck__
+ StdlibEnumMeta.__instancecheck__ = __instancecheck__
+
+def add_stdlib_integration():
+ if StdlibEnum:
+ StdlibEnumMeta.__subclasscheck__ = __subclasscheck__
+ StdlibEnumMeta.__instancecheck__ = __instancecheck__
+
+def remove_stdlib_integration():
+ """
+ Remove the __instancecheck__ and __subclasscheck__ overrides from the stdlib Enum.
+
+ Those overrides are in place so that code detecting stdlib enums will also detect
+ aenum enums. If a buggy __getattribute__, __instancecheck__, or __subclasscheck__
+ is defined on a custom EnumMeta then RecursionErrors can result; using this
+ function after importing aenum will solve that problem, but the better solution is
+ to fix the buggy method.
+ """
+ if StdlibEnum:
+ del StdlibEnumMeta.__instancecheck__
+ del StdlibEnumMeta.__subclasscheck__
+