view env/lib/python3.7/site-packages/aenum/__init__.py @ 3:758bc20232e8 draft

"planemo upload commit 2a0fe2cc28b09e101d37293e53e82f61762262ec"
author shellac
date Thu, 14 May 2020 16:20:52 -0400
parents 26e78fe6e8c4
children
line wrap: on
line source

"""Python Advanced Enumerations & NameTuples"""

import sys as _sys
pyver = float('%s.%s' % _sys.version_info[:2])

import re

try:
    from collections import OrderedDict
except ImportError:
    OrderedDict = dict
from collections import defaultdict
try:
    import sqlite3
except ImportError:
    sqlite3 = None

if pyver >= 3:
    from functools import reduce

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 pyver < 3:
    from operator import div as _div_

if pyver >= 3:
    from inspect import getfullargspec
    def getargspec(method):
        args, varargs, keywords, defaults, _, _, _ = getfullargspec(method)
        return args, varargs, keywords, defaults
else:
    from inspect import getargspec


__all__ = [
        'NamedConstant', 'constant', 'skip', 'nonmember', 'member', 'no_arg',
        'Enum', 'IntEnum', 'AutoNumberEnum', 'OrderedEnum', 'UniqueEnum',
        'Flag', 'IntFlag',
        'AutoNumber', 'MultiValue', 'NoAlias', 'Unique',
        'enum', 'extend_enum', 'unique', 'enum_property',
        'NamedTuple', 'SqliteEnum',
        ]
if sqlite3 is None:
    __all__.remove('SqliteEnum')

version = 2, 2, 3

try:
    any
except NameError:
    def any(iterable):
        for element in iterable:
            if element:
                return True
        return False

try:
    basestring
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:
    unicode
except NameError:
    # In Python 3 unicode no longer exists (it's just str)
    unicode = str

try:
    long
    baseinteger = int, long
except NameError:
    baseinteger = int
# deprecated
baseint = baseinteger

try:
    NoneType
except NameError:
    NoneType = type(None)

try:
    # derive from stdlib enum if possible
    import enum
    if hasattr(enum, 'version'):
        StdlibEnumMeta = StdlibEnum = None
    else:
        from enum import EnumMeta as StdlibEnumMeta, Enum as StdlibEnum
    del enum
except ImportError:
    StdlibEnumMeta = StdlibEnum = None

# will be exported later
AutoValue = AutoNumber = MultiValue = NoAlias = Unique = None

class enum_property(object):
    """
    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_.
    """

    name = None  # set by metaclass

    def __init__(self, fget=None, doc=None):
        self.fget = fget
        self.__doc__ = doc or fget.__doc__

    def __call__(self, func, doc=None):
        self.fget = func
        self.__doc__ = self.__doc__ or doc or func.__doc__

    def __get__(self, instance, ownerclass=None):
        if instance is None:
            try:
                return ownerclass._member_map_[self.name]
            except KeyError:
                raise AttributeError(self.name)
        else:
            return self.fget(instance)

    def __set__(self, instance, value):
        raise AttributeError("can't set attribute %r" % (self.name, ))

    def __delete__(self, instance):
        raise AttributeError("can't delete attribute %r" % (self.name, ))

_RouteClassAttributeToGetattr = enum_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


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 < 3.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 _make_class_unpicklable(cls):
    """Make the given class un-picklable."""
    def _break_on_call_reduce(self, protocol=None):
        raise TypeError('%r cannot be pickled' % (self, ))
    cls.__reduce_ex__ = _break_on_call_reduce
    cls.__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

################
# Constant stuff
################

# metaclass and class dict for 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 pyver < 3:
        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)



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('_names_ are reserved for future NamedConstant use')
        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.
    """

    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_ = {}
        for name, obj in constants.items():
            newcls.__new__(newcls, name, obj)
        return newcls

    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 __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)

temp_constant_dict = {}
temp_constant_dict['__doc__'] = "NamedConstants protection.\n\n    Derive from this class to lock NamedConstants.\n\n"

def __new__(cls, name, value, doc=None):
    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__
    actual_type = type(value)
    value_type = cls._named_constant_cache_.get(actual_type)
    if value_type is None:
        value_type = type(cls.__name__, (NamedConstant, 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
    metacls.__setattr__(cls, name, obj)
    return obj
temp_constant_dict['__new__'] = __new__
del __new__

def __repr__(self):
    return "<%s.%s: %r>" % (
            self.__class__.__name__, self._name_, self._value_)
temp_constant_dict['__repr__'] = __repr__
del __repr__

NamedConstant = NamedConstantMeta('NamedConstant', (object, ), temp_constant_dict)
Constant = NamedConstant
del temp_constant_dict

# now for a 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_'):
                raise ValueError('_names_ are reserved for future NamedTuple use')
        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):
        return _NamedTupleDict()

    def __init__(cls, *args , **kwds):
        super(NamedTupleMeta, cls).__init__(*args)

    def __new__(metacls, cls, bases, clsdict, size=undefined):
        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 pyver < 3.0:
                # 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

    @property
    def __fields__(cls):
        return list(cls._fields_)
    # collections.namedtuple compatibility
    _fields = __fields__

    @property
    def __aliases__(cls):
        return list(cls._aliases_)

    def __repr__(cls):
        return "<NamedTuple %r>" % (cls.__name__, )

temp_namedtuple_dict = {}
temp_namedtuple_dict['__doc__'] = "NamedTuple base class.\n\n    Derive from this class to define new NamedTuples.\n\n"

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))

temp_namedtuple_dict['__new__'] = __new__
del __new__

def __reduce_ex__(self, proto):
    return self.__class__, tuple(getattr(self, f) for f in self._fields_)
temp_namedtuple_dict['__reduce_ex__'] = __reduce_ex__
del __reduce_ex__

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]))
temp_namedtuple_dict['__repr__'] = __repr__
del __repr__

def __str__(self):
    return "%s(%s)" % (
            self.__class__.__name__, ', '.join(['%r' % (getattr(self, f), ) for f in self._fields_])
            )
temp_namedtuple_dict['__str__'] = __str__
del __str__

## compatibility methods with stdlib namedtuple
@property
def __aliases__(self):
    return list(self.__class__._aliases_)
temp_namedtuple_dict['__aliases__'] = __aliases__
del __aliases__

@property
def __fields__(self):
    return list(self.__class__._fields_)
temp_namedtuple_dict['__fields__'] = __fields__
temp_namedtuple_dict['_fields'] = __fields__
del __fields__

def _make(cls, iterable, new=None, len=None):
    return cls.__new__(cls, *iterable)
temp_namedtuple_dict['_make'] = classmethod(_make)
del _make

def _asdict(self):
    return OrderedDict(zip(self._fields_, self))
temp_namedtuple_dict['_asdict'] = _asdict
del _asdict

def _replace(self, **kwds):
    current = self._asdict()
    current.update(kwds)
    return self.__class__(**current)
temp_namedtuple_dict['_replace'] = _replace
del _replace

NamedTuple = NamedTupleMeta('NamedTuple', (object, ), temp_namedtuple_dict)
del temp_namedtuple_dict

# defined now for immediate use

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

# Constants used in Enum

@export(globals())
class EnumConstants(NamedConstant):
    AutoValue = constant('autovalue', 'values are automatically created from _generate_next_value_')
    AutoNumber = constant('autonumber', 'integer value is prepended to members, beginning from START')
    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')


############
# Enum stuff
############

# Dummy value for Enum as EnumMeta explicity checks for it, but of course until
# EnumMeta finishes running the first time the Enum class doesn't exist.  This
# is also why there are checks in EnumMeta like `if Enum is not None`
Enum = Flag = None

class enum(object):
    """
    Helper class to track args, kwds.
    """
    def __init__(self, *args, **kwds):
        self._args = args
        self._kwds = kwds.items()
        self._hash = hash(args)
        self.name = None

    @property
    def args(self):
        return self._args

    @property
    def kwds(self):
        return dict([(k, v) for k, v in self._kwds])

    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 'enum(%s)' % ', '.join(final)

_auto_null = object()
class auto(enum):
    """
    Instances are replaced with an appropriate value in Enum class suites.
    """
    _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 pyver < 3:
        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



    @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 _EnumDict(dict):
    """Track enum member order and ensure member names are not reused.

    EnumMeta 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):
        super(_EnumDict, self).__init__()
        self._cls_name = cls_name
        self._constructor_init = constructor_init
        self._constructor_start = constructor_start
        # for Flag enumerations, we may need to get the _init_ from __new__
        self._new_to_init = False
        # list of enum members
        self._member_names = []
        self._settings = settings
        autonumber = AutoNumber in settings
        autovalue = AutoValue in settings
        multivalue = MultiValue in settings
        if autonumber and start is None:
            # starting value for AutoNumber
            start = 1
        elif start is not None and not autonumber:
            autonumber = True
        if start is not None:
            self._value = start - 1
        else:
            self._value = None
        # when the magic turns off
        self._locked = not (autovalue or autonumber)
        # if auto or autonumber
        self._autovalue = autovalue
        self._autonumber = autonumber
        # if multiple values are allowed
        self._multivalue = multivalue
        # if init fields are specified
        self._init = None
        # list of temporary names
        self._ignore = []
        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 key == '_auto_on_':
            self._locked = False
            if not self._autonumber:
                self._autovalue = True
            return None
        elif key == '_auto_off_':
            self._locked = True
            return None
        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._autonumber:
            try:
                # try to generate the next value
                value = self._value + 1
                self._value += 1
            except:
                # couldn't work the magic, report error
                raise KeyError('%s not found' % (key,))
        elif self._autovalue:
            value = self._generate_next_value(key, 1, len(self._member_names), self._last_values[:])
        else:
            raise Exception('neither AutoNumber nor AutoValue set -- why am I here?')
        self.__setitem__(key, value)
        return value

    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.
        """
        if _is_internal_class(self._cls_name, value):
            pass
        elif _is_sunder(key):
            if key not in (
                    '_init_', '_settings_', '_order_', '_ignore_', '_start_',
                    '_create_pseudo_member_', '_create_pseudo_member_values_',
                    '_generate_next_value_',
                    '_missing_', '_missing_value_', '_missing_name_',
                    ):
                raise ValueError('_names_ are reserved for  Enum use')
            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('cannot set %r after init phase' % (key, ))
            elif key == '_ignore_':
                if self._ignore_init_done:
                    raise TypeError('ignore can only be specified once')
                if isinstance(value, basestring):
                    value = value.split()
                else:
                    value = list(value)
                self._ignore = value
                already = set(value) & set(self._member_names)
                if already:
                    raise ValueError('_ignore_ cannot specify already set names: %r' % (already, ))
                self._ignore_init_done = True
            elif key == '_start_':
                if self._constructor_start:
                    raise TypeError('start specified in constructor and class body')
                if value is None:
                    self._value = None
                    self._autonumber = False
                    if not self._autovalue:
                        self._locked = True
                else:
                    self._value = value - 1
                    self._locked = False
                    self._autonumber = True
            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('cannot specify both NoAlias and Unique')
                elif MultiValue in value and NoAlias in value:
                    raise TypeError('cannot specify both MultiValue and NoAlias')
                elif AutoValue in value and AutoNumber in value:
                    raise TypeError('cannot specify both AutoValue and AutoNumber')
                allowed_settings = dict.fromkeys(['autovalue', 'autonumber', 'noalias', 'unique', 'multivalue'])
                for arg in value:
                    if arg not in allowed_settings:
                        raise TypeError('unknown qualifier: %r (from %r)' % (arg, value))
                    allowed_settings[arg] = True
                self._multivalue = allowed_settings['multivalue']
                self._autovalue = allowed_settings['autovalue']
                self._autonumber = allowed_settings['autonumber']
                self._locked = not (self._autonumber or self._autovalue)
                if self._autovalue and not self._ignore_init_done:
                    self._ignore = ['property', 'classmethod', 'staticmethod']
                if self._autonumber and self._value is None:
                    self._value = 0
                if self._autonumber and self._init and self._init[0:1] == ['value']:
                    self._init.pop(0)
                value = tuple(self._settings)
            elif key == '_init_':
                if self._constructor_init:
                    raise TypeError('init specified in constructor and in class body')
                _init_ = value
                if isinstance(_init_, basestring):
                    _init_ = _init_.replace(',',' ').split()
                if _init_[0:1] == ['value'] and self._autonumber:
                    _init_.pop(0)
                self._init = _init_
            elif key == '_generate_next_value_':
                if isinstance(value, staticmethod):
                    gnv = value.__func__
                elif isinstance(value, classmethod):
                    raise TypeError('_generate_next_value should be a staticmethod, not a classmethod')
                else:
                    gnv = value
                    value = staticmethod(value)
                setattr(self, '_generate_next_value', gnv)
                self._auto_args = _check_auto_args(value)
        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('cannot set %r after init phase' % (key, ))
            elif key == '__new__' and self._new_to_init:
                # ArgSpec(args=[...], varargs=[...], keywords=[...], defaults=[...]
                if isinstance(value, staticmethod):
                    value = value.__func__
                new_args = getargspec(value)[0][1:]
                self._init = new_args
            if _is_descriptor(value):
                self._locked = True
        elif key in self._member_names:
            # descriptor overwriting an enum?
            raise TypeError('attempt to reuse name: %r' % (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('%s already defined as: %r' % (key, self[key]))
            if self._multivalue:
                # make sure it's a tuple
                if not isinstance(value, tuple):
                    value = (value, )
                # do we need to calculate the next value?
                if self._autonumber:
                    if self._init:
                        target_length = len(self._init)
                        if self._init[0] != 'value':
                            target_length += 1
                        if len(value) != target_length:
                            value = (self._value + 1, ) + value
                    else:
                        try:
                            value = (self._value + 1, ) + value
                        except TypeError:
                            pass
                if self._autonumber:
                    self._value = value[0]
            elif self._autovalue and self._init and not isinstance(value, auto):
                # call generate iff init is specified and calls for more values than are present
                target_values = len(self._init)
                if not isinstance(value, tuple):
                    value = (value, )
                source_values = len(value)
                if target_values != source_values:
                    gnv = self._generate_next_value
                    if self._auto_args:
                        value = gnv(
                                key, 1,
                                len(self._member_names),
                                self._last_values[:],
                                *value
                                )
                    else:
                        value = gnv(
                                key,
                                1,
                                len(self._member_names),
                                self._last_values[:],
                                )

            elif self._autonumber and not self._locked:
                # convert any auto instances to integers
                if isinstance(value, auto):
                    value = self._value + 1
                elif isinstance(value, basestring):
                    pass
                else:
                    try:
                        new_value = []
                        for v in value:
                            if isinstance(v, auto):
                                new_value.append(self._value + 1)
                            else:
                                new_value.append(v)
                        value = tuple(new_value)
                    except TypeError:
                        # value wasn't iterable
                        pass
                if isinstance(value, int):
                    self._value = value
                elif isinstance(value, tuple):
                    if self._init is None:
                        # old behavior -> if first item is int, use it as value
                        #                 otherwise, generate a value and prepend it
                        if value and isinstance(value[0], baseinteger):
                            self._value = value[0]
                        else:
                            self._value += 1
                            value = (self._value, ) + value
                    elif len(value) == len(self._init):
                        # provide actual value for member
                        self._value += 1
                        value = (self._value, ) + value
                    elif 'value'  not in self._init and len(value) == len(self._init) + 1:
                        # actual value for member is provided
                        self._value = value[0]
                    elif 'value' in self._init and len(value) == len(self._init) - 1:
                        count = self._value + 1
                        value = count, value
                        self._value = count
                    else:
                        # mismatch
                        raise TypeError('%s: number of fields provided do not match init' % key)
                else:
                    if self._init is not None and (len(self._init) != 1 or 'value' in self._init):
                        raise TypeError('%s: number of fields provided do not match init' % key)
                    count = self._value + 1
                    value = count, value
                    self._value = count
            elif isinstance(value, auto):
                # if AutoNumber set use built-in value, not _generate_next_value_
                if self._autonumber:
                    value = self._value + 1
                    self._value = value
                else:
                    if value.value == _auto_null:
                        gnv = self._generate_next_value
                        prev_values = []
                        for v in self._last_values:
                            if isinstance(v, auto):
                                prev_values.append(v.value)
                            else:
                                prev_values.append(v)
                        if isinstance(gnv, staticmethod):
                            gnv = gnv.__func__
                        if self._auto_args:
                            value.value = gnv(
                                    key,
                                    1,
                                    len(self._member_names),
                                    prev_values,
                                    *value.args,
                                    **value.kwds
                                    )
                        else:
                            value.value = gnv(
                                    key,
                                    1,
                                    len(self._member_names),
                                    prev_values,
                                    )
            elif isinstance(value, enum):
                value.name = key
            else:
                pass
            self._member_names.append(key)
        else:
            # not a new member, turn off the autoassign magic
            self._locked = True
            self._allow_init = False
        if not _is_sunder(key) and not _is_dunder(key) and not _is_descriptor(value):
            if (self._autonumber or self._multivalue) and isinstance(value, tuple):
                self._last_values.append(value[0])
            else:
                self._last_values.append(value)
        super(_EnumDict, self).__setitem__(key, value)


no_arg = object()
class EnumMeta(StdlibEnumMeta or type):
    """Metaclass for Enum"""
    @classmethod
    def __prepare__(metacls, cls, bases, init=None, start=None, settings=()):
        # settings are a combination of current and all past settings
        constructor_init = init is not None
        constructor_start = start 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_(bases)
        if first_enum is not None:
            settings |= first_enum._settings_
            init = init or first_enum._auto_init_
            order = first_enum._order_function_
            if start is None:
                start = first_enum._start_
            generate = getattr(first_enum, '_generate_next_value_', None)
            generate = getattr(generate, 'im_func', generate)
        # check for custom settings
        if NoAlias in settings and Unique in settings:
            raise TypeError('cannot specify both NoAlias and Unique')
        elif MultiValue in settings and NoAlias in settings:
            raise TypeError('cannot specify both MultiValue and NoAlias')
        elif AutoValue in settings and AutoNumber in settings:
            raise TypeError('cannot specify both AutoValue and AutoNumber')
        allowed_settings = dict.fromkeys(['autovalue', 'autonumber', 'noalias', 'unique', 'multivalue'])
        for arg in settings:
            if arg not in allowed_settings:
                raise TypeError('unknown qualifier: %r' % (arg, ))
            allowed_settings[arg] = True
        enum_dict = _EnumDict(cls_name=cls, settings=settings, start=start, constructor_init=constructor_init, constructor_start=constructor_start)
        if settings & set([AutoValue, AutoNumber]) or start is not None:
            enum_dict['_ignore_'] = ['property', 'classmethod', 'staticmethod']
            enum_dict._ignore_init_done = False
        if generate:
            enum_dict['_generate_next_value_'] = generate
        if init is not None:
            if isinstance(init, basestring):
                init = init.replace(',',' ').split()
            if init[0:1] == ['value'] and AutoNumber in settings:
                init.pop(0)
            enum_dict._init = init
        elif Flag is not None and any(issubclass(b, Flag) for b in bases) and member_type not in (int, object):
            enum_dict._new_to_init = True
            if Flag in bases:
                # only happens on first mixin with Flag
                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:
                    new_args = getargspec(first_enum.__new_member__)[0][1:]
                    enum_dict._init = new_args
                except TypeError:
                    pass
        if order is not None:
            enum_dict['_order_'] = staticmethod(order)
        return enum_dict

    def __init__(cls, *args , **kwds):
        super(EnumMeta, cls).__init__(*args)

    def __new__(metacls, cls, bases, clsdict, init=None, start=None, settings=()):
        # handle py2 case first
        if type(clsdict) is not _EnumDict:
            # py2 ard/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)
            __new__ = clsdict.pop('__new__', None)
            enum_members = dict([
                    (k, v) for (k, v) in clsdict.items()
                    if not (_is_sunder(k) or _is_dunder(k) or _is_descriptor(v))
                    ])
            original_dict = clsdict
            clsdict = metacls.__prepare__(cls, bases, init=init, start=start, 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 (
                    '_ignore_', '_create_pseudo_member_', '_create_pseudo_member_values_',
                    '_generate_next_value_', '_order_', '__new__',
                    '_missing_', '_missing_value_', '_missing_name_',
                ):
                attr = locals()[name]
                if attr is not None:
                    clsdict[name] = attr
            # now add members
            for k in calced_order:
                clsdict[k] = original_dict[k]
            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
        if clsdict._new_to_init:
            # remove calculated _init_ as it's no longer needed
            clsdict._init = None
        clsdict._locked = True
        member_type, first_enum = metacls._get_mixins_(bases)
        _order_ = clsdict.pop('_order_', None)
        if isinstance(_order_, basestring):
            _order_ = _order_.replace(',',' ').split()
        init = clsdict._init
        start = clsdict._value
        settings = clsdict._settings
        if start is not None:
            start += 1
        creating_init = []
        auto_init = False
        if init is None and (AutoNumber in settings or start is not None):
                creating_init = ['value']
        elif init is not None:
            auto_init = True
            if (AutoNumber in settings or start is not None) and 'value' not in  init:
                creating_init = ['value'] + init
            else:
                creating_init = init[:]
        autonumber = AutoNumber in settings
        autovalue = AutoValue 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)
        # get the method to create enum members
        __new__, save_new, new_uses_args = metacls._find_new_(
                clsdict,
                member_type,
                first_enum,
                )
        # save enum items into separate mapping so they don't get baked into
        # the new class
        enum_members = dict((k, clsdict[k]) for k in clsdict._member_names)
        for name in clsdict._member_names:
            del clsdict[name]
        # move skipped values out of the descriptor, and add names to DynamicAttributes
        for name, obj in clsdict.items():
            if isinstance(obj, nonmember):
                dict.__setitem__(clsdict, name, obj.value)
            elif isinstance(obj, enum_property):
                obj.name = name
        # check for illegal enum names (any others?)
        invalid_names = set(enum_members) & set(['mro', ''])
        if invalid_names:
            raise ValueError('Invalid enum member name(s): %s' % (
                ', '.join(invalid_names), ))
        # create our new Enum type
        enum_class = type.__new__(metacls, cls, bases, clsdict)
        enum_class._member_names_ = []               # names in random order
        enum_class._member_map_ = OrderedDict()
        enum_class._member_type_ = member_type
        # save current flags for subclasses
        enum_class._settings_ = settings
        enum_class._start_ = start
        enum_class._auto_init_ = _auto_init_ = init
        enum_class._order_function_ = None
        if 'value' in creating_init and creating_init[0] != 'value':
            raise TypeError("'value', if specified, must be the first item in 'init'")
        # save attributes from super classes so we know if we can take
        # the shortcut of storing members in the class dict
        base_attributes = set([a for b in enum_class.mro() for a in b.__dict__])
        # Reverse value->name map for hashable values.
        enum_class._value2member_map_ = {}
        enum_class._value2member_seq_ = ()
        # instantiate them, checking for duplicates as we go
        # we instantiate first instead of checking for duplicates first in case
        # a custom __new__ is doing something funky with the values -- such as
        # auto-numbering ;)
        if __new__ is None:
            __new__ = enum_class.__new__
        for member_name in clsdict._member_names:
            value = enum_members[member_name]
            if isinstance(value, auto):
                value = value.value
            kwds = {}
            new_args = ()
            init_args = ()
            extra_mv_args = ()
            if 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
            # 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 multivalue or 'value' in creating_init:
                if multivalue:
                    # when multivalue is True, creating_init can be anything
                    new_args = args[0:1]
                    extra_mv_args = args[1:]
                    if 'value' in creating_init:
                        init_args = args[1:]
                    else:
                        init_args = args
                else:
                    # 'value' is definitely in creating_init
                    new_args = args[0:1]
                    if auto_init:
                        # don't pass in value
                        init_args = args[1:]
                    else:
                        # keep the all args for user-defined __init__
                        init_args = args
                value = new_args[0]
            else:
                # either no creating_init, or it doesn't have 'value'
                new_args = args
                init_args = args
            if member_type is tuple:   # special case for tuple enums
                new_args = (new_args, )     # wrap it one more time
            if not new_uses_args:
                enum_member = __new__(enum_class)
                if not hasattr(enum_member, '_value_'):
                    enum_member._value_ = value
            else:
                enum_member = __new__(enum_class, *new_args, **kwds)
                if not hasattr(enum_member, '_value_'):
                    enum_member._value_ = member_type(*new_args, **kwds)
            value = enum_member._value_
            enum_member._name_ = member_name
            enum_member.__objclass__ = enum_class
            enum_member.__init__(*init_args, **kwds)
            # If another member with the same value was already defined, the
            # new member becomes an alias to the existing one.
            if noalias:
                # unless NoAlias was specified
                enum_class._member_names_.append(member_name)
            else:
                nonunique = defaultdict(list)
                for name, canonical_member in enum_class._member_map_.items():
                    if canonical_member.value == enum_member._value_:
                        if unique:
                            nonunique[name].append(member_name)
                            continue
                        enum_member = canonical_member
                        break
                else:
                    # Aliases don't appear in member names (only in __members__).
                    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' % (name, bad_aliases))
                    raise ValueError(
                            'duplicate names found in %r: %s' %
                                (cls, ';  '.join(message))
                            )
            # performance boost for any member that would not shadow
            # an enum_property
            if member_name not in base_attributes:
                setattr(enum_class, member_name, enum_member)
            else:
                # otherwise make sure the thing being shadowed /is/ an
                # enum_property
                for parent in enum_class.mro()[1:]:
                    if member_name in parent.__dict__:
                        obj = parent.__dict__[member_name]
                        if not isinstance(obj, enum_property):
                            raise TypeError('%r already used: %r' % (member_name, obj))
                        # we're good
                        break
            # now add to _member_map_
            enum_class._member_map_[member_name] = enum_member
            values = (value, ) + extra_mv_args
            enum_member._values_ = values
            for value in values:
                # first check if value has already been used
                if 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 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), )
        # 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 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(enum_class)
                    unpicklable = True

        # double check that repr and friends are not the mixin's or various
        # things break (such as pickle)

        for name in ('__repr__', '__str__', '__format__', '__reduce_ex__'):
            enum_class_method = enum_class.__dict__.get(name, None)
            if enum_class_method:
                # 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)

        # method resolution and int's are not playing nice
        # Python's less than 2.6 use __cmp__

        if pyver < 2.6:

            if issubclass(enum_class, int):
                setattr(enum_class, '__cmp__', getattr(int, '__cmp__'))

        elif pyver < 3.0:

            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__'])

        # py3 support for definition order (helps keep py2/py3 code in sync)
        if _order_:
            if isinstance(_order_, staticmethod):
                # _order_ = staticmethod.__get__(enum_class)
                # _order_ = getattr(_order_, 'im_func', _order_)
                _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_)]
            if _order_ != enum_class._member_names_:
                raise TypeError('member order does not match _order_: %r %r' % (enum_class._member_names_, enum_class._member_map_.items()))
        return enum_class

    def __bool__(cls):
        """
        classes/types should always be True.
        """
        return True

    def __call__(cls, value=no_arg, names=None, module=None, type=None, start=1):
        """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, type=type, start=start)

    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),
                    )
        if isinstance(_get_attr_from_chain(cls, attr), constant):
            raise AttributeError(
                    "%s: cannot delete constant %r" % (cls.__name__, attr),
                    )
        super(EnumMeta, cls).__delattr__(attr)

    def __dir__(self):
        return (['__class__', '__doc__', '__members__', '__module__'] +
                self._member_names_)

    @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 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),
                    )
        cur_obj = cls.__dict__.get(name)
        if isinstance(cur_obj, constant):
            raise AttributeError(
                    '%s: cannot rebind constant %r' % (cls.__name__, name),
                    )
        super(EnumMeta, cls).__setattr__(name, value)

    def _create_(cls, class_name, names, module=None, type=None, start=1):
        """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 pyver < 3.0:
            # 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_(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)
        # 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
        return enum_class

    @staticmethod
    def _get_mixins_(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
        def _find_data_type(bases):
            for chain in bases:
                for base in chain.__mro__:
                    if base is object or base is StdlibEnum:
                        continue
                    elif '__new__' in base.__dict__:
                        if issubclass(base, Enum):
                            continue
                        return base

        # 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 = _find_data_type(bases) or object
        if first_enum._member_names_:
            raise TypeError("cannot extend enumerations via subclassing")

        return member_type, first_enum

    if pyver < 3.0:
        @staticmethod
        def _find_new_(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)
            if __new__:
                return None, True, True      # __new__, save_new, new_uses_args

            N__new__ = getattr(None, '__new__')
            O__new__ = getattr(object, '__new__')
            if Enum is None:
                E__new__ = N__new__
            else:
                E__new__ = Enum.__dict__['__new__']
            # check all possibles for __new_member__ before falling back to
            # __new__
            for method in ('__new_member__', '__new__'):
                for possible in (member_type, first_enum):
                    try:
                        target = possible.__dict__[method]
                    except (AttributeError, KeyError):
                        target = getattr(possible, method, None)
                    if target not in [
                            None,
                            N__new__,
                            O__new__,
                            E__new__,
                            ]:
                        if method == '__new_member__':
                            clsdict['__new__'] = target
                            return None, False, True
                        if isinstance(target, staticmethod):
                            target = target.__get__(member_type)
                        __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__, False, new_uses_args
    else:
        @staticmethod
        def _find_new_(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 = __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.
########################################################
temp_enum_dict = EnumMeta.__prepare__('Enum', (object, ))
temp_enum_dict['__doc__'] = "Generic enumeration.\n\n    Derive from this class to define new enumerations.\n\n"

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()))
temp_enum_dict['__init__'] = __init__
del __init__

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):
        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)
                    )
        exc.__context__ = ve_exc
        raise exc
temp_enum_dict['__new__'] = __new__
del __new__

@staticmethod
def _generate_next_value_(name, start, count, last_values, *args, **kwds):
    for last_value in reversed(last_values):
        try:
            return last_value + 1
        except TypeError:
            pass
    else:
        return start
temp_enum_dict['_generate_next_value_'] = _generate_next_value_
del _generate_next_value_

@classmethod
def _missing_(cls, value):
    "deprecated, use _missing_value_ instead"
    return None
temp_enum_dict['_missing_'] = _missing_
del _missing_

@classmethod
def _missing_value_(cls, value):
    "used for failed value access"
    return cls._missing_(value)
temp_enum_dict['_missing_value_'] = _missing_value_
del _missing_value_

@classmethod
def _missing_name_(cls, name):
    "used for failed item access"
    return None
temp_enum_dict['_missing_name_'] = _missing_name_
del _missing_name_

def __repr__(self):
    return "<%s.%s: %r>" % (
            self.__class__.__name__, self._name_, self._value_)
temp_enum_dict['__repr__'] = __repr__
del __repr__

def __str__(self):
    return "%s.%s" % (self.__class__.__name__, self._name_)
temp_enum_dict['__str__'] = __str__
del __str__

if pyver >= 3.0:
    def __dir__(self):
        added_behavior = [
                m
                for cls in self.__class__.mro()
                for m in cls.__dict__
                if m[0] != '_' and m not in self._member_map_
                ]
        return (['__class__', '__doc__', '__module__', ] + added_behavior)
    temp_enum_dict['__dir__'] = __dir__
    del __dir__

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)
temp_enum_dict['__format__'] = __format__
del __format__

def __hash__(self):
    return hash(self._name_)
temp_enum_dict['__hash__'] = __hash__
del __hash__

def __reduce_ex__(self, proto):
    return self.__class__, (self._value_, )
temp_enum_dict['__reduce_ex__'] = __reduce_ex__
del __reduce_ex__


####################################
# Python's less than 2.6 use __cmp__

if pyver < 2.6:

    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__))
    temp_enum_dict['__cmp__'] = __cmp__
    del __cmp__

else:

    def __le__(self, other):
        raise TypeError("unorderable types: %s() <= %s()" % (self.__class__.__name__, other.__class__.__name__))
    temp_enum_dict['__le__'] = __le__
    del __le__

    def __lt__(self, other):
        raise TypeError("unorderable types: %s() < %s()" % (self.__class__.__name__, other.__class__.__name__))
    temp_enum_dict['__lt__'] = __lt__
    del __lt__

    def __ge__(self, other):
        raise TypeError("unorderable types: %s() >= %s()" % (self.__class__.__name__, other.__class__.__name__))
    temp_enum_dict['__ge__'] = __ge__
    del __ge__

    def __gt__(self, other):
        raise TypeError("unorderable types: %s() > %s()" % (self.__class__.__name__, other.__class__.__name__))
    temp_enum_dict['__gt__'] = __gt__
    del __gt__


def __eq__(self, other):
    if type(other) is self.__class__:
        return self is other
    return NotImplemented
temp_enum_dict['__eq__'] = __eq__
del __eq__

def __ne__(self, other):
    if type(other) is self.__class__:
        return self is not other
    return NotImplemented
temp_enum_dict['__ne__'] = __ne__
del __ne__

def __hash__(self):
    return hash(self._name_)
temp_enum_dict['__hash__'] = __hash__
del __hash__

def __reduce_ex__(self, proto):
    return self.__class__, (self._value_, )
temp_enum_dict['__reduce_ex__'] = __reduce_ex__
del __reduce_ex__

def _convert(cls, name, module, filter, source=None):
    """
    Create a new Enum subclass that replaces a collection of global constants
    """
    # convert all constants from source (or module) that pass filter() to
    # a new Enum called name, and export the enum and its members back to
    # module;
    # also, replace the __reduce_ex__ method so unpickling works in
    # previous Python versions
    module_globals = vars(_sys.modules[module])
    if source:
        source = vars(source)
    else:
        source = module_globals
    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)
    cls.__reduce_ex__ = _reduce_ex_by_name
    module_globals.update(cls.__members__)
    module_globals[name] = cls
    return cls
temp_enum_dict['_convert'] = classmethod(_convert)
del _convert

# 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_.
#
# This method is also very slow, so EnumMeta will add members directlyi
# to the Enum class if it won't shadow other instance attributes

@enum_property
def name(self):
    return self._name_
temp_enum_dict['name'] = name
del name

@enum_property
def value(self):
    return self._value_
temp_enum_dict['value'] = value
del value

@enum_property
def values(self):
    return self._values_
temp_enum_dict['values'] = values
del values

def _reduce_ex_by_name(self, proto):
    return self.name

if StdlibEnum is not None:
    Enum = EnumMeta('Enum', (StdlibEnum, ), temp_enum_dict)
else:
    Enum = EnumMeta('Enum', (object, ), temp_enum_dict)
del temp_enum_dict

# Enum has now been created
###########################

class IntEnum(int, Enum):
    """Enum where members are also (and must be) ints"""

if pyver >= 3:
    class AutoEnum(Enum):
        """
        automatically use _generate_next_value_ when values are missing (Python 3 only)
        """
        _settings_ = AutoValue

class AutoNumberEnum(Enum):
    """
    Automatically assign increasing values to members.

    Py3: numbers match creation order
    Py2: numbers are assigned alphabetically by member name
    """
    def __new__(cls, *args, **kwds):
        value = len(cls.__members__) + 1
        obj = object.__new__(cls)
        obj._value_ = value
        return obj

class MultiValueEnum(Enum):
    """
    Multiple values can map to each member.
    """
    _settings_ = MultiValue

class NoAliasEnum(Enum):
    """
    Duplicate value members are distinct, and 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, **_private_kwds):
    """
    Add a new member to an existing Enum.
    """
    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_
        # _auto_number_ = enumeration._auto_number_
        _multi_value_ = MultiValue in enumeration._settings_
        _no_alias_ = NoAlias in enumeration._settings_
        _unique_ = Unique in enumeration._settings_
        # _unique_ = Unique in enumeration._settings_
        _auto_init_ = enumeration._auto_init_ or []
    except AttributeError:
        # standard Enum
        _value2member_seq_ = []
        # _auto_number_ = False
        _multi_value_ = False
        _no_alias_ = False
        # _unique_ = False
        _auto_init_ = []
    mt_new = _member_type_.__new__
    _new = getattr(enumeration, '__new_member__', mt_new)
    if not args:
        _gnv = getattr(enumeration, '_generate_next_value_')
        if _gnv is None:
            raise TypeError('value not provided and _generate_next_value_ missing')
        last_values = [m.value for m in enumeration]
        count = len(enumeration)
        start = getattr(enumeration, '_start_')
        if start is None:
            start = last_values and last_values[0] or 1
        args = ( _gnv(name, start, count, last_values), )
    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 _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_
    new_member._name_ = name
    new_member.__objclass__ = enumeration.__class__
    new_member.__init__(*args)
    if _private_kwds.get('create_only'):
        return new_member
    # If another member with the same value was already defined, the
    # new member becomes an alias to the existing one.
    is_alias = False
    if _no_alias_:
        # unless NoAlias was specified
        _member_names_.append(name)
        _member_map_[name] = new_member
    else:
        for canonical_member in _member_map_.values():
            _values_ = getattr(canonical_member, '_values_', [canonical_member._value_])
            for canonical_value in _values_:
                if canonical_value == new_member._value_:
                    # name is an alias
                    if _unique_ or _multi_value_:
                        # aliases not allowed if Unique specified
                        raise ValueError('%s is a duplicate of %s' % (name, canonical_member.name))
                    if name not in base_attributes:
                        setattr(enumeration, name, canonical_member)
                    else:
                        # check type of name
                        for parent in enumeration.mro()[1:]:
                            if name in parent.__dict__:
                                obj = parent.__dict__[name]
                                if not isinstance(obj, enum_property):
                                    raise TypeError('%r already used: %r' % (name, obj))
                                break
                    # Aliases don't appear in member names (only in __members__ and _member_map_).
                    _member_map_[new_member._name_] = canonical_member
                    new_member = canonical_member
                    is_alias = True
                    break
            if is_alias:
                break
        else:
            # not an alias
            values = (value, ) + more_values
            new_member._values_ = values
            for value in (value, ) + more_values:
                # first check if value has already been used
                if _multi_value_ and (
                        value in _value2member_map_
                        or any(v == value for (v, m) in _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 _no_alias_:
                        raise TypeError('cannot use dict to store value')
                    _value2member_map_[value] = new_member
                except TypeError:
                    _value2member_seq_ += ((value, new_member), )
            if name not in base_attributes:
                setattr(enumeration, name, new_member)
            else:
                # check type of name
                for parent in enumeration.mro()[1:]:
                    if name in parent.__dict__:
                        obj = parent.__dict__[name]
                        if not isinstance(obj, enum_property):
                            raise TypeError('%r already used: %r' % (name, obj))
                        break
            _member_names_.append(name)
            _member_map_[name] = new_member
            try:
                _value2member_map_[value] = new_member
            except TypeError:
                pass

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

class Flag(Enum):
    """Support for flags"""

    def _generate_next_value_(name, start, count, last_values):
        """
        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:
            return (1, start)[start is not None]
        error = False
        for last_value in reversed(last_values):
            if isinstance(last_value, auto):
                last_value = last_value.value
            try:
                high_bit = _high_bit(last_value)
                break
            except Exception:
                error = True
                break
        if error:
            raise TypeError('invalid Flag value: %r' % (last_value, ))
        return 2 ** (high_bit+1)

    @classmethod
    def _missing_(cls, value):
        original_value = value
        if value < 0:
            value = ~value
        possible_member = cls._create_pseudo_member_(value)
        if original_value < 0:
            possible_member = ~possible_member
        return possible_member

    @classmethod
    def _create_pseudo_member_(cls, *values):
        """
        Create a composite member iff value contains only members.
        """
        value = values[0]
        pseudo_member = cls._value2member_map_.get(value, None)
        if pseudo_member is None:
            # verify all bits are accounted for
            members, extra_flags = _decompose(cls, value)
            if extra_flags:
                raise ValueError("%r is not a valid %s" % (value, cls.__name__))
            # give subclasses a chance to modify values for new pseudo-member
            values = cls._create_pseudo_member_values_(members, *values)
            # construct a singleton enum pseudo-member
            pseudo_member = extend_enum(cls, None, *values, create_only=True)
            # use setdefault in case another thread already created a composite
            # with this value
            pseudo_member = cls._value2member_map_.setdefault(value, pseudo_member)
        return pseudo_member

    @classmethod
    def _create_pseudo_member_values_(cls, members, *values):
        return values

    def __contains__(self, other):
        if not isinstance(other, Flag):
            raise TypeError("%r (%r) is not an <aenum 'Flag'>" % (other, type(other)))
        if not isinstance(other, self.__class__):
            return False
        return other._value_ & self._value_ == other._value_

    def __repr__(self):
        cls = self.__class__
        if self._name_ is not None:
            return '<%s.%s: %r>' % (cls.__name__, self._name_, self._value_)
        members, uncovered = _decompose(cls, self._value_)
        return '<%s.%s: %r>' % (
                cls.__name__,
                '|'.join([str(m._name_ or m._value_) for m in members]),
                self._value_,
                )

    def __str__(self):
        cls = self.__class__
        if self._name_ is not None:
            return '%s.%s' % (cls.__name__, self._name_)
        members, uncovered = _decompose(cls, self._value_)
        if len(members) == 1 and members[0]._name_ is None:
            return '%s.%r' % (cls.__name__, members[0]._value_)
        else:
            return '%s.%s' % (
                    cls.__name__,
                    '|'.join([str(m._name_ or m._value_) for m in members]),
                    )

    def __bool__(self):
        return bool(self._value_)
    if pyver < 3:
        __nonzero__ = __bool__
        del __bool__

    def __or__(self, other):
        if not isinstance(other, self.__class__):
            return NotImplemented
        return self.__class__(self._value_ | other._value_)

    def __and__(self, other):
        if not isinstance(other, self.__class__):
            return NotImplemented
        return self.__class__(self._value_ & other._value_)

    def __xor__(self, other):
        if not isinstance(other, self.__class__):
            return NotImplemented
        return self.__class__(self._value_ ^ other._value_)

    def __invert__(self):
        members, uncovered = _decompose(self.__class__, self._value_)
        inverted_members = [
                m for m in self.__class__
                if m not in members and not m._value_ & self._value_
                ]
        inverted = reduce(_or_, inverted_members, self.__class__(0))
        return self.__class__(inverted)

    def __iter__(self):
        members, extra_flags = _decompose(self.__class__, self.value)
        return (m for m in members if m._value_ != 0)


class IntFlag(int, Flag):
    """Support for integer-based Flags"""

    @classmethod
    def _missing_(cls, value):
        if not isinstance(value, int):
            raise ValueError("%r is not a valid %s" % (value, cls.__name__))
        new_member = cls._create_pseudo_member_(value)
        return new_member

    @classmethod
    def _create_pseudo_member_(cls, value):
        pseudo_member = cls._value2member_map_.get(value, None)
        if pseudo_member is None:
            need_to_create = [value]
            # get unaccounted for bits
            _, extra_flags = _decompose(cls, value)
            while extra_flags:
                bit = _high_bit(extra_flags)
                flag_value = 2 ** bit
                if (flag_value not in cls._value2member_map_ and
                        flag_value not in need_to_create
                        ):
                    need_to_create.append(flag_value)
                if extra_flags == -flag_value:
                    extra_flags = 0
                else:
                    extra_flags ^= flag_value
            for value in reversed(need_to_create):
                # construct singleton pseudo-members
                pseudo_member = int.__new__(cls, value)
                pseudo_member._name_ = None
                pseudo_member._value_ = value
                # use setdefault in case another thread already created a composite
                # with this value
                pseudo_member = cls._value2member_map_.setdefault(value, pseudo_member)
        return pseudo_member

    def __or__(self, other):
        if not isinstance(other, (self.__class__, int)):
            return NotImplemented
        result = self.__class__(self._value_ | self.__class__(other)._value_)
        return result

    def __and__(self, other):
        if not isinstance(other, (self.__class__, int)):
            return NotImplemented
        return self.__class__(self._value_ & self.__class__(other)._value_)

    def __xor__(self, other):
        if not isinstance(other, (self.__class__, int)):
            return NotImplemented
        return self.__class__(self._value_ ^ self.__class__(other)._value_)

    __ror__ = __or__
    __rand__ = __and__
    __rxor__ = __xor__

    def __invert__(self):
        result = self.__class__(~self._value_)
        return result


def _high_bit(value):
    """returns index of highest bit, or -1 if value is zero or negative"""
    return value.bit_length() - 1

def _decompose(flag, value):
    """Extract all members from the value."""
    # _decompose is only called if the value is not named
    not_covered = value
    negative = value < 0
    # issue29167: wrap accesses to _value2member_map_ in a list to avoid race
    #             conditions between iterating over it and having more psuedo-
    #             members added to it
    if negative:
        # only check for named flags
        flags_to_check = [
                (m, v)
                for v, m in list(flag._value2member_map_.items())
                if m.name is not None
                ]
    else:
        # check for named flags and powers-of-two flags
        flags_to_check = [
                (m, v)
                for v, m in list(flag._value2member_map_.items())
                if m.name is not None or _power_of_two(v)
                ]
    members = []
    for member, member_value in flags_to_check:
        if member_value and member_value & value == member_value:
            members.append(member)
            not_covered &= ~member_value
    if not members and value in flag._value2member_map_:
        members.append(flag._value2member_map_[value])
    members.sort(key=lambda m: m._value_, reverse=True)
    if len(members) > 1 and members[0].value == value:
        # we have the breakdown, don't need the value member itself
        members.pop(0)
    return members, not_covered

def _power_of_two(value):
    if value < 1:
        return False
    return value == 2 ** _high_bit(value)


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