blob: 40ff25b9cdad37bc31242bf55e0f84af54547c04 [file] [log] [blame]
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001import sys
Ethan Furmane03ea372013-09-25 07:14:41 -07002from types import MappingProxyType, DynamicClassAttribute
Ethan Furman6b3d64a2013-06-14 16:55:46 -07003
Ethan Furmane5754ab2015-09-17 22:03:52 -07004
Ethan Furmanc16595e2016-09-10 23:36:59 -07005__all__ = [
6 'EnumMeta',
Ethan Furman0063ff42020-09-21 17:23:13 -07007 'Enum', 'IntEnum', 'StrEnum', 'Flag', 'IntFlag',
Ethan Furmanc16595e2016-09-10 23:36:59 -07008 'auto', 'unique',
9 ]
Ethan Furman6b3d64a2013-06-14 16:55:46 -070010
11
Ethan Furman101e0742013-09-15 12:34:36 -070012def _is_descriptor(obj):
13 """Returns True if obj is a descriptor, False otherwise."""
14 return (
15 hasattr(obj, '__get__') or
16 hasattr(obj, '__set__') or
17 hasattr(obj, '__delete__'))
18
19
Ethan Furman6b3d64a2013-06-14 16:55:46 -070020def _is_dunder(name):
21 """Returns True if a __dunder__ name, False otherwise."""
Brennan D Baraban8b914d22019-03-03 14:09:11 -080022 return (len(name) > 4 and
23 name[:2] == name[-2:] == '__' and
24 name[2] != '_' and
25 name[-3] != '_')
Ethan Furman6b3d64a2013-06-14 16:55:46 -070026
27
28def _is_sunder(name):
29 """Returns True if a _sunder_ name, False otherwise."""
Brennan D Baraban8b914d22019-03-03 14:09:11 -080030 return (len(name) > 2 and
31 name[0] == name[-1] == '_' and
Ethan Furman6b3d64a2013-06-14 16:55:46 -070032 name[1:2] != '_' and
Brennan D Baraban8b914d22019-03-03 14:09:11 -080033 name[-2:-1] != '_')
34
Ethan Furman6b3d64a2013-06-14 16:55:46 -070035
Ethan Furman6b3d64a2013-06-14 16:55:46 -070036def _make_class_unpicklable(cls):
37 """Make the given class un-picklable."""
Ethan Furmanca1b7942014-02-08 11:36:27 -080038 def _break_on_call_reduce(self, proto):
Ethan Furman6b3d64a2013-06-14 16:55:46 -070039 raise TypeError('%r cannot be pickled' % self)
Ethan Furmanca1b7942014-02-08 11:36:27 -080040 cls.__reduce_ex__ = _break_on_call_reduce
Ethan Furman6b3d64a2013-06-14 16:55:46 -070041 cls.__module__ = '<unknown>'
42
Ethan Furman3515dcc2016-09-18 13:15:41 -070043_auto_null = object()
Ethan Furmanc16595e2016-09-10 23:36:59 -070044class auto:
45 """
46 Instances are replaced with an appropriate value in Enum class suites.
47 """
Ethan Furman3515dcc2016-09-18 13:15:41 -070048 value = _auto_null
Ethan Furmanc16595e2016-09-10 23:36:59 -070049
Ethan Furman101e0742013-09-15 12:34:36 -070050
Ethan Furman6b3d64a2013-06-14 16:55:46 -070051class _EnumDict(dict):
Ethan Furman101e0742013-09-15 12:34:36 -070052 """Track enum member order and ensure member names are not reused.
Ethan Furman6b3d64a2013-06-14 16:55:46 -070053
54 EnumMeta will use the names found in self._member_names as the
55 enumeration member names.
56
57 """
58 def __init__(self):
59 super().__init__()
60 self._member_names = []
Ethan Furmanc16595e2016-09-10 23:36:59 -070061 self._last_values = []
Ethan Furmana4b1bb42018-01-22 07:56:37 -080062 self._ignore = []
Ethan Onstottd9a43e22020-04-28 13:20:55 -040063 self._auto_called = False
Ethan Furman6b3d64a2013-06-14 16:55:46 -070064
65 def __setitem__(self, key, value):
Ethan Furman101e0742013-09-15 12:34:36 -070066 """Changes anything not dundered or not a descriptor.
Ethan Furman6b3d64a2013-06-14 16:55:46 -070067
68 If an enum member name is used twice, an error is raised; duplicate
69 values are not checked for.
70
71 Single underscore (sunder) names are reserved.
72
73 """
74 if _is_sunder(key):
Ethan Furmanee47e5c2016-08-31 00:12:15 -070075 if key not in (
Ethan Furman3515dcc2016-09-18 13:15:41 -070076 '_order_', '_create_pseudo_member_',
Ethan Furmana4b1bb42018-01-22 07:56:37 -080077 '_generate_next_value_', '_missing_', '_ignore_',
Ethan Furmanee47e5c2016-08-31 00:12:15 -070078 ):
Zackery Spytz2ec67522020-09-13 14:27:51 -060079 raise ValueError(f'_sunder_ names, such as "{key}", are '
80 'reserved for future Enum use')
Ethan Furmanc16595e2016-09-10 23:36:59 -070081 if key == '_generate_next_value_':
Ethan Onstottd9a43e22020-04-28 13:20:55 -040082 # check if members already defined as auto()
83 if self._auto_called:
84 raise TypeError("_generate_next_value_ must be defined before members")
Ethan Furmanc16595e2016-09-10 23:36:59 -070085 setattr(self, '_generate_next_value', value)
Ethan Furmana4b1bb42018-01-22 07:56:37 -080086 elif key == '_ignore_':
87 if isinstance(value, str):
88 value = value.replace(',',' ').split()
89 else:
90 value = list(value)
91 self._ignore = value
92 already = set(value) & set(self._member_names)
93 if already:
94 raise ValueError('_ignore_ cannot specify already set names: %r' % (already, ))
Ethan Furman101e0742013-09-15 12:34:36 -070095 elif _is_dunder(key):
Ethan Furmane8e61272016-08-20 07:19:31 -070096 if key == '__order__':
97 key = '_order_'
Ethan Furman101e0742013-09-15 12:34:36 -070098 elif key in self._member_names:
99 # descriptor overwriting an enum?
100 raise TypeError('Attempted to reuse key: %r' % key)
Ethan Furmana4b1bb42018-01-22 07:56:37 -0800101 elif key in self._ignore:
102 pass
Ethan Furman101e0742013-09-15 12:34:36 -0700103 elif not _is_descriptor(value):
104 if key in self:
105 # enum overwriting a descriptor?
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700106 raise TypeError('%r already defined as: %r' % (key, self[key]))
Ethan Furmanc16595e2016-09-10 23:36:59 -0700107 if isinstance(value, auto):
Ethan Furman3515dcc2016-09-18 13:15:41 -0700108 if value.value == _auto_null:
109 value.value = self._generate_next_value(key, 1, len(self._member_names), self._last_values[:])
Ethan Furmanfc23a942020-09-16 12:37:54 -0700110 self._auto_called = True
Ethan Furman3515dcc2016-09-18 13:15:41 -0700111 value = value.value
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700112 self._member_names.append(key)
Ethan Furmanc16595e2016-09-10 23:36:59 -0700113 self._last_values.append(value)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700114 super().__setitem__(key, value)
115
116
Ezio Melotti9a3777e2013-08-17 15:53:55 +0300117# Dummy value for Enum as EnumMeta explicitly checks for it, but of course
118# until EnumMeta finishes running the first time the Enum class doesn't exist.
119# This is also why there are checks in EnumMeta like `if Enum is not None`
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700120Enum = None
121
Ethan Furman332dbc72016-08-20 00:00:52 -0700122
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700123class EnumMeta(type):
124 """Metaclass for Enum"""
125 @classmethod
Ethan Furman332dbc72016-08-20 00:00:52 -0700126 def __prepare__(metacls, cls, bases):
Ethan Furman3064dbf2020-09-16 07:11:57 -0700127 # check that previous enum members do not exist
128 metacls._check_for_existing_members(cls, bases)
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700129 # create the namespace dict
130 enum_dict = _EnumDict()
131 # inherit previous flags and _generate_next_value_ function
Ethan Furman3064dbf2020-09-16 07:11:57 -0700132 member_type, first_enum = metacls._get_mixins_(cls, bases)
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700133 if first_enum is not None:
134 enum_dict['_generate_next_value_'] = getattr(first_enum, '_generate_next_value_', None)
135 return enum_dict
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700136
Ethan Furman65a5a472016-09-01 23:55:19 -0700137 def __new__(metacls, cls, bases, classdict):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700138 # an Enum class is final once enumeration items have been defined; it
139 # cannot be mixed with other types (int, float, etc.) if it has an
140 # inherited __new__ unless a new __new__ is defined (or the resulting
141 # class will fail).
Ethan Furmana4b1bb42018-01-22 07:56:37 -0800142 #
143 # remove any keys listed in _ignore_
144 classdict.setdefault('_ignore_', []).append('_ignore_')
145 ignore = classdict['_ignore_']
146 for key in ignore:
147 classdict.pop(key, None)
Ethan Furman3064dbf2020-09-16 07:11:57 -0700148 member_type, first_enum = metacls._get_mixins_(cls, bases)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700149 __new__, save_new, use_args = metacls._find_new_(classdict, member_type,
150 first_enum)
151
152 # save enum items into separate mapping so they don't get baked into
153 # the new class
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700154 enum_members = {k: classdict[k] for k in classdict._member_names}
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700155 for name in classdict._member_names:
156 del classdict[name]
157
Ethan Furmane8e61272016-08-20 07:19:31 -0700158 # adjust the sunders
159 _order_ = classdict.pop('_order_', None)
160
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700161 # check for illegal enum names (any others?)
Brennan D Baraban8b914d22019-03-03 14:09:11 -0800162 invalid_names = set(enum_members) & {'mro', ''}
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700163 if invalid_names:
164 raise ValueError('Invalid enum member name: {0}'.format(
165 ','.join(invalid_names)))
166
Ethan Furman48a724f2015-04-11 23:23:06 -0700167 # create a default docstring if one has not been provided
168 if '__doc__' not in classdict:
169 classdict['__doc__'] = 'An enumeration.'
170
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700171 # create our new Enum type
172 enum_class = super().__new__(metacls, cls, bases, classdict)
Ethan Furman520ad572013-07-19 19:47:21 -0700173 enum_class._member_names_ = [] # names in definition order
INADA Naokie57f91a2018-06-19 01:14:26 +0900174 enum_class._member_map_ = {} # name->value map
Ethan Furman5e5a8232013-08-04 08:42:23 -0700175 enum_class._member_type_ = member_type
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700176
orlnub1230fb9fad2018-09-12 20:28:53 +0300177 # save DynamicClassAttribute attributes from super classes so we know
178 # if we can take the shortcut of storing members in the class dict
179 dynamic_attributes = {k for c in enum_class.mro()
180 for k, v in c.__dict__.items()
181 if isinstance(v, DynamicClassAttribute)}
Ethan Furman354ecf12015-03-11 08:43:12 -0700182
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700183 # Reverse value->name map for hashable values.
Ethan Furman520ad572013-07-19 19:47:21 -0700184 enum_class._value2member_map_ = {}
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700185
Ethan Furman2da95042014-03-03 12:42:52 -0800186 # If a custom type is mixed into the Enum, and it does not know how
187 # to pickle itself, pickle.dumps will succeed but pickle.loads will
188 # fail. Rather than have the error show up later and possibly far
189 # from the source, sabotage the pickle protocol for this class so
190 # that pickle.dumps also fails.
191 #
192 # However, if the new class implements its own __reduce_ex__, do not
193 # sabotage -- it's on them to make sure it works correctly. We use
194 # __reduce_ex__ instead of any of the others as it is preferred by
195 # pickle over __reduce__, and it handles all pickle protocols.
196 if '__reduce_ex__' not in classdict:
Ethan Furmandc870522014-02-18 12:37:12 -0800197 if member_type is not object:
198 methods = ('__getnewargs_ex__', '__getnewargs__',
199 '__reduce_ex__', '__reduce__')
Ethan Furman2da95042014-03-03 12:42:52 -0800200 if not any(m in member_type.__dict__ for m in methods):
Ethan Furmandc870522014-02-18 12:37:12 -0800201 _make_class_unpicklable(enum_class)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700202
203 # instantiate them, checking for duplicates as we go
204 # we instantiate first instead of checking for duplicates first in case
205 # a custom __new__ is doing something funky with the values -- such as
206 # auto-numbering ;)
207 for member_name in classdict._member_names:
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700208 value = enum_members[member_name]
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700209 if not isinstance(value, tuple):
210 args = (value, )
211 else:
212 args = value
213 if member_type is tuple: # special case for tuple enums
214 args = (args, ) # wrap it one more time
215 if not use_args:
216 enum_member = __new__(enum_class)
Ethan Furmanb41803e2013-07-25 13:50:45 -0700217 if not hasattr(enum_member, '_value_'):
218 enum_member._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700219 else:
220 enum_member = __new__(enum_class, *args)
Ethan Furmanb41803e2013-07-25 13:50:45 -0700221 if not hasattr(enum_member, '_value_'):
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700222 if member_type is object:
223 enum_member._value_ = value
224 else:
225 enum_member._value_ = member_type(*args)
Ethan Furman520ad572013-07-19 19:47:21 -0700226 value = enum_member._value_
Ethan Furman520ad572013-07-19 19:47:21 -0700227 enum_member._name_ = member_name
Ethan Furmanc850f342013-09-15 16:59:35 -0700228 enum_member.__objclass__ = enum_class
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700229 enum_member.__init__(*args)
230 # If another member with the same value was already defined, the
231 # new member becomes an alias to the existing one.
Ethan Furman520ad572013-07-19 19:47:21 -0700232 for name, canonical_member in enum_class._member_map_.items():
Ethan Furman0081f232014-09-16 17:31:23 -0700233 if canonical_member._value_ == enum_member._value_:
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700234 enum_member = canonical_member
235 break
236 else:
237 # Aliases don't appear in member names (only in __members__).
Ethan Furman520ad572013-07-19 19:47:21 -0700238 enum_class._member_names_.append(member_name)
Ethan Furman354ecf12015-03-11 08:43:12 -0700239 # performance boost for any member that would not shadow
240 # a DynamicClassAttribute
orlnub1230fb9fad2018-09-12 20:28:53 +0300241 if member_name not in dynamic_attributes:
Ethan Furman354ecf12015-03-11 08:43:12 -0700242 setattr(enum_class, member_name, enum_member)
243 # now add to _member_map_
Ethan Furman520ad572013-07-19 19:47:21 -0700244 enum_class._member_map_[member_name] = enum_member
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700245 try:
246 # This may fail if value is not hashable. We can't add the value
247 # to the map, and by-value lookups for this value will be
248 # linear.
Ethan Furman520ad572013-07-19 19:47:21 -0700249 enum_class._value2member_map_[value] = enum_member
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700250 except TypeError:
251 pass
252
253 # double check that repr and friends are not the mixin's or various
254 # things break (such as pickle)
Ethan Furman22415ad2020-09-15 16:28:25 -0700255 # however, if the method is defined in the Enum itself, don't replace
256 # it
Ethan Furmandc870522014-02-18 12:37:12 -0800257 for name in ('__repr__', '__str__', '__format__', '__reduce_ex__'):
Ethan Furman22415ad2020-09-15 16:28:25 -0700258 if name in classdict:
259 continue
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700260 class_method = getattr(enum_class, name)
261 obj_method = getattr(member_type, name, None)
262 enum_method = getattr(first_enum, name, None)
263 if obj_method is not None and obj_method is class_method:
264 setattr(enum_class, name, enum_method)
265
266 # replace any other __new__ with our own (as long as Enum is not None,
267 # anyway) -- again, this is to support pickle
268 if Enum is not None:
269 # if the user defined their own __new__, save it before it gets
270 # clobbered in case they subclass later
271 if save_new:
272 enum_class.__new_member__ = __new__
273 enum_class.__new__ = Enum.__new__
Ethan Furmane8e61272016-08-20 07:19:31 -0700274
275 # py3 support for definition order (helps keep py2/py3 code in sync)
276 if _order_ is not None:
277 if isinstance(_order_, str):
278 _order_ = _order_.replace(',', ' ').split()
279 if _order_ != enum_class._member_names_:
280 raise TypeError('member order does not match _order_')
281
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700282 return enum_class
283
Ethan Furman5de67b12016-04-13 23:52:09 -0700284 def __bool__(self):
285 """
286 classes/types should always be True.
287 """
288 return True
289
Ethan Furmand9925a12014-09-16 20:35:55 -0700290 def __call__(cls, value, names=None, *, module=None, qualname=None, type=None, start=1):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700291 """Either returns an existing member, or creates a new enum class.
292
293 This method is used both when an enum class is given a value to match
294 to an enumeration member (i.e. Color(3)) and for the functional API
Ethan Furman23bb6f42016-11-21 09:22:05 -0800295 (i.e. Color = Enum('Color', names='RED GREEN BLUE')).
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700296
Ethan Furman2da95042014-03-03 12:42:52 -0800297 When used for the functional API:
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700298
Ethan Furman2da95042014-03-03 12:42:52 -0800299 `value` will be the name of the new class.
300
301 `names` should be either a string of white-space/comma delimited names
Ethan Furmand9925a12014-09-16 20:35:55 -0700302 (values will start at `start`), or an iterator/mapping of name, value pairs.
Ethan Furman2da95042014-03-03 12:42:52 -0800303
304 `module` should be set to the module this class is being created in;
305 if it is not set, an attempt to find that module will be made, but if
306 it fails the class will not be picklable.
307
308 `qualname` should be set to the actual location this class can be found
309 at in its module; by default it is set to the global scope. If this is
310 not correct, unpickling will fail in some circumstances.
311
312 `type`, if set, will be mixed in as the first base class.
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700313
314 """
315 if names is None: # simple value lookup
316 return cls.__new__(cls, value)
317 # otherwise, functional API: we're creating a new Enum type
Ethan Furmand9925a12014-09-16 20:35:55 -0700318 return cls._create_(value, names, module=module, qualname=qualname, type=type, start=start)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700319
320 def __contains__(cls, member):
Rahul Jha94306522018-09-10 23:51:04 +0530321 if not isinstance(member, Enum):
322 raise TypeError(
323 "unsupported operand type(s) for 'in': '%s' and '%s'" % (
324 type(member).__qualname__, cls.__class__.__qualname__))
Ethan Furman0081f232014-09-16 17:31:23 -0700325 return isinstance(member, cls) and member._name_ in cls._member_map_
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700326
Ethan Furman64a99722013-09-22 16:18:19 -0700327 def __delattr__(cls, attr):
328 # nicer error message when someone tries to delete an attribute
329 # (see issue19025).
330 if attr in cls._member_map_:
331 raise AttributeError(
332 "%s: cannot delete Enum member." % cls.__name__)
333 super().__delattr__(attr)
334
Ethan Furman388a3922013-08-12 06:51:41 -0700335 def __dir__(self):
Ethan Furman64a99722013-09-22 16:18:19 -0700336 return (['__class__', '__doc__', '__members__', '__module__'] +
337 self._member_names_)
Ethan Furman388a3922013-08-12 06:51:41 -0700338
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700339 def __getattr__(cls, name):
340 """Return the enum member matching `name`
341
342 We use __getattr__ instead of descriptors or inserting into the enum
343 class' __dict__ in order to support `name` and `value` being both
344 properties for enum members (which live in the class' __dict__) and
345 enum members themselves.
346
347 """
348 if _is_dunder(name):
349 raise AttributeError(name)
350 try:
Ethan Furman520ad572013-07-19 19:47:21 -0700351 return cls._member_map_[name]
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700352 except KeyError:
353 raise AttributeError(name) from None
354
355 def __getitem__(cls, name):
Ethan Furman520ad572013-07-19 19:47:21 -0700356 return cls._member_map_[name]
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700357
358 def __iter__(cls):
Ethan Furman520ad572013-07-19 19:47:21 -0700359 return (cls._member_map_[name] for name in cls._member_names_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700360
361 def __len__(cls):
Ethan Furman520ad572013-07-19 19:47:21 -0700362 return len(cls._member_names_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700363
Ethan Furman2131a4a2013-09-14 18:11:24 -0700364 @property
365 def __members__(cls):
366 """Returns a mapping of member name->value.
367
368 This mapping lists all enum members, including aliases. Note that this
369 is a read-only view of the internal mapping.
370
371 """
372 return MappingProxyType(cls._member_map_)
373
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700374 def __repr__(cls):
375 return "<enum %r>" % cls.__name__
376
Ethan Furman2131a4a2013-09-14 18:11:24 -0700377 def __reversed__(cls):
378 return (cls._member_map_[name] for name in reversed(cls._member_names_))
379
Ethan Furmanf203f2d2013-09-06 07:16:48 -0700380 def __setattr__(cls, name, value):
381 """Block attempts to reassign Enum members.
382
383 A simple assignment to the class namespace only changes one of the
384 several possible ways to get an Enum member from the Enum class,
385 resulting in an inconsistent Enumeration.
386
387 """
388 member_map = cls.__dict__.get('_member_map_', {})
389 if name in member_map:
390 raise AttributeError('Cannot reassign members.')
391 super().__setattr__(name, value)
392
anentropicb8e21f12018-04-16 04:40:35 +0100393 def _create_(cls, class_name, names, *, module=None, qualname=None, type=None, start=1):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700394 """Convenience method to create a new Enum class.
395
396 `names` can be:
397
398 * A string containing member names, separated either with spaces or
Ethan Furmand9925a12014-09-16 20:35:55 -0700399 commas. Values are incremented by 1 from `start`.
400 * An iterable of member names. Values are incremented by 1 from `start`.
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700401 * An iterable of (member name, value) pairs.
Ethan Furmand9925a12014-09-16 20:35:55 -0700402 * A mapping of member name -> value pairs.
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700403
404 """
405 metacls = cls.__class__
406 bases = (cls, ) if type is None else (type, cls)
Ethan Furman3064dbf2020-09-16 07:11:57 -0700407 _, first_enum = cls._get_mixins_(cls, bases)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700408 classdict = metacls.__prepare__(class_name, bases)
409
410 # special processing needed for names?
411 if isinstance(names, str):
412 names = names.replace(',', ' ').split()
Dong-hee Nadcc8ce42017-06-22 01:52:32 +0900413 if isinstance(names, (tuple, list)) and names and isinstance(names[0], str):
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700414 original_names, names = names, []
Ethan Furmanc16595e2016-09-10 23:36:59 -0700415 last_values = []
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700416 for count, name in enumerate(original_names):
Ethan Furmanc16595e2016-09-10 23:36:59 -0700417 value = first_enum._generate_next_value_(name, start, count, last_values[:])
418 last_values.append(value)
419 names.append((name, value))
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700420
421 # Here, names is either an iterable of (name, value) or a mapping.
422 for item in names:
423 if isinstance(item, str):
424 member_name, member_value = item, names[item]
425 else:
426 member_name, member_value = item
427 classdict[member_name] = member_value
428 enum_class = metacls.__new__(metacls, class_name, bases, classdict)
429
430 # TODO: replace the frame hack if a blessed way to know the calling
431 # module is ever developed
432 if module is None:
433 try:
434 module = sys._getframe(2).f_globals['__name__']
Pablo Galindo293dd232019-11-19 21:34:03 +0000435 except (AttributeError, ValueError, KeyError):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700436 pass
437 if module is None:
438 _make_class_unpicklable(enum_class)
439 else:
440 enum_class.__module__ = module
Ethan Furmanca1b7942014-02-08 11:36:27 -0800441 if qualname is not None:
442 enum_class.__qualname__ = qualname
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700443
444 return enum_class
445
orlnub1230fb9fad2018-09-12 20:28:53 +0300446 def _convert_(cls, name, module, filter, source=None):
447 """
448 Create a new Enum subclass that replaces a collection of global constants
449 """
450 # convert all constants from source (or module) that pass filter() to
451 # a new Enum called name, and export the enum and its members back to
452 # module;
453 # also, replace the __reduce_ex__ method so unpickling works in
454 # previous Python versions
455 module_globals = vars(sys.modules[module])
456 if source:
457 source = vars(source)
458 else:
459 source = module_globals
460 # _value2member_map_ is populated in the same order every time
461 # for a consistent reverse mapping of number to name when there
462 # are multiple names for the same number.
463 members = [
464 (name, value)
465 for name, value in source.items()
466 if filter(name)]
467 try:
468 # sort by value
469 members.sort(key=lambda t: (t[1], t[0]))
470 except TypeError:
471 # unless some values aren't comparable, in which case sort by name
472 members.sort(key=lambda t: t[0])
473 cls = cls(name, members, module=module)
474 cls.__reduce_ex__ = _reduce_ex_by_name
475 module_globals.update(cls.__members__)
476 module_globals[name] = cls
477 return cls
478
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700479 @staticmethod
Ethan Furman3064dbf2020-09-16 07:11:57 -0700480 def _check_for_existing_members(class_name, bases):
481 for chain in bases:
482 for base in chain.__mro__:
483 if issubclass(base, Enum) and base._member_names_:
484 raise TypeError("%s: cannot extend enumeration %r" % (class_name, base.__name__))
485
486 @staticmethod
487 def _get_mixins_(class_name, bases):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700488 """Returns the type for creating enum members, and the first inherited
489 enum class.
490
491 bases: the tuple of bases that was given to __new__
492
493 """
494 if not bases:
495 return object, Enum
496
Ethan Furman5bdab642018-09-21 19:03:09 -0700497 def _find_data_type(bases):
Ethan Furmanbff01f32020-09-15 15:56:26 -0700498 data_types = []
Ethan Furman5bdab642018-09-21 19:03:09 -0700499 for chain in bases:
Ethan Furmanbff01f32020-09-15 15:56:26 -0700500 candidate = None
Ethan Furman5bdab642018-09-21 19:03:09 -0700501 for base in chain.__mro__:
502 if base is object:
503 continue
504 elif '__new__' in base.__dict__:
Ethan Furmancd453852018-10-05 23:29:36 -0700505 if issubclass(base, Enum):
Ethan Furman5bdab642018-09-21 19:03:09 -0700506 continue
Ethan Furmanbff01f32020-09-15 15:56:26 -0700507 data_types.append(candidate or base)
508 break
509 elif not issubclass(base, Enum):
510 candidate = base
511 if len(data_types) > 1:
Ethan Furman3064dbf2020-09-16 07:11:57 -0700512 raise TypeError('%r: too many data types: %r' % (class_name, data_types))
Ethan Furmanbff01f32020-09-15 15:56:26 -0700513 elif data_types:
514 return data_types[0]
515 else:
516 return None
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700517
Ethan Furman5bdab642018-09-21 19:03:09 -0700518 # ensure final parent class is an Enum derivative, find any concrete
519 # data type, and check that Enum has no members
520 first_enum = bases[-1]
521 if not issubclass(first_enum, Enum):
522 raise TypeError("new enumerations should be created as "
523 "`EnumName([mixin_type, ...] [data_type,] enum_type)`")
524 member_type = _find_data_type(bases) or object
525 if first_enum._member_names_:
526 raise TypeError("Cannot extend enumerations")
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700527 return member_type, first_enum
528
529 @staticmethod
530 def _find_new_(classdict, member_type, first_enum):
531 """Returns the __new__ to be used for creating the enum members.
532
533 classdict: the class dictionary given to __new__
534 member_type: the data type whose __new__ will be used by default
535 first_enum: enumeration to check for an overriding __new__
536
537 """
538 # now find the correct __new__, checking to see of one was defined
539 # by the user; also check earlier enum classes in case a __new__ was
540 # saved as __new_member__
541 __new__ = classdict.get('__new__', None)
542
543 # should __new__ be saved as __new_member__ later?
544 save_new = __new__ is not None
545
546 if __new__ is None:
547 # check all possibles for __new_member__ before falling back to
548 # __new__
549 for method in ('__new_member__', '__new__'):
550 for possible in (member_type, first_enum):
551 target = getattr(possible, method, None)
552 if target not in {
553 None,
554 None.__new__,
555 object.__new__,
556 Enum.__new__,
557 }:
558 __new__ = target
559 break
560 if __new__ is not None:
561 break
562 else:
563 __new__ = object.__new__
564
565 # if a non-object.__new__ is used then whatever value/tuple was
566 # assigned to the enum member name will be passed to __new__ and to the
567 # new enum member's __init__
568 if __new__ is object.__new__:
569 use_args = False
570 else:
571 use_args = True
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700572 return __new__, save_new, use_args
573
574
575class Enum(metaclass=EnumMeta):
576 """Generic enumeration.
577
578 Derive from this class to define new enumerations.
579
580 """
581 def __new__(cls, value):
582 # all enum instances are actually created during class construction
583 # without calling this method; this method is called by the metaclass'
584 # __call__ (i.e. Color(3) ), and by pickle
585 if type(value) is cls:
Ethan Furman23bb6f42016-11-21 09:22:05 -0800586 # For lookups like Color(Color.RED)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700587 return value
588 # by-value search for a matching enum member
589 # see if it's in the reverse mapping (for hashable values)
Ethan Furman2aa27322013-07-19 19:35:56 -0700590 try:
Andrew Svetlov34ae04f2018-12-26 20:45:33 +0200591 return cls._value2member_map_[value]
592 except KeyError:
593 # Not found, no need to do long O(n) search
594 pass
Ethan Furman2aa27322013-07-19 19:35:56 -0700595 except TypeError:
596 # not there, now do long search -- O(n) behavior
Ethan Furman520ad572013-07-19 19:47:21 -0700597 for member in cls._member_map_.values():
Ethan Furman0081f232014-09-16 17:31:23 -0700598 if member._value_ == value:
Ethan Furman2aa27322013-07-19 19:35:56 -0700599 return member
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700600 # still not found -- try _missing_ hook
Ethan Furman019f0a02018-09-12 11:43:34 -0700601 try:
602 exc = None
603 result = cls._missing_(value)
604 except Exception as e:
605 exc = e
606 result = None
607 if isinstance(result, cls):
608 return result
609 else:
Walter Dörwald323842c2019-07-18 20:37:13 +0200610 ve_exc = ValueError("%r is not a valid %s" % (value, cls.__qualname__))
Ethan Furman019f0a02018-09-12 11:43:34 -0700611 if result is None and exc is None:
612 raise ve_exc
613 elif exc is None:
614 exc = TypeError(
615 'error in %s._missing_: returned %r instead of None or a valid member'
616 % (cls.__name__, result)
617 )
618 exc.__context__ = ve_exc
619 raise exc
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700620
Ethan Furmanc16595e2016-09-10 23:36:59 -0700621 def _generate_next_value_(name, start, count, last_values):
622 for last_value in reversed(last_values):
623 try:
624 return last_value + 1
625 except TypeError:
626 pass
627 else:
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700628 return start
Ethan Furmanc16595e2016-09-10 23:36:59 -0700629
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700630 @classmethod
631 def _missing_(cls, value):
Ethan Furmanc95ad7a2020-09-16 10:26:50 -0700632 return None
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700633
634 def __repr__(self):
635 return "<%s.%s: %r>" % (
Ethan Furman520ad572013-07-19 19:47:21 -0700636 self.__class__.__name__, self._name_, self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700637
638 def __str__(self):
Ethan Furman520ad572013-07-19 19:47:21 -0700639 return "%s.%s" % (self.__class__.__name__, self._name_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700640
Ethan Furman388a3922013-08-12 06:51:41 -0700641 def __dir__(self):
Ethan Furman0ae550b2014-10-14 08:58:32 -0700642 added_behavior = [
643 m
644 for cls in self.__class__.mro()
645 for m in cls.__dict__
Ethan Furman354ecf12015-03-11 08:43:12 -0700646 if m[0] != '_' and m not in self._member_map_
Angelin BOOZ68526fe2020-09-21 15:11:06 +0200647 ] + [m for m in self.__dict__ if m[0] != '_']
Ethan Furmanec5f8eb2014-10-21 13:40:35 -0700648 return (['__class__', '__doc__', '__module__'] + added_behavior)
Ethan Furman388a3922013-08-12 06:51:41 -0700649
Ethan Furmanec15a822013-08-31 19:17:41 -0700650 def __format__(self, format_spec):
651 # mixed-in Enums should use the mixed-in type's __format__, otherwise
652 # we can get strange results with the Enum name showing up instead of
653 # the value
654
thatneat2f19e822019-07-04 11:28:37 -0700655 # pure Enum branch, or branch with __str__ explicitly overridden
656 str_overridden = type(self).__str__ != Enum.__str__
657 if self._member_type_ is object or str_overridden:
Ethan Furmanec15a822013-08-31 19:17:41 -0700658 cls = str
659 val = str(self)
660 # mix-in branch
661 else:
662 cls = self._member_type_
Ethan Furman0081f232014-09-16 17:31:23 -0700663 val = self._value_
Ethan Furmanec15a822013-08-31 19:17:41 -0700664 return cls.__format__(val, format_spec)
665
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700666 def __hash__(self):
Ethan Furman520ad572013-07-19 19:47:21 -0700667 return hash(self._name_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700668
Ethan Furmanca1b7942014-02-08 11:36:27 -0800669 def __reduce_ex__(self, proto):
Ethan Furmandc870522014-02-18 12:37:12 -0800670 return self.__class__, (self._value_, )
Ethan Furmanca1b7942014-02-08 11:36:27 -0800671
Ethan Furman33918c12013-09-27 23:02:02 -0700672 # DynamicClassAttribute is used to provide access to the `name` and
673 # `value` properties of enum members while keeping some measure of
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700674 # protection from modification, while still allowing for an enumeration
675 # to have members named `name` and `value`. This works because enumeration
676 # members are not set directly on the enum class -- __getattr__ is
677 # used to look them up.
678
Ethan Furmane03ea372013-09-25 07:14:41 -0700679 @DynamicClassAttribute
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700680 def name(self):
Ethan Furmanc850f342013-09-15 16:59:35 -0700681 """The name of the Enum member."""
Ethan Furman520ad572013-07-19 19:47:21 -0700682 return self._name_
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700683
Ethan Furmane03ea372013-09-25 07:14:41 -0700684 @DynamicClassAttribute
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700685 def value(self):
Ethan Furmanc850f342013-09-15 16:59:35 -0700686 """The value of the Enum member."""
Ethan Furman520ad572013-07-19 19:47:21 -0700687 return self._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700688
689
690class IntEnum(int, Enum):
Ethan Furman0063ff42020-09-21 17:23:13 -0700691 """
692 Enum where members are also (and must be) ints
693 """
694
695
696class StrEnum(str, Enum):
697 """
698 Enum where members are also (and must be) strings
699 """
700
701 def __new__(cls, *values):
702 if len(values) > 3:
703 raise TypeError('too many arguments for str(): %r' % (values, ))
704 if len(values) == 1:
705 # it must be a string
706 if not isinstance(values[0], str):
707 raise TypeError('%r is not a string' % (values[0], ))
708 if len(values) > 1:
709 # check that encoding argument is a string
710 if not isinstance(values[1], str):
711 raise TypeError('encoding must be a string, not %r' % (values[1], ))
712 if len(values) > 2:
713 # check that errors argument is a string
714 if not isinstance(values[2], str):
715 raise TypeError('errors must be a string, not %r' % (values[2], ))
716 value = str(*values)
717 member = str.__new__(cls, value)
718 member._value_ = value
719 return member
Ethan Furmanf24bb352013-07-18 17:05:39 -0700720
Ethan Furmand986d162020-09-22 13:00:07 -0700721 __str__ = str.__str__
722
Ethan Furmanf24bb352013-07-18 17:05:39 -0700723
Ethan Furman24e837f2015-03-18 17:27:57 -0700724def _reduce_ex_by_name(self, proto):
725 return self.name
726
Ethan Furman65a5a472016-09-01 23:55:19 -0700727class Flag(Enum):
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700728 """Support for flags"""
Ethan Furmanc16595e2016-09-10 23:36:59 -0700729
730 def _generate_next_value_(name, start, count, last_values):
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700731 """
732 Generate the next value when not given.
733
734 name: the name of the member
HongWeipengbb16fb22019-09-21 13:22:54 +0800735 start: the initial start value or None
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700736 count: the number of existing members
737 last_value: the last value assigned or None
738 """
739 if not count:
740 return start if start is not None else 1
Ethan Furmanc16595e2016-09-10 23:36:59 -0700741 for last_value in reversed(last_values):
742 try:
743 high_bit = _high_bit(last_value)
744 break
Ethan Furman3515dcc2016-09-18 13:15:41 -0700745 except Exception:
Ethan Furmanc16595e2016-09-10 23:36:59 -0700746 raise TypeError('Invalid Flag value: %r' % last_value) from None
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700747 return 2 ** (high_bit+1)
748
749 @classmethod
750 def _missing_(cls, value):
751 original_value = value
752 if value < 0:
753 value = ~value
754 possible_member = cls._create_pseudo_member_(value)
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700755 if original_value < 0:
756 possible_member = ~possible_member
757 return possible_member
758
759 @classmethod
760 def _create_pseudo_member_(cls, value):
Ethan Furman3515dcc2016-09-18 13:15:41 -0700761 """
762 Create a composite member iff value contains only members.
763 """
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700764 pseudo_member = cls._value2member_map_.get(value, None)
765 if pseudo_member is None:
Ethan Furman3515dcc2016-09-18 13:15:41 -0700766 # verify all bits are accounted for
767 _, extra_flags = _decompose(cls, value)
768 if extra_flags:
Walter Dörwald323842c2019-07-18 20:37:13 +0200769 raise ValueError("%r is not a valid %s" % (value, cls.__qualname__))
Ethan Furman3515dcc2016-09-18 13:15:41 -0700770 # construct a singleton enum pseudo-member
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700771 pseudo_member = object.__new__(cls)
772 pseudo_member._name_ = None
773 pseudo_member._value_ = value
Ethan Furman28cf6632017-01-24 12:12:06 -0800774 # use setdefault in case another thread already created a composite
775 # with this value
776 pseudo_member = cls._value2member_map_.setdefault(value, pseudo_member)
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700777 return pseudo_member
778
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700779 def __contains__(self, other):
780 if not isinstance(other, self.__class__):
Rahul Jha94306522018-09-10 23:51:04 +0530781 raise TypeError(
782 "unsupported operand type(s) for 'in': '%s' and '%s'" % (
783 type(other).__qualname__, self.__class__.__qualname__))
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700784 return other._value_ & self._value_ == other._value_
785
Ethan Furman7219e272020-09-16 13:01:00 -0700786 def __iter__(self):
787 members, extra_flags = _decompose(self.__class__, self.value)
788 return (m for m in members if m._value_ != 0)
789
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700790 def __repr__(self):
791 cls = self.__class__
792 if self._name_ is not None:
793 return '<%s.%s: %r>' % (cls.__name__, self._name_, self._value_)
Ethan Furman3515dcc2016-09-18 13:15:41 -0700794 members, uncovered = _decompose(cls, self._value_)
Ethan Furman27682d22016-09-04 11:39:01 -0700795 return '<%s.%s: %r>' % (
796 cls.__name__,
797 '|'.join([str(m._name_ or m._value_) for m in members]),
798 self._value_,
799 )
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700800
801 def __str__(self):
802 cls = self.__class__
803 if self._name_ is not None:
804 return '%s.%s' % (cls.__name__, self._name_)
Ethan Furman3515dcc2016-09-18 13:15:41 -0700805 members, uncovered = _decompose(cls, self._value_)
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700806 if len(members) == 1 and members[0]._name_ is None:
807 return '%s.%r' % (cls.__name__, members[0]._value_)
808 else:
809 return '%s.%s' % (
810 cls.__name__,
811 '|'.join([str(m._name_ or m._value_) for m in members]),
812 )
813
Ethan Furman25d94bb2016-09-02 16:32:32 -0700814 def __bool__(self):
815 return bool(self._value_)
816
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700817 def __or__(self, other):
818 if not isinstance(other, self.__class__):
819 return NotImplemented
820 return self.__class__(self._value_ | other._value_)
821
822 def __and__(self, other):
823 if not isinstance(other, self.__class__):
824 return NotImplemented
825 return self.__class__(self._value_ & other._value_)
826
827 def __xor__(self, other):
828 if not isinstance(other, self.__class__):
829 return NotImplemented
830 return self.__class__(self._value_ ^ other._value_)
831
832 def __invert__(self):
Ethan Furman3515dcc2016-09-18 13:15:41 -0700833 members, uncovered = _decompose(self.__class__, self._value_)
Serhiy Storchaka81108372017-09-26 00:55:55 +0300834 inverted = self.__class__(0)
835 for m in self.__class__:
836 if m not in members and not (m._value_ & self._value_):
837 inverted = inverted | m
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700838 return self.__class__(inverted)
839
840
Ethan Furman65a5a472016-09-01 23:55:19 -0700841class IntFlag(int, Flag):
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700842 """Support for integer-based Flags"""
843
844 @classmethod
Ethan Furman3515dcc2016-09-18 13:15:41 -0700845 def _missing_(cls, value):
846 if not isinstance(value, int):
Walter Dörwald323842c2019-07-18 20:37:13 +0200847 raise ValueError("%r is not a valid %s" % (value, cls.__qualname__))
Ethan Furman3515dcc2016-09-18 13:15:41 -0700848 new_member = cls._create_pseudo_member_(value)
849 return new_member
850
851 @classmethod
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700852 def _create_pseudo_member_(cls, value):
853 pseudo_member = cls._value2member_map_.get(value, None)
854 if pseudo_member is None:
Ethan Furman3515dcc2016-09-18 13:15:41 -0700855 need_to_create = [value]
856 # get unaccounted for bits
857 _, extra_flags = _decompose(cls, value)
858 # timer = 10
859 while extra_flags:
860 # timer -= 1
861 bit = _high_bit(extra_flags)
862 flag_value = 2 ** bit
863 if (flag_value not in cls._value2member_map_ and
864 flag_value not in need_to_create
865 ):
866 need_to_create.append(flag_value)
867 if extra_flags == -flag_value:
868 extra_flags = 0
869 else:
870 extra_flags ^= flag_value
871 for value in reversed(need_to_create):
872 # construct singleton pseudo-members
873 pseudo_member = int.__new__(cls, value)
874 pseudo_member._name_ = None
875 pseudo_member._value_ = value
Ethan Furman28cf6632017-01-24 12:12:06 -0800876 # use setdefault in case another thread already created a composite
877 # with this value
878 pseudo_member = cls._value2member_map_.setdefault(value, pseudo_member)
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700879 return pseudo_member
880
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700881 def __or__(self, other):
882 if not isinstance(other, (self.__class__, int)):
883 return NotImplemented
Ethan Furman3515dcc2016-09-18 13:15:41 -0700884 result = self.__class__(self._value_ | self.__class__(other)._value_)
885 return result
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700886
887 def __and__(self, other):
888 if not isinstance(other, (self.__class__, int)):
889 return NotImplemented
890 return self.__class__(self._value_ & self.__class__(other)._value_)
891
892 def __xor__(self, other):
893 if not isinstance(other, (self.__class__, int)):
894 return NotImplemented
895 return self.__class__(self._value_ ^ self.__class__(other)._value_)
896
897 __ror__ = __or__
898 __rand__ = __and__
899 __rxor__ = __xor__
900
901 def __invert__(self):
Ethan Furman3515dcc2016-09-18 13:15:41 -0700902 result = self.__class__(~self._value_)
903 return result
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700904
905
906def _high_bit(value):
Ethan Furman04439532016-09-02 15:50:21 -0700907 """returns index of highest bit, or -1 if value is zero or negative"""
Ethan Furman3515dcc2016-09-18 13:15:41 -0700908 return value.bit_length() - 1
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700909
Ethan Furmanf24bb352013-07-18 17:05:39 -0700910def unique(enumeration):
911 """Class decorator for enumerations ensuring unique member values."""
912 duplicates = []
913 for name, member in enumeration.__members__.items():
914 if name != member.name:
915 duplicates.append((name, member.name))
916 if duplicates:
917 alias_details = ', '.join(
918 ["%s -> %s" % (alias, name) for (alias, name) in duplicates])
919 raise ValueError('duplicate values found in %r: %s' %
920 (enumeration, alias_details))
921 return enumeration
Ethan Furman3515dcc2016-09-18 13:15:41 -0700922
923def _decompose(flag, value):
924 """Extract all members from the value."""
925 # _decompose is only called if the value is not named
926 not_covered = value
927 negative = value < 0
Ethan Furman3515dcc2016-09-18 13:15:41 -0700928 members = []
HongWeipeng0b41a922019-11-27 06:36:02 +0800929 for member in flag:
930 member_value = member.value
Ethan Furman3515dcc2016-09-18 13:15:41 -0700931 if member_value and member_value & value == member_value:
932 members.append(member)
933 not_covered &= ~member_value
HongWeipeng0b41a922019-11-27 06:36:02 +0800934 if not negative:
935 tmp = not_covered
936 while tmp:
937 flag_value = 2 ** _high_bit(tmp)
938 if flag_value in flag._value2member_map_:
939 members.append(flag._value2member_map_[flag_value])
940 not_covered &= ~flag_value
941 tmp &= ~flag_value
Ethan Furman3515dcc2016-09-18 13:15:41 -0700942 if not members and value in flag._value2member_map_:
943 members.append(flag._value2member_map_[value])
944 members.sort(key=lambda m: m._value_, reverse=True)
945 if len(members) > 1 and members[0].value == value:
946 # we have the breakdown, don't need the value member itself
947 members.pop(0)
948 return members, not_covered