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