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