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