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