1# type: ignore
2"""Python Enumerations"""
3
4import sys as _sys
5
6__all__ = ["Enum", "IntEnum", "unique"]
7
8version = 1, 1, 6
9
10pyver = float("%s.%s" % _sys.version_info[:2])
11
12try:
13    any
14except NameError:
15
16    def any(iterable):
17        for element in iterable:
18            if element:
19                return True
20        return False
21
22
23try:
24    from collections import OrderedDict  # type: ignore
25except ImportError:
26
27    class OrderedDict(object):  # type: ignore
28        pass
29
30
31try:
32    basestring  # type: ignore
33except NameError:
34    # In Python 2 basestring is the ancestor of both str and unicode
35    # in Python 3 it's just str, but was missing in 3.1
36    basestring = str
37
38try:
39    unicode  # type: ignore
40except NameError:
41    # In Python 3 unicode no longer exists (it's just str)
42    unicode = str
43
44
45class _RouteClassAttributeToGetattr(object):
46    """Route attribute access on a class to __getattr__.
47
48    This is a descriptor, used to define attributes that act differently when
49    accessed through an instance and through a class.  Instance access remains
50    normal, but access to an attribute through a class will be routed to the
51    class's __getattr__ method; this is done by raising AttributeError.
52
53    """
54
55    def __init__(self, fget=None):
56        self.fget = fget
57
58    def __get__(self, instance, ownerclass=None):
59        if instance is None:
60            raise AttributeError()
61        return self.fget(instance)
62
63    def __set__(self, instance, value):
64        raise AttributeError("can't set attribute")
65
66    def __delete__(self, instance):
67        raise AttributeError("can't delete attribute")
68
69
70def _is_descriptor(obj):
71    """Returns True if obj is a descriptor, False otherwise."""
72    return (
73        hasattr(obj, "__get__") or hasattr(obj, "__set__") or hasattr(obj, "__delete__")
74    )
75
76
77def _is_dunder(name):
78    """Returns True if a __dunder__ name, False otherwise."""
79    return (
80        len(name) > 4
81        and name[:2] == name[-2:] == "__"
82        and name[2:3] != "_"
83        and name[-3:-2] != "_"
84    )
85
86
87def _is_sunder(name):
88    """Returns True if a _sunder_ name, False otherwise."""
89    return (
90        len(name) > 2
91        and name[0] == name[-1] == "_"
92        and name[1:2] != "_"
93        and name[-2:-1] != "_"
94    )
95
96
97def _make_class_unpicklable(cls):
98    """Make the given class un-picklable."""
99
100    def _break_on_call_reduce(self, protocol=None):
101        raise TypeError("%r cannot be pickled" % self)
102
103    cls.__reduce_ex__ = _break_on_call_reduce
104    cls.__module__ = "<unknown>"
105
106
107class _EnumDict(OrderedDict):
108    """Track enum member order and ensure member names are not reused.
109
110    EnumMeta will use the names found in self._member_names as the
111    enumeration member names.
112
113    """
114
115    def __init__(self):
116        super(_EnumDict, self).__init__()
117        self._member_names = []
118
119    def __setitem__(self, key, value):
120        """Changes anything not dundered or not a descriptor.
121
122        If a descriptor is added with the same name as an enum member, the name
123        is removed from _member_names (this may leave a hole in the numerical
124        sequence of values).
125
126        If an enum member name is used twice, an error is raised; duplicate
127        values are not checked for.
128
129        Single underscore (sunder) names are reserved.
130
131        Note:   in 3.x __order__ is simply discarded as a not necessary piece
132                leftover from 2.x
133
134        """
135        if pyver >= 3.0 and key in ("_order_", "__order__"):
136            return
137        elif key == "__order__":
138            key = "_order_"
139        if _is_sunder(key):
140            if key != "_order_":
141                raise ValueError("_names_ are reserved for future Enum use")
142        elif _is_dunder(key):
143            pass
144        elif key in self._member_names:
145            # descriptor overwriting an enum?
146            raise TypeError("Attempted to reuse key: %r" % key)
147        elif not _is_descriptor(value):
148            if key in self:
149                # enum overwriting a descriptor?
150                raise TypeError("Key already defined as: %r" % self[key])
151            self._member_names.append(key)
152        super(_EnumDict, self).__setitem__(key, value)
153
154
155# Dummy value for Enum as EnumMeta explicity checks for it, but of course until
156# EnumMeta finishes running the first time the Enum class doesn't exist.  This
157# is also why there are checks in EnumMeta like `if Enum is not None`
158Enum = None
159
160
161class EnumMeta(type):
162    """Metaclass for Enum"""
163
164    @classmethod
165    def __prepare__(metacls, cls, bases):
166        return _EnumDict()
167
168    def __new__(metacls, cls, bases, classdict):
169        # an Enum class is final once enumeration items have been defined; it
170        # cannot be mixed with other types (int, float, etc.) if it has an
171        # inherited __new__ unless a new __new__ is defined (or the resulting
172        # class will fail).
173        if isinstance(classdict, dict):
174            original_dict = classdict
175            classdict = _EnumDict()
176            for k, v in original_dict.items():
177                classdict[k] = v
178
179        member_type, first_enum = metacls._get_mixins_(bases)
180        __new__, save_new, use_args = metacls._find_new_(
181            classdict, member_type, first_enum
182        )
183        # save enum items into separate mapping so they don't get baked into
184        # the new class
185        members = {k: classdict[k] for k in classdict._member_names}
186        for name in classdict._member_names:
187            del classdict[name]
188
189        # py2 support for definition order
190        _order_ = classdict.get("_order_")
191        if _order_ is None:
192            if pyver < 3.0:
193                try:
194                    _order_ = [
195                        name
196                        for (name, value) in sorted(
197                            members.items(), key=lambda item: item[1]
198                        )
199                    ]
200                except TypeError:
201                    _order_ = [name for name in sorted(members.keys())]
202            else:
203                _order_ = classdict._member_names
204        else:
205            del classdict["_order_"]
206            if pyver < 3.0:
207                _order_ = _order_.replace(",", " ").split()
208                aliases = [name for name in members if name not in _order_]
209                _order_ += aliases
210
211        # check for illegal enum names (any others?)
212        invalid_names = set(members) & {"mro"}
213        if invalid_names:
214            raise ValueError(
215                "Invalid enum member name(s): {}".format(", ".join(invalid_names))
216            )
217
218        # save attributes from super classes so we know if we can take
219        # the shortcut of storing members in the class dict
220        base_attributes = {a for b in bases for a in b.__dict__}
221        # create our new Enum type
222        enum_class = super(EnumMeta, metacls).__new__(metacls, cls, bases, classdict)
223        enum_class._member_names_ = []  # names in random order
224        if OrderedDict is not None:
225            enum_class._member_map_ = OrderedDict()
226        else:
227            enum_class._member_map_ = {}  # name->value map
228        enum_class._member_type_ = member_type
229
230        # Reverse value->name map for hashable values.
231        enum_class._value2member_map_ = {}
232
233        # instantiate them, checking for duplicates as we go
234        # we instantiate first instead of checking for duplicates first in case
235        # a custom __new__ is doing something funky with the values -- such as
236        # auto-numbering ;)
237        if __new__ is None:
238            __new__ = enum_class.__new__
239        for member_name in _order_:
240            value = members[member_name]
241            if not isinstance(value, tuple):
242                args = (value,)
243            else:
244                args = value
245            if member_type is tuple:  # special case for tuple enums
246                args = (args,)  # wrap it one more time
247            if not use_args or not args:
248                enum_member = __new__(enum_class)
249                if not hasattr(enum_member, "_value_"):
250                    enum_member._value_ = value
251            else:
252                enum_member = __new__(enum_class, *args)
253                if not hasattr(enum_member, "_value_"):
254                    enum_member._value_ = member_type(*args)
255            value = enum_member._value_
256            enum_member._name_ = member_name
257            enum_member.__objclass__ = enum_class
258            enum_member.__init__(*args)
259            # If another member with the same value was already defined, the
260            # new member becomes an alias to the existing one.
261            for name, canonical_member in enum_class._member_map_.items():
262                if canonical_member.value == enum_member._value_:
263                    enum_member = canonical_member
264                    break
265            else:
266                # Aliases don't appear in member names (only in __members__).
267                enum_class._member_names_.append(member_name)
268            # performance boost for any member that would not shadow
269            # a DynamicClassAttribute (aka _RouteClassAttributeToGetattr)
270            if member_name not in base_attributes:
271                setattr(enum_class, member_name, enum_member)
272            # now add to _member_map_
273            enum_class._member_map_[member_name] = enum_member
274            try:
275                # This may fail if value is not hashable. We can't add the value
276                # to the map, and by-value lookups for this value will be
277                # linear.
278                enum_class._value2member_map_[value] = enum_member
279            except TypeError:
280                pass
281
282        # If a custom type is mixed into the Enum, and it does not know how
283        # to pickle itself, pickle.dumps will succeed but pickle.loads will
284        # fail.  Rather than have the error show up later and possibly far
285        # from the source, sabotage the pickle protocol for this class so
286        # that pickle.dumps also fails.
287        #
288        # However, if the new class implements its own __reduce_ex__, do not
289        # sabotage -- it's on them to make sure it works correctly.  We use
290        # __reduce_ex__ instead of any of the others as it is preferred by
291        # pickle over __reduce__, and it handles all pickle protocols.
292        unpicklable = False
293        if "__reduce_ex__" not in classdict:
294            if member_type is not object:
295                methods = (
296                    "__getnewargs_ex__",
297                    "__getnewargs__",
298                    "__reduce_ex__",
299                    "__reduce__",
300                )
301                if not any(m in member_type.__dict__ for m in methods):
302                    _make_class_unpicklable(enum_class)
303                    unpicklable = True
304
305        # double check that repr and friends are not the mixin's or various
306        # things break (such as pickle)
307        for name in ("__repr__", "__str__", "__format__", "__reduce_ex__"):
308            class_method = getattr(enum_class, name)
309            getattr(member_type, name, None)
310            enum_method = getattr(first_enum, name, None)
311            if name not in classdict and class_method is not enum_method:
312                if name == "__reduce_ex__" and unpicklable:
313                    continue
314                setattr(enum_class, name, enum_method)
315
316        # method resolution and int's are not playing nice
317        # Python's less than 2.6 use __cmp__
318
319        if pyver < 2.6:
320
321            if issubclass(enum_class, int):
322                setattr(enum_class, "__cmp__", getattr(int, "__cmp__"))
323
324        elif pyver < 3.0:
325
326            if issubclass(enum_class, int):
327                for method in (
328                    "__le__",
329                    "__lt__",
330                    "__gt__",
331                    "__ge__",
332                    "__eq__",
333                    "__ne__",
334                    "__hash__",
335                ):
336                    setattr(enum_class, method, getattr(int, method))
337
338        # replace any other __new__ with our own (as long as Enum is not None,
339        # anyway) -- again, this is to support pickle
340        if Enum is not None:
341            # if the user defined their own __new__, save it before it gets
342            # clobbered in case they subclass later
343            if save_new:
344                setattr(enum_class, "__member_new__", enum_class.__dict__["__new__"])
345            setattr(enum_class, "__new__", Enum.__dict__["__new__"])
346        return enum_class
347
348    def __bool__(cls):
349        """
350        classes/types should always be True.
351        """
352        return True
353
354    def __call__(cls, value, names=None, module=None, type=None, start=1):
355        """Either returns an existing member, or creates a new enum class.
356
357        This method is used both when an enum class is given a value to match
358        to an enumeration member (i.e. Color(3)) and for the functional API
359        (i.e. Color = Enum('Color', names='red green blue')).
360
361        When used for the functional API: `module`, if set, will be stored in
362        the new class' __module__ attribute; `type`, if set, will be mixed in
363        as the first base class.
364
365        Note: if `module` is not set this routine will attempt to discover the
366        calling module by walking the frame stack; if this is unsuccessful
367        the resulting class will not be pickleable.
368
369        """
370        if names is None:  # simple value lookup
371            return cls.__new__(cls, value)
372        # otherwise, functional API: we're creating a new Enum type
373        return cls._create_(value, names, module=module, type=type, start=start)
374
375    def __contains__(cls, member):
376        return isinstance(member, cls) and member.name in cls._member_map_
377
378    def __delattr__(cls, attr):
379        # nicer error message when someone tries to delete an attribute
380        # (see issue19025).
381        if attr in cls._member_map_:
382            raise AttributeError("%s: cannot delete Enum member." % cls.__name__)
383        super(EnumMeta, cls).__delattr__(attr)
384
385    def __dir__(self):
386        return [
387            "__class__",
388            "__doc__",
389            "__members__",
390            "__module__",
391        ] + self._member_names_
392
393    @property
394    def __members__(cls):
395        """Returns a mapping of member name->value.
396
397        This mapping lists all enum members, including aliases. Note that this
398        is a copy of the internal mapping.
399
400        """
401        return cls._member_map_.copy()
402
403    def __getattr__(cls, name):
404        """Return the enum member matching `name`
405
406        We use __getattr__ instead of descriptors or inserting into the enum
407        class' __dict__ in order to support `name` and `value` being both
408        properties for enum members (which live in the class' __dict__) and
409        enum members themselves.
410
411        """
412        if _is_dunder(name):
413            raise AttributeError(name)
414        try:
415            return cls._member_map_[name]
416        except KeyError:
417            raise AttributeError(name)
418
419    def __getitem__(cls, name):
420        return cls._member_map_[name]
421
422    def __iter__(cls):
423        return (cls._member_map_[name] for name in cls._member_names_)
424
425    def __reversed__(cls):
426        return (cls._member_map_[name] for name in reversed(cls._member_names_))
427
428    def __len__(cls):
429        return len(cls._member_names_)
430
431    __nonzero__ = __bool__
432
433    def __repr__(cls):
434        return "<enum %r>" % cls.__name__
435
436    def __setattr__(cls, name, value):
437        """Block attempts to reassign Enum members.
438
439        A simple assignment to the class namespace only changes one of the
440        several possible ways to get an Enum member from the Enum class,
441        resulting in an inconsistent Enumeration.
442
443        """
444        member_map = cls.__dict__.get("_member_map_", {})
445        if name in member_map:
446            raise AttributeError("Cannot reassign members.")
447        super(EnumMeta, cls).__setattr__(name, value)
448
449    def _create_(cls, class_name, names=None, module=None, type=None, start=1):
450        """Convenience method to create a new Enum class.
451
452        `names` can be:
453
454        * A string containing member names, separated either with spaces or
455          commas.  Values are auto-numbered from 1.
456        * An iterable of member names.  Values are auto-numbered from 1.
457        * An iterable of (member name, value) pairs.
458        * A mapping of member name -> value.
459
460        """
461        if pyver < 3.0:
462            # if class_name is unicode, attempt a conversion to ASCII
463            if isinstance(class_name, unicode):
464                try:
465                    class_name = class_name.encode("ascii")
466                except UnicodeEncodeError:
467                    raise TypeError("%r is not representable in ASCII" % class_name)
468        metacls = cls.__class__
469        if type is None:
470            bases = (cls,)
471        else:
472            bases = (type, cls)
473        classdict = metacls.__prepare__(class_name, bases)
474        _order_ = []
475
476        # special processing needed for names?
477        if isinstance(names, basestring):
478            names = names.replace(",", " ").split()
479        if isinstance(names, (tuple, list)) and isinstance(names[0], basestring):
480            names = [(e, i + start) for (i, e) in enumerate(names)]
481
482        # Here, names is either an iterable of (name, value) or a mapping.
483        item = None  # in case names is empty
484        for item in names:
485            if isinstance(item, basestring):
486                member_name, member_value = item, names[item]
487            else:
488                member_name, member_value = item
489            classdict[member_name] = member_value
490            _order_.append(member_name)
491        # only set _order_ in classdict if name/value was not from a mapping
492        if not isinstance(item, basestring):
493            classdict["_order_"] = " ".join(_order_)
494        enum_class = metacls.__new__(metacls, class_name, bases, classdict)
495
496        # TODO: replace the frame hack if a blessed way to know the calling
497        # module is ever developed
498        if module is None:
499            try:
500                module = _sys._getframe(2).f_globals["__name__"]
501            except (AttributeError, ValueError):
502                pass
503        if module is None:
504            _make_class_unpicklable(enum_class)
505        else:
506            enum_class.__module__ = module
507
508        return enum_class
509
510    @staticmethod
511    def _get_mixins_(bases):
512        """Returns the type for creating enum members, and the first inherited
513        enum class.
514
515        bases: the tuple of bases that was given to __new__
516
517        """
518        if not bases or Enum is None:
519            return object, Enum
520
521        # double check that we are not subclassing a class with existing
522        # enumeration members; while we're at it, see if any other data
523        # type has been mixed in so we can use the correct __new__
524        member_type = first_enum = None
525        for base in bases:
526            if base is not Enum and issubclass(base, Enum) and base._member_names_:
527                raise TypeError("Cannot extend enumerations")
528        # base is now the last base in bases
529        if not issubclass(base, Enum):
530            raise TypeError(
531                "new enumerations must be created as "
532                "`ClassName([mixin_type,] enum_type)`"
533            )
534
535        # get correct mix-in type (either mix-in type of Enum subclass, or
536        # first base if last base is Enum)
537        if not issubclass(bases[0], Enum):
538            member_type = bases[0]  # first data type
539            first_enum = bases[-1]  # enum type
540        else:
541            for base in bases[0].__mro__:
542                # most common: (IntEnum, int, Enum, object)
543                # possible:    (<Enum 'AutoIntEnum'>, <Enum 'IntEnum'>,
544                #               <class 'int'>, <Enum 'Enum'>,
545                #               <class 'object'>)
546                if issubclass(base, Enum):
547                    if first_enum is None:
548                        first_enum = base
549                else:
550                    if member_type is None:
551                        member_type = base
552
553        return member_type, first_enum
554
555    if pyver < 3.0:
556
557        @staticmethod
558        def _find_new_(classdict, member_type, first_enum):
559            """Returns the __new__ to be used for creating the enum members.
560
561            classdict: the class dictionary given to __new__
562            member_type: the data type whose __new__ will be used by default
563            first_enum: enumeration to check for an overriding __new__
564
565            """
566            # now find the correct __new__, checking to see of one was defined
567            # by the user; also check earlier enum classes in case a __new__ was
568            # saved as __member_new__
569            __new__ = classdict.get("__new__", None)
570            if __new__:
571                return None, True, True  # __new__, save_new, use_args
572
573            N__new__ = getattr(None, "__new__")
574            O__new__ = getattr(object, "__new__")
575            if Enum is None:
576                E__new__ = N__new__
577            else:
578                E__new__ = Enum.__dict__["__new__"]
579            # check all possibles for __member_new__ before falling back to
580            # __new__
581            for method in ("__member_new__", "__new__"):
582                for possible in (member_type, first_enum):
583                    try:
584                        target = possible.__dict__[method]
585                    except (AttributeError, KeyError):
586                        target = getattr(possible, method, None)
587                    if target not in [None, N__new__, O__new__, E__new__]:
588                        if method == "__member_new__":
589                            classdict["__new__"] = target
590                            return None, False, True
591                        if isinstance(target, staticmethod):
592                            target = target.__get__(member_type)
593                        __new__ = target
594                        break
595                if __new__ is not None:
596                    break
597            else:
598                __new__ = object.__new__
599
600            # if a non-object.__new__ is used then whatever value/tuple was
601            # assigned to the enum member name will be passed to __new__ and to the
602            # new enum member's __init__
603            if __new__ is object.__new__:
604                use_args = False
605            else:
606                use_args = True
607
608            return __new__, False, use_args
609
610    else:
611
612        @staticmethod
613        def _find_new_(classdict, member_type, first_enum):
614            """Returns the __new__ to be used for creating the enum members.
615
616            classdict: the class dictionary given to __new__
617            member_type: the data type whose __new__ will be used by default
618            first_enum: enumeration to check for an overriding __new__
619
620            """
621            # now find the correct __new__, checking to see of one was defined
622            # by the user; also check earlier enum classes in case a __new__ was
623            # saved as __member_new__
624            __new__ = classdict.get("__new__", None)
625
626            # should __new__ be saved as __member_new__ later?
627            save_new = __new__ is not None
628
629            if __new__ is None:
630                # check all possibles for __member_new__ before falling back to
631                # __new__
632                for method in ("__member_new__", "__new__"):
633                    for possible in (member_type, first_enum):
634                        target = getattr(possible, method, None)
635                        if target not in (
636                            None,
637                            None.__new__,
638                            object.__new__,
639                            Enum.__new__,
640                        ):
641                            __new__ = target
642                            break
643                    if __new__ is not None:
644                        break
645                else:
646                    __new__ = object.__new__
647
648            # if a non-object.__new__ is used then whatever value/tuple was
649            # assigned to the enum member name will be passed to __new__ and to the
650            # new enum member's __init__
651            if __new__ is object.__new__:
652                use_args = False
653            else:
654                use_args = True
655
656            return __new__, save_new, use_args
657
658
659########################################################
660# In order to support Python 2 and 3 with a single
661# codebase we have to create the Enum methods separately
662# and then use the `type(name, bases, dict)` method to
663# create the class.
664########################################################
665temp_enum_dict = {}
666temp_enum_dict[
667    "__doc__"
668] = "Generic enumeration.\n\n    Derive from this class to define new enumerations.\n\n"
669
670
671def __new__(cls, value):
672    # all enum instances are actually created during class construction
673    # without calling this method; this method is called by the metaclass'
674    # __call__ (i.e. Color(3) ), and by pickle
675    if isinstance(value, cls):
676        # For lookups like Color(Color.red)
677        value = value.value
678        # return value
679    # by-value search for a matching enum member
680    # see if it's in the reverse mapping (for hashable values)
681    try:
682        if value in cls._value2member_map_:
683            return cls._value2member_map_[value]
684    except TypeError:
685        # not there, now do long search -- O(n) behavior
686        for member in cls._member_map_.values():
687            if member.value == value:
688                return member
689    raise ValueError("{} is not a valid {}".format(value, cls.__name__))
690
691
692temp_enum_dict["__new__"] = __new__  # type: ignore
693del __new__
694
695
696def __repr__(self):
697    return "<{}.{}: {!r}>".format(self.__class__.__name__, self._name_, self._value_)
698
699
700temp_enum_dict["__repr__"] = __repr__  # type: ignore
701del __repr__
702
703
704def __str__(self):
705    return "{}.{}".format(self.__class__.__name__, self._name_)
706
707
708temp_enum_dict["__str__"] = __str__  # type: ignore
709del __str__
710
711if pyver >= 3.0:
712
713    def __dir__(self):
714        added_behavior = [
715            m
716            for cls in self.__class__.mro()
717            for m in cls.__dict__
718            if m[0] != "_" and m not in self._member_map_
719        ]
720        return ["__class__", "__doc__", "__module__"] + added_behavior
721
722    temp_enum_dict["__dir__"] = __dir__  # type: ignore
723    del __dir__
724
725
726def __format__(self, format_spec):
727    # mixed-in Enums should use the mixed-in type's __format__, otherwise
728    # we can get strange results with the Enum name showing up instead of
729    # the value
730
731    # pure Enum branch
732    if self._member_type_ is object:
733        cls = str
734        val = str(self)
735    # mix-in branch
736    else:
737        cls = self._member_type_
738        val = self.value
739    return cls.__format__(val, format_spec)
740
741
742temp_enum_dict["__format__"] = __format__  # type: ignore
743del __format__
744
745
746####################################
747# Python's less than 2.6 use __cmp__
748
749if pyver < 2.6:
750
751    def __cmp__(self, other):
752        if isinstance(other, self.__class__):
753            if self is other:
754                return 0
755            return -1
756        return NotImplemented
757        raise TypeError(
758            "unorderable types: %s() and %s()"
759            % (self.__class__.__name__, other.__class__.__name__)
760        )
761
762    temp_enum_dict["__cmp__"] = __cmp__  # type: ignore
763    del __cmp__
764
765else:
766
767    def __le__(self, other):
768        raise TypeError(
769            "unorderable types: %s() <= %s()"
770            % (self.__class__.__name__, other.__class__.__name__)
771        )
772
773    temp_enum_dict["__le__"] = __le__  # type: ignore
774    del __le__
775
776    def __lt__(self, other):
777        raise TypeError(
778            "unorderable types: %s() < %s()"
779            % (self.__class__.__name__, other.__class__.__name__)
780        )
781
782    temp_enum_dict["__lt__"] = __lt__  # type: ignore
783    del __lt__
784
785    def __ge__(self, other):
786        raise TypeError(
787            "unorderable types: %s() >= %s()"
788            % (self.__class__.__name__, other.__class__.__name__)
789        )
790
791    temp_enum_dict["__ge__"] = __ge__  # type: ignore
792    del __ge__
793
794    def __gt__(self, other):
795        raise TypeError(
796            "unorderable types: %s() > %s()"
797            % (self.__class__.__name__, other.__class__.__name__)
798        )
799
800    temp_enum_dict["__gt__"] = __gt__  # type: ignore
801    del __gt__
802
803
804def __eq__(self, other):
805    if isinstance(other, self.__class__):
806        return self is other
807    return NotImplemented
808
809
810temp_enum_dict["__eq__"] = __eq__  # type: ignore
811del __eq__
812
813
814def __ne__(self, other):
815    if isinstance(other, self.__class__):
816        return self is not other
817    return NotImplemented
818
819
820temp_enum_dict["__ne__"] = __ne__  # type: ignore
821del __ne__
822
823
824def __hash__(self):
825    return hash(self._name_)
826
827
828temp_enum_dict["__hash__"] = __hash__  # type: ignore
829del __hash__
830
831
832def __reduce_ex__(self, proto):
833    return self.__class__, (self._value_,)
834
835
836temp_enum_dict["__reduce_ex__"] = __reduce_ex__  # type: ignore
837del __reduce_ex__
838
839# _RouteClassAttributeToGetattr is used to provide access to the `name`
840# and `value` properties of enum members while keeping some measure of
841# protection from modification, while still allowing for an enumeration
842# to have members named `name` and `value`.  This works because enumeration
843# members are not set directly on the enum class -- __getattr__ is
844# used to look them up.
845
846
847@_RouteClassAttributeToGetattr
848def name(self):
849    return self._name_
850
851
852temp_enum_dict["name"] = name  # type: ignore
853del name
854
855
856@_RouteClassAttributeToGetattr
857def value(self):
858    return self._value_
859
860
861temp_enum_dict["value"] = value  # type: ignore
862del value
863
864
865@classmethod  # type: ignore
866def _convert(cls, name, module, filter, source=None):
867    """
868    Create a new Enum subclass that replaces a collection of global constants
869    """
870    # convert all constants from source (or module) that pass filter() to
871    # a new Enum called name, and export the enum and its members back to
872    # module;
873    # also, replace the __reduce_ex__ method so unpickling works in
874    # previous Python versions
875    module_globals = vars(_sys.modules[module])
876    if source:
877        source = vars(source)
878    else:
879        source = module_globals
880    members = {name: value for name, value in source.items() if filter(name)}
881    cls = cls(name, members, module=module)
882    cls.__reduce_ex__ = _reduce_ex_by_name
883    module_globals.update(cls.__members__)
884    module_globals[name] = cls
885    return cls
886
887
888temp_enum_dict["_convert"] = _convert  # type: ignore
889del _convert
890
891Enum = EnumMeta("Enum", (object,), temp_enum_dict)
892del temp_enum_dict
893
894# Enum has now been created
895###########################
896
897
898class IntEnum(int, Enum):  # type: ignore
899    """Enum where members are also (and must be) ints"""
900
901
902def _reduce_ex_by_name(self, proto):
903    return self.name
904
905
906def unique(enumeration):
907    """Class decorator that ensures only unique members exist in an enumeration."""
908    duplicates = []
909    for name, member in enumeration.__members__.items():
910        if name != member.name:
911            duplicates.append((name, member.name))
912    if duplicates:
913        duplicate_names = ", ".join(
914            ["{} -> {}".format(alias, name) for (alias, name) in duplicates]
915        )
916        raise ValueError(
917            "duplicate names found in {!r}: {}".format(enumeration, duplicate_names)
918        )
919    return enumeration
920