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