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