1import sys 2from types import MappingProxyType, DynamicClassAttribute 3 4 5__all__ = [ 6 'EnumMeta', 7 'Enum', 'IntEnum', 'Flag', 'IntFlag', 8 'auto', 'unique', 9 ] 10 11 12def _is_descriptor(obj): 13 """ 14 Returns True if obj is a descriptor, False otherwise. 15 """ 16 return ( 17 hasattr(obj, '__get__') or 18 hasattr(obj, '__set__') or 19 hasattr(obj, '__delete__') 20 ) 21 22def _is_dunder(name): 23 """ 24 Returns True if a __dunder__ name, False otherwise. 25 """ 26 return ( 27 len(name) > 4 and 28 name[:2] == name[-2:] == '__' and 29 name[2] != '_' and 30 name[-3] != '_' 31 ) 32 33def _is_sunder(name): 34 """ 35 Returns True if a _sunder_ name, False otherwise. 36 """ 37 return ( 38 len(name) > 2 and 39 name[0] == name[-1] == '_' and 40 name[1:2] != '_' and 41 name[-2:-1] != '_' 42 ) 43 44def _is_private(cls_name, name): 45 # do not use `re` as `re` imports `enum` 46 pattern = '_%s__' % (cls_name, ) 47 if ( 48 len(name) >= 5 49 and name.startswith(pattern) 50 and name[len(pattern)] != '_' 51 and (name[-1] != '_' or name[-2] != '_') 52 ): 53 return True 54 else: 55 return False 56 57def _make_class_unpicklable(cls): 58 """ 59 Make the given class un-picklable. 60 """ 61 def _break_on_call_reduce(self, proto): 62 raise TypeError('%r cannot be pickled' % self) 63 cls.__reduce_ex__ = _break_on_call_reduce 64 cls.__module__ = '<unknown>' 65 66_auto_null = object() 67class auto: 68 """ 69 Instances are replaced with an appropriate value in Enum class suites. 70 """ 71 value = _auto_null 72 73 74class _EnumDict(dict): 75 """ 76 Track enum member order and ensure member names are not reused. 77 78 EnumMeta will use the names found in self._member_names as the 79 enumeration member names. 80 """ 81 def __init__(self): 82 super().__init__() 83 self._member_names = [] 84 self._last_values = [] 85 self._ignore = [] 86 self._auto_called = False 87 88 def __setitem__(self, key, value): 89 """ 90 Changes anything not dundered or not a descriptor. 91 92 If an enum member name is used twice, an error is raised; duplicate 93 values are not checked for. 94 95 Single underscore (sunder) names are reserved. 96 """ 97 if _is_private(self._cls_name, key): 98 import warnings 99 warnings.warn( 100 "private variables, such as %r, will be normal attributes in 3.10" 101 % (key, ), 102 DeprecationWarning, 103 stacklevel=2, 104 ) 105 if _is_sunder(key): 106 if key not in ( 107 '_order_', '_create_pseudo_member_', 108 '_generate_next_value_', '_missing_', '_ignore_', 109 ): 110 raise ValueError('_names_ are reserved for future Enum use') 111 if key == '_generate_next_value_': 112 # check if members already defined as auto() 113 if self._auto_called: 114 raise TypeError("_generate_next_value_ must be defined before members") 115 setattr(self, '_generate_next_value', value) 116 elif key == '_ignore_': 117 if isinstance(value, str): 118 value = value.replace(',',' ').split() 119 else: 120 value = list(value) 121 self._ignore = value 122 already = set(value) & set(self._member_names) 123 if already: 124 raise ValueError( 125 '_ignore_ cannot specify already set names: %r' 126 % (already, ) 127 ) 128 elif _is_dunder(key): 129 if key == '__order__': 130 key = '_order_' 131 elif key in self._member_names: 132 # descriptor overwriting an enum? 133 raise TypeError('Attempted to reuse key: %r' % key) 134 elif key in self._ignore: 135 pass 136 elif not _is_descriptor(value): 137 if key in self: 138 # enum overwriting a descriptor? 139 raise TypeError('%r already defined as: %r' % (key, self[key])) 140 if isinstance(value, auto): 141 if value.value == _auto_null: 142 value.value = self._generate_next_value( 143 key, 144 1, 145 len(self._member_names), 146 self._last_values[:], 147 ) 148 self._auto_called = True 149 value = value.value 150 self._member_names.append(key) 151 self._last_values.append(value) 152 super().__setitem__(key, value) 153 154 155# Dummy value for Enum as EnumMeta explicitly checks for it, but of course 156# until EnumMeta finishes running the first time the Enum class doesn't exist. 157# This is also why there are checks in EnumMeta like `if Enum is not None` 158Enum = None 159 160class EnumMeta(type): 161 """ 162 Metaclass for Enum 163 """ 164 @classmethod 165 def __prepare__(metacls, cls, bases, **kwds): 166 # check that previous enum members do not exist 167 metacls._check_for_existing_members(cls, bases) 168 # create the namespace dict 169 enum_dict = _EnumDict() 170 enum_dict._cls_name = cls 171 # inherit previous flags and _generate_next_value_ function 172 member_type, first_enum = metacls._get_mixins_(cls, bases) 173 if first_enum is not None: 174 enum_dict['_generate_next_value_'] = getattr( 175 first_enum, '_generate_next_value_', None, 176 ) 177 return enum_dict 178 179 def __new__(metacls, cls, bases, classdict, **kwds): 180 # an Enum class is final once enumeration items have been defined; it 181 # cannot be mixed with other types (int, float, etc.) if it has an 182 # inherited __new__ unless a new __new__ is defined (or the resulting 183 # class will fail). 184 # 185 # remove any keys listed in _ignore_ 186 classdict.setdefault('_ignore_', []).append('_ignore_') 187 ignore = classdict['_ignore_'] 188 for key in ignore: 189 classdict.pop(key, None) 190 member_type, first_enum = metacls._get_mixins_(cls, bases) 191 __new__, save_new, use_args = metacls._find_new_( 192 classdict, member_type, first_enum, 193 ) 194 195 # save enum items into separate mapping so they don't get baked into 196 # the new class 197 enum_members = {k: classdict[k] for k in classdict._member_names} 198 for name in classdict._member_names: 199 del classdict[name] 200 201 # adjust the sunders 202 _order_ = classdict.pop('_order_', None) 203 204 # check for illegal enum names (any others?) 205 invalid_names = set(enum_members) & {'mro', ''} 206 if invalid_names: 207 raise ValueError('Invalid enum member name: {0}'.format( 208 ','.join(invalid_names))) 209 210 # create a default docstring if one has not been provided 211 if '__doc__' not in classdict: 212 classdict['__doc__'] = 'An enumeration.' 213 214 enum_class = super().__new__(metacls, cls, bases, classdict, **kwds) 215 enum_class._member_names_ = [] # names in definition order 216 enum_class._member_map_ = {} # name->value map 217 enum_class._member_type_ = member_type 218 219 # save DynamicClassAttribute attributes from super classes so we know 220 # if we can take the shortcut of storing members in the class dict 221 dynamic_attributes = { 222 k for c in enum_class.mro() 223 for k, v in c.__dict__.items() 224 if isinstance(v, DynamicClassAttribute) 225 } 226 227 # Reverse value->name map for hashable values. 228 enum_class._value2member_map_ = {} 229 230 # If a custom type is mixed into the Enum, and it does not know how 231 # to pickle itself, pickle.dumps will succeed but pickle.loads will 232 # fail. Rather than have the error show up later and possibly far 233 # from the source, sabotage the pickle protocol for this class so 234 # that pickle.dumps also fails. 235 # 236 # However, if the new class implements its own __reduce_ex__, do not 237 # sabotage -- it's on them to make sure it works correctly. We use 238 # __reduce_ex__ instead of any of the others as it is preferred by 239 # pickle over __reduce__, and it handles all pickle protocols. 240 if '__reduce_ex__' not in classdict: 241 if member_type is not object: 242 methods = ('__getnewargs_ex__', '__getnewargs__', 243 '__reduce_ex__', '__reduce__') 244 if not any(m in member_type.__dict__ for m in methods): 245 _make_class_unpicklable(enum_class) 246 247 # instantiate them, checking for duplicates as we go 248 # we instantiate first instead of checking for duplicates first in case 249 # a custom __new__ is doing something funky with the values -- such as 250 # auto-numbering ;) 251 for member_name in classdict._member_names: 252 value = enum_members[member_name] 253 if not isinstance(value, tuple): 254 args = (value, ) 255 else: 256 args = value 257 if member_type is tuple: # special case for tuple enums 258 args = (args, ) # wrap it one more time 259 if not use_args: 260 enum_member = __new__(enum_class) 261 if not hasattr(enum_member, '_value_'): 262 enum_member._value_ = value 263 else: 264 enum_member = __new__(enum_class, *args) 265 if not hasattr(enum_member, '_value_'): 266 if member_type is object: 267 enum_member._value_ = value 268 else: 269 enum_member._value_ = member_type(*args) 270 value = enum_member._value_ 271 enum_member._name_ = member_name 272 enum_member.__objclass__ = enum_class 273 enum_member.__init__(*args) 274 # If another member with the same value was already defined, the 275 # new member becomes an alias to the existing one. 276 for name, canonical_member in enum_class._member_map_.items(): 277 if canonical_member._value_ == enum_member._value_: 278 enum_member = canonical_member 279 break 280 else: 281 # Aliases don't appear in member names (only in __members__). 282 enum_class._member_names_.append(member_name) 283 # performance boost for any member that would not shadow 284 # a DynamicClassAttribute 285 if member_name not in dynamic_attributes: 286 setattr(enum_class, member_name, enum_member) 287 # now add to _member_map_ 288 enum_class._member_map_[member_name] = enum_member 289 try: 290 # This may fail if value is not hashable. We can't add the value 291 # to the map, and by-value lookups for this value will be 292 # linear. 293 enum_class._value2member_map_[value] = enum_member 294 except TypeError: 295 pass 296 297 # double check that repr and friends are not the mixin's or various 298 # things break (such as pickle) 299 # however, if the method is defined in the Enum itself, don't replace 300 # it 301 for name in ('__repr__', '__str__', '__format__', '__reduce_ex__'): 302 if name in classdict: 303 continue 304 class_method = getattr(enum_class, name) 305 obj_method = getattr(member_type, name, None) 306 enum_method = getattr(first_enum, name, None) 307 if obj_method is not None and obj_method is class_method: 308 setattr(enum_class, name, enum_method) 309 310 # replace any other __new__ with our own (as long as Enum is not None, 311 # anyway) -- again, this is to support pickle 312 if Enum is not None: 313 # if the user defined their own __new__, save it before it gets 314 # clobbered in case they subclass later 315 if save_new: 316 enum_class.__new_member__ = __new__ 317 enum_class.__new__ = Enum.__new__ 318 319 # py3 support for definition order (helps keep py2/py3 code in sync) 320 if _order_ is not None: 321 if isinstance(_order_, str): 322 _order_ = _order_.replace(',', ' ').split() 323 if _order_ != enum_class._member_names_: 324 raise TypeError('member order does not match _order_') 325 326 return enum_class 327 328 def __bool__(self): 329 """ 330 classes/types should always be True. 331 """ 332 return True 333 334 def __call__(cls, value, names=None, *, module=None, qualname=None, type=None, start=1): 335 """ 336 Either returns an existing member, or creates a new enum class. 337 338 This method is used both when an enum class is given a value to match 339 to an enumeration member (i.e. Color(3)) and for the functional API 340 (i.e. Color = Enum('Color', names='RED GREEN BLUE')). 341 342 When used for the functional API: 343 344 `value` will be the name of the new class. 345 346 `names` should be either a string of white-space/comma delimited names 347 (values will start at `start`), or an iterator/mapping of name, value pairs. 348 349 `module` should be set to the module this class is being created in; 350 if it is not set, an attempt to find that module will be made, but if 351 it fails the class will not be picklable. 352 353 `qualname` should be set to the actual location this class can be found 354 at in its module; by default it is set to the global scope. If this is 355 not correct, unpickling will fail in some circumstances. 356 357 `type`, if set, will be mixed in as the first base class. 358 """ 359 if names is None: # simple value lookup 360 return cls.__new__(cls, value) 361 # otherwise, functional API: we're creating a new Enum type 362 return cls._create_( 363 value, 364 names, 365 module=module, 366 qualname=qualname, 367 type=type, 368 start=start, 369 ) 370 371 def __contains__(cls, member): 372 if not isinstance(member, Enum): 373 raise TypeError( 374 "unsupported operand type(s) for 'in': '%s' and '%s'" % ( 375 type(member).__qualname__, cls.__class__.__qualname__)) 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().__delattr__(attr) 384 385 def __dir__(self): 386 return ( 387 ['__class__', '__doc__', '__members__', '__module__'] 388 + self._member_names_ 389 ) 390 391 def __getattr__(cls, name): 392 """ 393 Return the enum member matching `name` 394 395 We use __getattr__ instead of descriptors or inserting into the enum 396 class' __dict__ in order to support `name` and `value` being both 397 properties for enum members (which live in the class' __dict__) and 398 enum members themselves. 399 """ 400 if _is_dunder(name): 401 raise AttributeError(name) 402 try: 403 return cls._member_map_[name] 404 except KeyError: 405 raise AttributeError(name) from None 406 407 def __getitem__(cls, name): 408 return cls._member_map_[name] 409 410 def __iter__(cls): 411 """ 412 Returns members in definition order. 413 """ 414 return (cls._member_map_[name] for name in cls._member_names_) 415 416 def __len__(cls): 417 return len(cls._member_names_) 418 419 @property 420 def __members__(cls): 421 """ 422 Returns a mapping of member name->value. 423 424 This mapping lists all enum members, including aliases. Note that this 425 is a read-only view of the internal mapping. 426 """ 427 return MappingProxyType(cls._member_map_) 428 429 def __repr__(cls): 430 return "<enum %r>" % cls.__name__ 431 432 def __reversed__(cls): 433 """ 434 Returns members in reverse definition order. 435 """ 436 return (cls._member_map_[name] for name in reversed(cls._member_names_)) 437 438 def __setattr__(cls, name, value): 439 """ 440 Block attempts to reassign Enum members. 441 442 A simple assignment to the class namespace only changes one of the 443 several possible ways to get an Enum member from the Enum class, 444 resulting in an inconsistent Enumeration. 445 """ 446 member_map = cls.__dict__.get('_member_map_', {}) 447 if name in member_map: 448 raise AttributeError('Cannot reassign members.') 449 super().__setattr__(name, value) 450 451 def _create_(cls, class_name, names, *, module=None, qualname=None, type=None, start=1): 452 """ 453 Convenience method to create a new Enum class. 454 455 `names` can be: 456 457 * A string containing member names, separated either with spaces or 458 commas. Values are incremented by 1 from `start`. 459 * An iterable of member names. Values are incremented by 1 from `start`. 460 * An iterable of (member name, value) pairs. 461 * A mapping of member name -> value pairs. 462 """ 463 metacls = cls.__class__ 464 bases = (cls, ) if type is None else (type, cls) 465 _, first_enum = cls._get_mixins_(cls, bases) 466 classdict = metacls.__prepare__(class_name, bases) 467 468 # special processing needed for names? 469 if isinstance(names, str): 470 names = names.replace(',', ' ').split() 471 if isinstance(names, (tuple, list)) and names and isinstance(names[0], str): 472 original_names, names = names, [] 473 last_values = [] 474 for count, name in enumerate(original_names): 475 value = first_enum._generate_next_value_(name, start, count, last_values[:]) 476 last_values.append(value) 477 names.append((name, value)) 478 479 # Here, names is either an iterable of (name, value) or a mapping. 480 for item in names: 481 if isinstance(item, str): 482 member_name, member_value = item, names[item] 483 else: 484 member_name, member_value = item 485 classdict[member_name] = member_value 486 enum_class = metacls.__new__(metacls, class_name, bases, classdict) 487 488 # TODO: replace the frame hack if a blessed way to know the calling 489 # module is ever developed 490 if module is None: 491 try: 492 module = sys._getframe(2).f_globals['__name__'] 493 except (AttributeError, ValueError, KeyError): 494 pass 495 if module is None: 496 _make_class_unpicklable(enum_class) 497 else: 498 enum_class.__module__ = module 499 if qualname is not None: 500 enum_class.__qualname__ = qualname 501 502 return enum_class 503 504 def _convert_(cls, name, module, filter, source=None): 505 """ 506 Create a new Enum subclass that replaces a collection of global constants 507 """ 508 # convert all constants from source (or module) that pass filter() to 509 # a new Enum called name, and export the enum and its members back to 510 # module; 511 # also, replace the __reduce_ex__ method so unpickling works in 512 # previous Python versions 513 module_globals = vars(sys.modules[module]) 514 if source: 515 source = vars(source) 516 else: 517 source = module_globals 518 # _value2member_map_ is populated in the same order every time 519 # for a consistent reverse mapping of number to name when there 520 # are multiple names for the same number. 521 members = [ 522 (name, value) 523 for name, value in source.items() 524 if filter(name)] 525 try: 526 # sort by value 527 members.sort(key=lambda t: (t[1], t[0])) 528 except TypeError: 529 # unless some values aren't comparable, in which case sort by name 530 members.sort(key=lambda t: t[0]) 531 cls = cls(name, members, module=module) 532 cls.__reduce_ex__ = _reduce_ex_by_name 533 module_globals.update(cls.__members__) 534 module_globals[name] = cls 535 return cls 536 537 @staticmethod 538 def _check_for_existing_members(class_name, bases): 539 for chain in bases: 540 for base in chain.__mro__: 541 if issubclass(base, Enum) and base._member_names_: 542 raise TypeError( 543 "%s: cannot extend enumeration %r" 544 % (class_name, base.__name__) 545 ) 546 547 @staticmethod 548 def _get_mixins_(class_name, bases): 549 """ 550 Returns the type for creating enum members, and the first inherited 551 enum class. 552 553 bases: the tuple of bases that was given to __new__ 554 """ 555 if not bases: 556 return object, Enum 557 558 def _find_data_type(bases): 559 data_types = [] 560 for chain in bases: 561 candidate = None 562 for base in chain.__mro__: 563 if base is object: 564 continue 565 elif issubclass(base, Enum): 566 if base._member_type_ is not object: 567 data_types.append(base._member_type_) 568 break 569 elif '__new__' in base.__dict__: 570 if issubclass(base, Enum): 571 continue 572 data_types.append(candidate or base) 573 break 574 else: 575 candidate = base 576 if len(data_types) > 1: 577 raise TypeError('%r: too many data types: %r' % (class_name, data_types)) 578 elif data_types: 579 return data_types[0] 580 else: 581 return None 582 583 # ensure final parent class is an Enum derivative, find any concrete 584 # data type, and check that Enum has no members 585 first_enum = bases[-1] 586 if not issubclass(first_enum, Enum): 587 raise TypeError("new enumerations should be created as " 588 "`EnumName([mixin_type, ...] [data_type,] enum_type)`") 589 member_type = _find_data_type(bases) or object 590 if first_enum._member_names_: 591 raise TypeError("Cannot extend enumerations") 592 return member_type, first_enum 593 594 @staticmethod 595 def _find_new_(classdict, member_type, first_enum): 596 """ 597 Returns the __new__ to be used for creating the enum members. 598 599 classdict: the class dictionary given to __new__ 600 member_type: the data type whose __new__ will be used by default 601 first_enum: enumeration to check for an overriding __new__ 602 """ 603 # now find the correct __new__, checking to see of one was defined 604 # by the user; also check earlier enum classes in case a __new__ was 605 # saved as __new_member__ 606 __new__ = classdict.get('__new__', None) 607 608 # should __new__ be saved as __new_member__ later? 609 save_new = __new__ is not None 610 611 if __new__ is None: 612 # check all possibles for __new_member__ before falling back to 613 # __new__ 614 for method in ('__new_member__', '__new__'): 615 for possible in (member_type, first_enum): 616 target = getattr(possible, method, None) 617 if target not in { 618 None, 619 None.__new__, 620 object.__new__, 621 Enum.__new__, 622 }: 623 __new__ = target 624 break 625 if __new__ is not None: 626 break 627 else: 628 __new__ = object.__new__ 629 630 # if a non-object.__new__ is used then whatever value/tuple was 631 # assigned to the enum member name will be passed to __new__ and to the 632 # new enum member's __init__ 633 if __new__ is object.__new__: 634 use_args = False 635 else: 636 use_args = True 637 return __new__, save_new, use_args 638 639 640class Enum(metaclass=EnumMeta): 641 """ 642 Generic enumeration. 643 644 Derive from this class to define new enumerations. 645 """ 646 def __new__(cls, value): 647 # all enum instances are actually created during class construction 648 # without calling this method; this method is called by the metaclass' 649 # __call__ (i.e. Color(3) ), and by pickle 650 if type(value) is cls: 651 # For lookups like Color(Color.RED) 652 return value 653 # by-value search for a matching enum member 654 # see if it's in the reverse mapping (for hashable values) 655 try: 656 return cls._value2member_map_[value] 657 except KeyError: 658 # Not found, no need to do long O(n) search 659 pass 660 except TypeError: 661 # not there, now do long search -- O(n) behavior 662 for member in cls._member_map_.values(): 663 if member._value_ == value: 664 return member 665 # still not found -- try _missing_ hook 666 try: 667 exc = None 668 result = cls._missing_(value) 669 except Exception as e: 670 exc = e 671 result = None 672 if isinstance(result, cls): 673 return result 674 else: 675 ve_exc = ValueError("%r is not a valid %s" % (value, cls.__qualname__)) 676 if result is None and exc is None: 677 raise ve_exc 678 elif exc is None: 679 exc = TypeError( 680 'error in %s._missing_: returned %r instead of None or a valid member' 681 % (cls.__name__, result) 682 ) 683 exc.__context__ = ve_exc 684 raise exc 685 686 def _generate_next_value_(name, start, count, last_values): 687 """ 688 Generate the next value when not given. 689 690 name: the name of the member 691 start: the initial start value or None 692 count: the number of existing members 693 last_value: the last value assigned or None 694 """ 695 for last_value in reversed(last_values): 696 try: 697 return last_value + 1 698 except TypeError: 699 pass 700 else: 701 return start 702 703 @classmethod 704 def _missing_(cls, value): 705 return None 706 707 def __repr__(self): 708 return "<%s.%s: %r>" % ( 709 self.__class__.__name__, self._name_, self._value_) 710 711 def __str__(self): 712 return "%s.%s" % (self.__class__.__name__, self._name_) 713 714 def __dir__(self): 715 """ 716 Returns all members and all public methods 717 """ 718 added_behavior = [ 719 m 720 for cls in self.__class__.mro() 721 for m in cls.__dict__ 722 if m[0] != '_' and m not in self._member_map_ 723 ] + [m for m in self.__dict__ if m[0] != '_'] 724 return (['__class__', '__doc__', '__module__'] + added_behavior) 725 726 def __format__(self, format_spec): 727 """ 728 Returns format using actual value type unless __str__ has been overridden. 729 """ 730 # mixed-in Enums should use the mixed-in type's __format__, otherwise 731 # we can get strange results with the Enum name showing up instead of 732 # the value 733 734 # pure Enum branch, or branch with __str__ explicitly overridden 735 str_overridden = type(self).__str__ not in (Enum.__str__, Flag.__str__) 736 if self._member_type_ is object or str_overridden: 737 cls = str 738 val = str(self) 739 # mix-in branch 740 else: 741 cls = self._member_type_ 742 val = self._value_ 743 return cls.__format__(val, format_spec) 744 745 def __hash__(self): 746 return hash(self._name_) 747 748 def __reduce_ex__(self, proto): 749 return self.__class__, (self._value_, ) 750 751 # DynamicClassAttribute is used to provide access to the `name` and 752 # `value` properties of enum members while keeping some measure of 753 # protection from modification, while still allowing for an enumeration 754 # to have members named `name` and `value`. This works because enumeration 755 # members are not set directly on the enum class -- __getattr__ is 756 # used to look them up. 757 758 @DynamicClassAttribute 759 def name(self): 760 """The name of the Enum member.""" 761 return self._name_ 762 763 @DynamicClassAttribute 764 def value(self): 765 """The value of the Enum member.""" 766 return self._value_ 767 768 769class IntEnum(int, Enum): 770 """Enum where members are also (and must be) ints""" 771 772 773def _reduce_ex_by_name(self, proto): 774 return self.name 775 776class Flag(Enum): 777 """ 778 Support for flags 779 """ 780 781 def _generate_next_value_(name, start, count, last_values): 782 """ 783 Generate the next value when not given. 784 785 name: the name of the member 786 start: the initial start value or None 787 count: the number of existing members 788 last_value: the last value assigned or None 789 """ 790 if not count: 791 return start if start is not None else 1 792 for last_value in reversed(last_values): 793 try: 794 high_bit = _high_bit(last_value) 795 break 796 except Exception: 797 raise TypeError('Invalid Flag value: %r' % last_value) from None 798 return 2 ** (high_bit+1) 799 800 @classmethod 801 def _missing_(cls, value): 802 """ 803 Returns member (possibly creating it) if one can be found for value. 804 """ 805 original_value = value 806 if value < 0: 807 value = ~value 808 possible_member = cls._create_pseudo_member_(value) 809 if original_value < 0: 810 possible_member = ~possible_member 811 return possible_member 812 813 @classmethod 814 def _create_pseudo_member_(cls, value): 815 """ 816 Create a composite member iff value contains only members. 817 """ 818 pseudo_member = cls._value2member_map_.get(value, None) 819 if pseudo_member is None: 820 # verify all bits are accounted for 821 _, extra_flags = _decompose(cls, value) 822 if extra_flags: 823 raise ValueError("%r is not a valid %s" % (value, cls.__qualname__)) 824 # construct a singleton enum pseudo-member 825 pseudo_member = object.__new__(cls) 826 pseudo_member._name_ = None 827 pseudo_member._value_ = value 828 # use setdefault in case another thread already created a composite 829 # with this value 830 pseudo_member = cls._value2member_map_.setdefault(value, pseudo_member) 831 return pseudo_member 832 833 def __contains__(self, other): 834 """ 835 Returns True if self has at least the same flags set as other. 836 """ 837 if not isinstance(other, self.__class__): 838 raise TypeError( 839 "unsupported operand type(s) for 'in': '%s' and '%s'" % ( 840 type(other).__qualname__, self.__class__.__qualname__)) 841 return other._value_ & self._value_ == other._value_ 842 843 def __repr__(self): 844 cls = self.__class__ 845 if self._name_ is not None: 846 return '<%s.%s: %r>' % (cls.__name__, self._name_, self._value_) 847 members, uncovered = _decompose(cls, self._value_) 848 return '<%s.%s: %r>' % ( 849 cls.__name__, 850 '|'.join([str(m._name_ or m._value_) for m in members]), 851 self._value_, 852 ) 853 854 def __str__(self): 855 cls = self.__class__ 856 if self._name_ is not None: 857 return '%s.%s' % (cls.__name__, self._name_) 858 members, uncovered = _decompose(cls, self._value_) 859 if len(members) == 1 and members[0]._name_ is None: 860 return '%s.%r' % (cls.__name__, members[0]._value_) 861 else: 862 return '%s.%s' % ( 863 cls.__name__, 864 '|'.join([str(m._name_ or m._value_) for m in members]), 865 ) 866 867 def __bool__(self): 868 return bool(self._value_) 869 870 def __or__(self, other): 871 if not isinstance(other, self.__class__): 872 return NotImplemented 873 return self.__class__(self._value_ | other._value_) 874 875 def __and__(self, other): 876 if not isinstance(other, self.__class__): 877 return NotImplemented 878 return self.__class__(self._value_ & other._value_) 879 880 def __xor__(self, other): 881 if not isinstance(other, self.__class__): 882 return NotImplemented 883 return self.__class__(self._value_ ^ other._value_) 884 885 def __invert__(self): 886 members, uncovered = _decompose(self.__class__, self._value_) 887 inverted = self.__class__(0) 888 for m in self.__class__: 889 if m not in members and not (m._value_ & self._value_): 890 inverted = inverted | m 891 return self.__class__(inverted) 892 893 894class IntFlag(int, Flag): 895 """ 896 Support for integer-based Flags 897 """ 898 899 @classmethod 900 def _missing_(cls, value): 901 """ 902 Returns member (possibly creating it) if one can be found for value. 903 """ 904 if not isinstance(value, int): 905 raise ValueError("%r is not a valid %s" % (value, cls.__qualname__)) 906 new_member = cls._create_pseudo_member_(value) 907 return new_member 908 909 @classmethod 910 def _create_pseudo_member_(cls, value): 911 """ 912 Create a composite member iff value contains only members. 913 """ 914 pseudo_member = cls._value2member_map_.get(value, None) 915 if pseudo_member is None: 916 need_to_create = [value] 917 # get unaccounted for bits 918 _, extra_flags = _decompose(cls, value) 919 # timer = 10 920 while extra_flags: 921 # timer -= 1 922 bit = _high_bit(extra_flags) 923 flag_value = 2 ** bit 924 if (flag_value not in cls._value2member_map_ and 925 flag_value not in need_to_create 926 ): 927 need_to_create.append(flag_value) 928 if extra_flags == -flag_value: 929 extra_flags = 0 930 else: 931 extra_flags ^= flag_value 932 for value in reversed(need_to_create): 933 # construct singleton pseudo-members 934 pseudo_member = int.__new__(cls, value) 935 pseudo_member._name_ = None 936 pseudo_member._value_ = value 937 # use setdefault in case another thread already created a composite 938 # with this value 939 pseudo_member = cls._value2member_map_.setdefault(value, pseudo_member) 940 return pseudo_member 941 942 def __or__(self, other): 943 if not isinstance(other, (self.__class__, int)): 944 return NotImplemented 945 result = self.__class__(self._value_ | self.__class__(other)._value_) 946 return result 947 948 def __and__(self, other): 949 if not isinstance(other, (self.__class__, int)): 950 return NotImplemented 951 return self.__class__(self._value_ & self.__class__(other)._value_) 952 953 def __xor__(self, other): 954 if not isinstance(other, (self.__class__, int)): 955 return NotImplemented 956 return self.__class__(self._value_ ^ self.__class__(other)._value_) 957 958 __ror__ = __or__ 959 __rand__ = __and__ 960 __rxor__ = __xor__ 961 962 def __invert__(self): 963 result = self.__class__(~self._value_) 964 return result 965 966 967def _high_bit(value): 968 """ 969 returns index of highest bit, or -1 if value is zero or negative 970 """ 971 return value.bit_length() - 1 972 973def unique(enumeration): 974 """ 975 Class decorator for enumerations ensuring unique member values. 976 """ 977 duplicates = [] 978 for name, member in enumeration.__members__.items(): 979 if name != member.name: 980 duplicates.append((name, member.name)) 981 if duplicates: 982 alias_details = ', '.join( 983 ["%s -> %s" % (alias, name) for (alias, name) in duplicates]) 984 raise ValueError('duplicate values found in %r: %s' % 985 (enumeration, alias_details)) 986 return enumeration 987 988def _decompose(flag, value): 989 """ 990 Extract all members from the value. 991 """ 992 # _decompose is only called if the value is not named 993 not_covered = value 994 negative = value < 0 995 members = [] 996 for member in flag: 997 member_value = member.value 998 if member_value and member_value & value == member_value: 999 members.append(member) 1000 not_covered &= ~member_value 1001 if not negative: 1002 tmp = not_covered 1003 while tmp: 1004 flag_value = 2 ** _high_bit(tmp) 1005 if flag_value in flag._value2member_map_: 1006 members.append(flag._value2member_map_[flag_value]) 1007 not_covered &= ~flag_value 1008 tmp &= ~flag_value 1009 if not members and value in flag._value2member_map_: 1010 members.append(flag._value2member_map_[value]) 1011 members.sort(key=lambda m: m._value_, reverse=True) 1012 if len(members) > 1 and members[0].value == value: 1013 # we have the breakdown, don't need the value member itself 1014 members.pop(0) 1015 return members, not_covered 1016