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