diff options
author | ThereforeGames <95403634+ThereforeGames@users.noreply.github.com> | 2022-12-11 22:59:59 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-12-11 22:59:59 +0000 |
commit | 00ca6a6db4674713a10d1de312559cb924ed3c55 (patch) | |
tree | 467a1107f8c27f625511e8589bb1d919ceba3b5b /venv/Lib/site-packages/aenum/__init__.py | |
parent | 685f9631b56ff8bd43bce24ff5ce0f9a0e9af490 (diff) | |
download | stable-diffusion-webui-gfx803-00ca6a6db4674713a10d1de312559cb924ed3c55.tar.gz stable-diffusion-webui-gfx803-00ca6a6db4674713a10d1de312559cb924ed3c55.tar.bz2 stable-diffusion-webui-gfx803-00ca6a6db4674713a10d1de312559cb924ed3c55.zip |
Add files via upload
Diffstat (limited to 'venv/Lib/site-packages/aenum/__init__.py')
-rw-r--r-- | venv/Lib/site-packages/aenum/__init__.py | 4111 |
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__ + |