blob: 54633d8a7fbb0145fd8e69ad2b1e49b8e54f4563 [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 Furman7aaeb2a2021-01-25 14:26:19 -08003from builtins import property as _bltin_property, bin as _bltin_bin
Ethan Furman6b3d64a2013-06-14 16:55:46 -07004
Ethan Furmane5754ab2015-09-17 22:03:52 -07005
Ethan Furmanc16595e2016-09-10 23:36:59 -07006__all__ = [
Ethan Furmanb7751062021-03-30 21:17:26 -07007 'EnumType', 'EnumMeta',
Ethan Furman0063ff42020-09-21 17:23:13 -07008 'Enum', 'IntEnum', 'StrEnum', 'Flag', 'IntFlag',
Ethan Furman74964862021-06-10 07:24:20 -07009 'auto', 'unique', 'property', 'verify',
Ethan Furman7aaeb2a2021-01-25 14:26:19 -080010 'FlagBoundary', 'STRICT', 'CONFORM', 'EJECT', 'KEEP',
Ethan Furmanb7751062021-03-30 21:17:26 -070011 'global_flag_repr', 'global_enum_repr', 'global_enum',
Ethan Furman74964862021-06-10 07:24:20 -070012 'EnumCheck', 'CONTINUOUS', 'NAMED_FLAGS', 'UNIQUE',
Ethan Furmanc16595e2016-09-10 23:36:59 -070013 ]
Ethan Furman6b3d64a2013-06-14 16:55:46 -070014
15
Ethan Furman7aaeb2a2021-01-25 14:26:19 -080016# Dummy value for Enum and Flag as there are explicit checks for them
17# before they have been created.
Ethan Furmanb7751062021-03-30 21:17:26 -070018# This is also why there are checks in EnumType like `if Enum is not None`
Ethan Furman7aaeb2a2021-01-25 14:26:19 -080019Enum = Flag = EJECT = None
20
Ethan Furman101e0742013-09-15 12:34:36 -070021def _is_descriptor(obj):
Ethan Furman6d3dfee2020-12-08 12:26:56 -080022 """
23 Returns True if obj is a descriptor, False otherwise.
24 """
Ethan Furman101e0742013-09-15 12:34:36 -070025 return (
26 hasattr(obj, '__get__') or
27 hasattr(obj, '__set__') or
Ethan Furman6d3dfee2020-12-08 12:26:56 -080028 hasattr(obj, '__delete__')
29 )
Ethan Furman101e0742013-09-15 12:34:36 -070030
Ethan Furman6b3d64a2013-06-14 16:55:46 -070031def _is_dunder(name):
Ethan Furman6d3dfee2020-12-08 12:26:56 -080032 """
33 Returns True if a __dunder__ name, False otherwise.
34 """
35 return (
36 len(name) > 4 and
Brennan D Baraban8b914d22019-03-03 14:09:11 -080037 name[:2] == name[-2:] == '__' and
38 name[2] != '_' and
Ethan Furman6d3dfee2020-12-08 12:26:56 -080039 name[-3] != '_'
40 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -070041
42def _is_sunder(name):
Ethan Furman6d3dfee2020-12-08 12:26:56 -080043 """
44 Returns True if a _sunder_ name, False otherwise.
45 """
46 return (
47 len(name) > 2 and
Brennan D Baraban8b914d22019-03-03 14:09:11 -080048 name[0] == name[-1] == '_' and
Ethan Furman6b3d64a2013-06-14 16:55:46 -070049 name[1:2] != '_' and
Ethan Furman6d3dfee2020-12-08 12:26:56 -080050 name[-2:-1] != '_'
51 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -070052
Ethan Furman7cf0aad2020-12-09 17:12:11 -080053def _is_private(cls_name, name):
54 # do not use `re` as `re` imports `enum`
55 pattern = '_%s__' % (cls_name, )
Ethan Furmanec099732021-04-15 06:58:33 -070056 pat_len = len(pattern)
Ethan Furman7cf0aad2020-12-09 17:12:11 -080057 if (
Ethan Furmanec099732021-04-15 06:58:33 -070058 len(name) > pat_len
Ethan Furman7cf0aad2020-12-09 17:12:11 -080059 and name.startswith(pattern)
Ethan Furmanec099732021-04-15 06:58:33 -070060 and name[pat_len:pat_len+1] != ['_']
Ethan Furman7cf0aad2020-12-09 17:12:11 -080061 and (name[-1] != '_' or name[-2] != '_')
62 ):
63 return True
64 else:
65 return False
66
Ethan Furman7aaeb2a2021-01-25 14:26:19 -080067def _is_single_bit(num):
68 """
69 True if only one bit set in num (should be an int)
70 """
71 if num == 0:
72 return False
73 num &= num - 1
74 return num == 0
75
Ethan Furmanc314e602021-01-12 23:47:57 -080076def _make_class_unpicklable(obj):
Ethan Furman6d3dfee2020-12-08 12:26:56 -080077 """
Ethan Furmanc314e602021-01-12 23:47:57 -080078 Make the given obj un-picklable.
79
80 obj should be either a dictionary, on an Enum
Ethan Furman6d3dfee2020-12-08 12:26:56 -080081 """
Ethan Furmanca1b7942014-02-08 11:36:27 -080082 def _break_on_call_reduce(self, proto):
Ethan Furman6b3d64a2013-06-14 16:55:46 -070083 raise TypeError('%r cannot be pickled' % self)
Ethan Furmanc314e602021-01-12 23:47:57 -080084 if isinstance(obj, dict):
85 obj['__reduce_ex__'] = _break_on_call_reduce
86 obj['__module__'] = '<unknown>'
87 else:
88 setattr(obj, '__reduce_ex__', _break_on_call_reduce)
89 setattr(obj, '__module__', '<unknown>')
Ethan Furman6b3d64a2013-06-14 16:55:46 -070090
Ethan Furman7aaeb2a2021-01-25 14:26:19 -080091def _iter_bits_lsb(num):
Ethan Furman74964862021-06-10 07:24:20 -070092 # num must be an integer
93 if isinstance(num, Enum):
94 num = num.value
Ethan Furman7aaeb2a2021-01-25 14:26:19 -080095 while num:
96 b = num & (~num + 1)
97 yield b
98 num ^= b
99
100def bin(num, max_bits=None):
101 """
102 Like built-in bin(), except negative values are represented in
103 twos-compliment, and the leading bit always indicates sign
104 (0=positive, 1=negative).
105
106 >>> bin(10)
107 '0b0 1010'
108 >>> bin(~10) # ~10 is -11
109 '0b1 0101'
110 """
111
112 ceiling = 2 ** (num).bit_length()
113 if num >= 0:
114 s = _bltin_bin(num + ceiling).replace('1', '0', 1)
115 else:
116 s = _bltin_bin(~num ^ (ceiling - 1) + ceiling)
117 sign = s[:3]
118 digits = s[3:]
119 if max_bits is not None:
120 if len(digits) < max_bits:
121 digits = (sign[-1] * max_bits + digits)[-max_bits:]
122 return "%s %s" % (sign, digits)
123
124
Ethan Furman3515dcc2016-09-18 13:15:41 -0700125_auto_null = object()
Ethan Furmanc16595e2016-09-10 23:36:59 -0700126class auto:
127 """
128 Instances are replaced with an appropriate value in Enum class suites.
129 """
Ethan Furman3515dcc2016-09-18 13:15:41 -0700130 value = _auto_null
Ethan Furmanc16595e2016-09-10 23:36:59 -0700131
Ethan Furmanc314e602021-01-12 23:47:57 -0800132class property(DynamicClassAttribute):
133 """
134 This is a descriptor, used to define attributes that act differently
135 when accessed through an enum member and through an enum class.
136 Instance access is the same as property(), but access to an attribute
137 through the enum class will instead look in the class' _member_map_ for
138 a corresponding enum member.
139 """
140
141 def __get__(self, instance, ownerclass=None):
142 if instance is None:
143 try:
144 return ownerclass._member_map_[self.name]
145 except KeyError:
Ethan Furman7aaeb2a2021-01-25 14:26:19 -0800146 raise AttributeError(
Ethan Furmand65b9032021-02-08 17:32:38 -0800147 '%s: no class attribute %r' % (ownerclass.__name__, self.name)
Ethan Furman7aaeb2a2021-01-25 14:26:19 -0800148 )
Ethan Furmanc314e602021-01-12 23:47:57 -0800149 else:
150 if self.fget is None:
Ethan Furmand65b9032021-02-08 17:32:38 -0800151 # check for member
152 if self.name in ownerclass._member_map_:
153 import warnings
154 warnings.warn(
155 "accessing one member from another is not supported, "
Ethan Furman44e580f2021-03-03 09:54:30 -0800156 " and will be disabled in 3.12",
Ethan Furmand65b9032021-02-08 17:32:38 -0800157 DeprecationWarning,
158 stacklevel=2,
159 )
160 return ownerclass._member_map_[self.name]
Ethan Furman7aaeb2a2021-01-25 14:26:19 -0800161 raise AttributeError(
Ethan Furmand65b9032021-02-08 17:32:38 -0800162 '%s: no instance attribute %r' % (ownerclass.__name__, self.name)
Ethan Furman7aaeb2a2021-01-25 14:26:19 -0800163 )
Ethan Furmanc314e602021-01-12 23:47:57 -0800164 else:
165 return self.fget(instance)
166
167 def __set__(self, instance, value):
168 if self.fset is None:
Ethan Furman7aaeb2a2021-01-25 14:26:19 -0800169 raise AttributeError(
Ethan Furmand65b9032021-02-08 17:32:38 -0800170 "%s: cannot set instance attribute %r" % (self.clsname, self.name)
Ethan Furman7aaeb2a2021-01-25 14:26:19 -0800171 )
Ethan Furmanc314e602021-01-12 23:47:57 -0800172 else:
173 return self.fset(instance, value)
174
175 def __delete__(self, instance):
176 if self.fdel is None:
Ethan Furman7aaeb2a2021-01-25 14:26:19 -0800177 raise AttributeError(
Ethan Furmand65b9032021-02-08 17:32:38 -0800178 "%s: cannot delete instance attribute %r" % (self.clsname, self.name)
Ethan Furman7aaeb2a2021-01-25 14:26:19 -0800179 )
Ethan Furmanc314e602021-01-12 23:47:57 -0800180 else:
181 return self.fdel(instance)
182
183 def __set_name__(self, ownerclass, name):
184 self.name = name
185 self.clsname = ownerclass.__name__
186
187
188class _proto_member:
189 """
190 intermediate step for enum members between class execution and final creation
191 """
192
193 def __init__(self, value):
194 self.value = value
195
196 def __set_name__(self, enum_class, member_name):
197 """
198 convert each quasi-member into an instance of the new enum class
199 """
200 # first step: remove ourself from enum_class
201 delattr(enum_class, member_name)
202 # second step: create member based on enum_class
203 value = self.value
204 if not isinstance(value, tuple):
205 args = (value, )
206 else:
207 args = value
208 if enum_class._member_type_ is tuple: # special case for tuple enums
209 args = (args, ) # wrap it one more time
210 if not enum_class._use_args_:
211 enum_member = enum_class._new_member_(enum_class)
212 if not hasattr(enum_member, '_value_'):
213 enum_member._value_ = value
214 else:
215 enum_member = enum_class._new_member_(enum_class, *args)
216 if not hasattr(enum_member, '_value_'):
217 if enum_class._member_type_ is object:
218 enum_member._value_ = value
219 else:
Ethan Furman7aaeb2a2021-01-25 14:26:19 -0800220 try:
221 enum_member._value_ = enum_class._member_type_(*args)
222 except Exception as exc:
223 raise TypeError(
224 '_value_ not set in __new__, unable to create it'
225 ) from None
Ethan Furmanc314e602021-01-12 23:47:57 -0800226 value = enum_member._value_
227 enum_member._name_ = member_name
228 enum_member.__objclass__ = enum_class
229 enum_member.__init__(*args)
Ethan Furman7aaeb2a2021-01-25 14:26:19 -0800230 enum_member._sort_order_ = len(enum_class._member_names_)
Ethan Furmanc314e602021-01-12 23:47:57 -0800231 # If another member with the same value was already defined, the
232 # new member becomes an alias to the existing one.
233 for name, canonical_member in enum_class._member_map_.items():
234 if canonical_member._value_ == enum_member._value_:
235 enum_member = canonical_member
236 break
237 else:
Ethan Furman7aaeb2a2021-01-25 14:26:19 -0800238 # this could still be an alias if the value is multi-bit and the
239 # class is a flag class
240 if (
241 Flag is None
242 or not issubclass(enum_class, Flag)
243 ):
244 # no other instances found, record this member in _member_names_
245 enum_class._member_names_.append(member_name)
246 elif (
247 Flag is not None
248 and issubclass(enum_class, Flag)
249 and _is_single_bit(value)
250 ):
251 # no other instances found, record this member in _member_names_
252 enum_class._member_names_.append(member_name)
Ethan Furmanc314e602021-01-12 23:47:57 -0800253 # get redirect in place before adding to _member_map_
254 # but check for other instances in parent classes first
255 need_override = False
256 descriptor = None
257 for base in enum_class.__mro__[1:]:
258 descriptor = base.__dict__.get(member_name)
259 if descriptor is not None:
260 if isinstance(descriptor, (property, DynamicClassAttribute)):
261 break
262 else:
263 need_override = True
264 # keep looking for an enum.property
265 if descriptor and not need_override:
266 # previous enum.property found, no further action needed
267 pass
268 else:
269 redirect = property()
270 redirect.__set_name__(enum_class, member_name)
271 if descriptor and need_override:
272 # previous enum.property found, but some other inherited attribute
273 # is in the way; copy fget, fset, fdel to this one
274 redirect.fget = descriptor.fget
275 redirect.fset = descriptor.fset
276 redirect.fdel = descriptor.fdel
277 setattr(enum_class, member_name, redirect)
278 # now add to _member_map_ (even aliases)
279 enum_class._member_map_[member_name] = enum_member
280 try:
281 # This may fail if value is not hashable. We can't add the value
282 # to the map, and by-value lookups for this value will be
283 # linear.
Ethan Furman7aaeb2a2021-01-25 14:26:19 -0800284 enum_class._value2member_map_.setdefault(value, enum_member)
Ethan Furmanc314e602021-01-12 23:47:57 -0800285 except TypeError:
Ethan Furman6bd92882021-04-27 13:05:08 -0700286 # keep track of the value in a list so containment checks are quick
287 enum_class._unhashable_values_.append(value)
Ethan Furmanc314e602021-01-12 23:47:57 -0800288
Ethan Furman101e0742013-09-15 12:34:36 -0700289
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700290class _EnumDict(dict):
Ethan Furman6d3dfee2020-12-08 12:26:56 -0800291 """
292 Track enum member order and ensure member names are not reused.
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700293
Ethan Furmanb7751062021-03-30 21:17:26 -0700294 EnumType will use the names found in self._member_names as the
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700295 enumeration member names.
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700296 """
297 def __init__(self):
298 super().__init__()
299 self._member_names = []
Ethan Furmanc16595e2016-09-10 23:36:59 -0700300 self._last_values = []
Ethan Furmana4b1bb42018-01-22 07:56:37 -0800301 self._ignore = []
Ethan Onstottd9a43e22020-04-28 13:20:55 -0400302 self._auto_called = False
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700303
304 def __setitem__(self, key, value):
Ethan Furman6d3dfee2020-12-08 12:26:56 -0800305 """
306 Changes anything not dundered or not a descriptor.
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700307
308 If an enum member name is used twice, an error is raised; duplicate
309 values are not checked for.
310
311 Single underscore (sunder) names are reserved.
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700312 """
Ethan Furman7cf0aad2020-12-09 17:12:11 -0800313 if _is_private(self._cls_name, key):
314 # do nothing, name will be a normal attribute
315 pass
316 elif _is_sunder(key):
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700317 if key not in (
Ethan Furman0dca5eb2021-04-15 06:49:54 -0700318 '_order_',
Ethan Furmana4b1bb42018-01-22 07:56:37 -0800319 '_generate_next_value_', '_missing_', '_ignore_',
Ethan Furman7aaeb2a2021-01-25 14:26:19 -0800320 '_iter_member_', '_iter_member_by_value_', '_iter_member_by_def_',
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700321 ):
Ethan Furman6d3dfee2020-12-08 12:26:56 -0800322 raise ValueError(
323 '_sunder_ names, such as %r, are reserved for future Enum use'
324 % (key, )
325 )
Ethan Furmanc16595e2016-09-10 23:36:59 -0700326 if key == '_generate_next_value_':
Ethan Onstottd9a43e22020-04-28 13:20:55 -0400327 # check if members already defined as auto()
328 if self._auto_called:
329 raise TypeError("_generate_next_value_ must be defined before members")
Ethan Furmanb7751062021-03-30 21:17:26 -0700330 _gnv = value.__func__ if isinstance(value, staticmethod) else value
331 setattr(self, '_generate_next_value', _gnv)
Ethan Furmana4b1bb42018-01-22 07:56:37 -0800332 elif key == '_ignore_':
333 if isinstance(value, str):
334 value = value.replace(',',' ').split()
335 else:
336 value = list(value)
337 self._ignore = value
338 already = set(value) & set(self._member_names)
339 if already:
Ethan Furman6d3dfee2020-12-08 12:26:56 -0800340 raise ValueError(
341 '_ignore_ cannot specify already set names: %r'
342 % (already, )
343 )
Ethan Furman101e0742013-09-15 12:34:36 -0700344 elif _is_dunder(key):
Ethan Furmane8e61272016-08-20 07:19:31 -0700345 if key == '__order__':
346 key = '_order_'
Ethan Furman101e0742013-09-15 12:34:36 -0700347 elif key in self._member_names:
348 # descriptor overwriting an enum?
Ethan Furmana6582872020-12-10 13:07:00 -0800349 raise TypeError('%r already defined as: %r' % (key, self[key]))
Ethan Furmana4b1bb42018-01-22 07:56:37 -0800350 elif key in self._ignore:
351 pass
Ethan Furman101e0742013-09-15 12:34:36 -0700352 elif not _is_descriptor(value):
353 if key in self:
354 # enum overwriting a descriptor?
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700355 raise TypeError('%r already defined as: %r' % (key, self[key]))
Ethan Furmanc16595e2016-09-10 23:36:59 -0700356 if isinstance(value, auto):
Ethan Furman3515dcc2016-09-18 13:15:41 -0700357 if value.value == _auto_null:
Ethan Furman6d3dfee2020-12-08 12:26:56 -0800358 value.value = self._generate_next_value(
Ethan Furman7aaeb2a2021-01-25 14:26:19 -0800359 key, 1, len(self._member_names), self._last_values[:],
Ethan Furman6d3dfee2020-12-08 12:26:56 -0800360 )
Ethan Furmanfc23a942020-09-16 12:37:54 -0700361 self._auto_called = True
Ethan Furman3515dcc2016-09-18 13:15:41 -0700362 value = value.value
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700363 self._member_names.append(key)
Ethan Furmanc16595e2016-09-10 23:36:59 -0700364 self._last_values.append(value)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700365 super().__setitem__(key, value)
366
Ethan Furmana6582872020-12-10 13:07:00 -0800367 def update(self, members, **more_members):
368 try:
369 for name in members.keys():
370 self[name] = members[name]
371 except AttributeError:
372 for name, value in members:
373 self[name] = value
374 for name, value in more_members.items():
375 self[name] = value
376
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700377
Ethan Furmanb7751062021-03-30 21:17:26 -0700378class EnumType(type):
Ethan Furman6d3dfee2020-12-08 12:26:56 -0800379 """
380 Metaclass for Enum
381 """
Ethan Furman7aaeb2a2021-01-25 14:26:19 -0800382
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700383 @classmethod
Ethan Furman6ec0ade2020-12-24 10:05:02 -0800384 def __prepare__(metacls, cls, bases, **kwds):
Ethan Furman3064dbf2020-09-16 07:11:57 -0700385 # check that previous enum members do not exist
386 metacls._check_for_existing_members(cls, bases)
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700387 # create the namespace dict
388 enum_dict = _EnumDict()
Ethan Furman7cf0aad2020-12-09 17:12:11 -0800389 enum_dict._cls_name = cls
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700390 # inherit previous flags and _generate_next_value_ function
Ethan Furman3064dbf2020-09-16 07:11:57 -0700391 member_type, first_enum = metacls._get_mixins_(cls, bases)
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700392 if first_enum is not None:
Ethan Furman6d3dfee2020-12-08 12:26:56 -0800393 enum_dict['_generate_next_value_'] = getattr(
394 first_enum, '_generate_next_value_', None,
395 )
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700396 return enum_dict
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700397
Ethan Furmana02cb472021-04-21 10:20:44 -0700398 def __new__(metacls, cls, bases, classdict, *, boundary=None, _simple=False, **kwds):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700399 # an Enum class is final once enumeration items have been defined; it
400 # cannot be mixed with other types (int, float, etc.) if it has an
401 # inherited __new__ unless a new __new__ is defined (or the resulting
402 # class will fail).
Ethan Furmana4b1bb42018-01-22 07:56:37 -0800403 #
404 # remove any keys listed in _ignore_
Ethan Furmana02cb472021-04-21 10:20:44 -0700405 if _simple:
406 return super().__new__(metacls, cls, bases, classdict, **kwds)
Ethan Furmana4b1bb42018-01-22 07:56:37 -0800407 classdict.setdefault('_ignore_', []).append('_ignore_')
408 ignore = classdict['_ignore_']
409 for key in ignore:
410 classdict.pop(key, None)
Ethan Furmanc314e602021-01-12 23:47:57 -0800411 #
412 # grab member names
413 member_names = classdict._member_names
414 #
415 # check for illegal enum names (any others?)
416 invalid_names = set(member_names) & {'mro', ''}
417 if invalid_names:
418 raise ValueError('Invalid enum member name: {0}'.format(
419 ','.join(invalid_names)))
420 #
421 # adjust the sunders
422 _order_ = classdict.pop('_order_', None)
423 # convert to normal dict
424 classdict = dict(classdict.items())
425 #
426 # data type of member and the controlling Enum class
Ethan Furman3064dbf2020-09-16 07:11:57 -0700427 member_type, first_enum = metacls._get_mixins_(cls, bases)
Ethan Furmanc2667362020-12-07 00:17:31 -0800428 __new__, save_new, use_args = metacls._find_new_(
429 classdict, member_type, first_enum,
430 )
Ethan Furmanc314e602021-01-12 23:47:57 -0800431 classdict['_new_member_'] = __new__
432 classdict['_use_args_'] = use_args
433 #
434 # convert future enum members into temporary _proto_members
Ethan Furman7aaeb2a2021-01-25 14:26:19 -0800435 # and record integer values in case this will be a Flag
436 flag_mask = 0
Ethan Furmanc314e602021-01-12 23:47:57 -0800437 for name in member_names:
Ethan Furman7aaeb2a2021-01-25 14:26:19 -0800438 value = classdict[name]
439 if isinstance(value, int):
440 flag_mask |= value
441 classdict[name] = _proto_member(value)
Ethan Furmanc314e602021-01-12 23:47:57 -0800442 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -0800443 # house-keeping structures
Ethan Furmanc314e602021-01-12 23:47:57 -0800444 classdict['_member_names_'] = []
445 classdict['_member_map_'] = {}
446 classdict['_value2member_map_'] = {}
Ethan Furman6bd92882021-04-27 13:05:08 -0700447 classdict['_unhashable_values_'] = []
Ethan Furmanc314e602021-01-12 23:47:57 -0800448 classdict['_member_type_'] = member_type
449 #
Ethan Furman7aaeb2a2021-01-25 14:26:19 -0800450 # Flag structures (will be removed if final class is not a Flag
451 classdict['_boundary_'] = (
452 boundary
453 or getattr(first_enum, '_boundary_', None)
454 )
455 classdict['_flag_mask_'] = flag_mask
456 classdict['_all_bits_'] = 2 ** ((flag_mask).bit_length()) - 1
457 classdict['_inverted_'] = None
458 #
Ethan Furman2da95042014-03-03 12:42:52 -0800459 # If a custom type is mixed into the Enum, and it does not know how
460 # to pickle itself, pickle.dumps will succeed but pickle.loads will
461 # fail. Rather than have the error show up later and possibly far
462 # from the source, sabotage the pickle protocol for this class so
463 # that pickle.dumps also fails.
464 #
465 # However, if the new class implements its own __reduce_ex__, do not
466 # sabotage -- it's on them to make sure it works correctly. We use
467 # __reduce_ex__ instead of any of the others as it is preferred by
468 # pickle over __reduce__, and it handles all pickle protocols.
469 if '__reduce_ex__' not in classdict:
Ethan Furmandc870522014-02-18 12:37:12 -0800470 if member_type is not object:
471 methods = ('__getnewargs_ex__', '__getnewargs__',
472 '__reduce_ex__', '__reduce__')
Ethan Furman2da95042014-03-03 12:42:52 -0800473 if not any(m in member_type.__dict__ for m in methods):
Ethan Furmanc314e602021-01-12 23:47:57 -0800474 _make_class_unpicklable(classdict)
475 #
476 # create a default docstring if one has not been provided
477 if '__doc__' not in classdict:
478 classdict['__doc__'] = 'An enumeration.'
479 try:
480 exc = None
481 enum_class = super().__new__(metacls, cls, bases, classdict, **kwds)
482 except RuntimeError as e:
483 # any exceptions raised by member.__new__ will get converted to a
484 # RuntimeError, so get that original exception back and raise it instead
485 exc = e.__cause__ or e
486 if exc is not None:
487 raise exc
488 #
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700489 # double check that repr and friends are not the mixin's or various
490 # things break (such as pickle)
Ethan Furman22415ad2020-09-15 16:28:25 -0700491 # however, if the method is defined in the Enum itself, don't replace
492 # it
Ethan Furmandc870522014-02-18 12:37:12 -0800493 for name in ('__repr__', '__str__', '__format__', '__reduce_ex__'):
Ethan Furman22415ad2020-09-15 16:28:25 -0700494 if name in classdict:
495 continue
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700496 class_method = getattr(enum_class, name)
497 obj_method = getattr(member_type, name, None)
498 enum_method = getattr(first_enum, name, None)
499 if obj_method is not None and obj_method is class_method:
500 setattr(enum_class, name, enum_method)
Ethan Furmanc314e602021-01-12 23:47:57 -0800501 #
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700502 # replace any other __new__ with our own (as long as Enum is not None,
503 # anyway) -- again, this is to support pickle
504 if Enum is not None:
505 # if the user defined their own __new__, save it before it gets
506 # clobbered in case they subclass later
507 if save_new:
508 enum_class.__new_member__ = __new__
509 enum_class.__new__ = Enum.__new__
Ethan Furmanc314e602021-01-12 23:47:57 -0800510 #
Ethan Furmane8e61272016-08-20 07:19:31 -0700511 # py3 support for definition order (helps keep py2/py3 code in sync)
Ethan Furman7aaeb2a2021-01-25 14:26:19 -0800512 #
513 # _order_ checking is spread out into three/four steps
514 # - if enum_class is a Flag:
515 # - remove any non-single-bit flags from _order_
516 # - remove any aliases from _order_
517 # - check that _order_ and _member_names_ match
518 #
519 # step 1: ensure we have a list
Ethan Furmane8e61272016-08-20 07:19:31 -0700520 if _order_ is not None:
521 if isinstance(_order_, str):
522 _order_ = _order_.replace(',', ' ').split()
Ethan Furman7aaeb2a2021-01-25 14:26:19 -0800523 #
524 # remove Flag structures if final class is not a Flag
525 if (
526 Flag is None and cls != 'Flag'
527 or Flag is not None and not issubclass(enum_class, Flag)
528 ):
529 delattr(enum_class, '_boundary_')
530 delattr(enum_class, '_flag_mask_')
531 delattr(enum_class, '_all_bits_')
532 delattr(enum_class, '_inverted_')
533 elif Flag is not None and issubclass(enum_class, Flag):
534 # ensure _all_bits_ is correct and there are no missing flags
535 single_bit_total = 0
536 multi_bit_total = 0
537 for flag in enum_class._member_map_.values():
538 flag_value = flag._value_
539 if _is_single_bit(flag_value):
540 single_bit_total |= flag_value
541 else:
542 # multi-bit flags are considered aliases
543 multi_bit_total |= flag_value
Ethan Furman7aaeb2a2021-01-25 14:26:19 -0800544 enum_class._flag_mask_ = single_bit_total
545 #
546 # set correct __iter__
547 member_list = [m._value_ for m in enum_class]
548 if member_list != sorted(member_list):
549 enum_class._iter_member_ = enum_class._iter_member_by_def_
550 if _order_:
551 # _order_ step 2: remove any items from _order_ that are not single-bit
552 _order_ = [
553 o
554 for o in _order_
555 if o not in enum_class._member_map_ or _is_single_bit(enum_class[o]._value_)
556 ]
557 #
558 if _order_:
559 # _order_ step 3: remove aliases from _order_
560 _order_ = [
561 o
562 for o in _order_
563 if (
564 o not in enum_class._member_map_
565 or
566 (o in enum_class._member_map_ and o in enum_class._member_names_)
567 )]
568 # _order_ step 4: verify that _order_ and _member_names_ match
Ethan Furmane8e61272016-08-20 07:19:31 -0700569 if _order_ != enum_class._member_names_:
Ethan Furman7aaeb2a2021-01-25 14:26:19 -0800570 raise TypeError(
571 'member order does not match _order_:\n%r\n%r'
572 % (enum_class._member_names_, _order_)
573 )
Ethan Furmanc314e602021-01-12 23:47:57 -0800574 #
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700575 return enum_class
576
Ethan Furman5de67b12016-04-13 23:52:09 -0700577 def __bool__(self):
578 """
579 classes/types should always be True.
580 """
581 return True
582
Ethan Furman7aaeb2a2021-01-25 14:26:19 -0800583 def __call__(cls, value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None):
Ethan Furman6d3dfee2020-12-08 12:26:56 -0800584 """
585 Either returns an existing member, or creates a new enum class.
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700586
587 This method is used both when an enum class is given a value to match
588 to an enumeration member (i.e. Color(3)) and for the functional API
Ethan Furman23bb6f42016-11-21 09:22:05 -0800589 (i.e. Color = Enum('Color', names='RED GREEN BLUE')).
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700590
Ethan Furman2da95042014-03-03 12:42:52 -0800591 When used for the functional API:
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700592
Ethan Furman2da95042014-03-03 12:42:52 -0800593 `value` will be the name of the new class.
594
595 `names` should be either a string of white-space/comma delimited names
Ethan Furmand9925a12014-09-16 20:35:55 -0700596 (values will start at `start`), or an iterator/mapping of name, value pairs.
Ethan Furman2da95042014-03-03 12:42:52 -0800597
598 `module` should be set to the module this class is being created in;
599 if it is not set, an attempt to find that module will be made, but if
600 it fails the class will not be picklable.
601
602 `qualname` should be set to the actual location this class can be found
603 at in its module; by default it is set to the global scope. If this is
604 not correct, unpickling will fail in some circumstances.
605
606 `type`, if set, will be mixed in as the first base class.
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700607 """
608 if names is None: # simple value lookup
609 return cls.__new__(cls, value)
610 # otherwise, functional API: we're creating a new Enum type
Ethan Furman6d3dfee2020-12-08 12:26:56 -0800611 return cls._create_(
612 value,
613 names,
614 module=module,
615 qualname=qualname,
616 type=type,
617 start=start,
Ethan Furman7aaeb2a2021-01-25 14:26:19 -0800618 boundary=boundary,
Ethan Furman6d3dfee2020-12-08 12:26:56 -0800619 )
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700620
621 def __contains__(cls, member):
Rahul Jha94306522018-09-10 23:51:04 +0530622 if not isinstance(member, Enum):
Ethan Furman6bd92882021-04-27 13:05:08 -0700623 import warnings
624 warnings.warn(
625 "in 3.12 __contains__ will no longer raise TypeError, but will return True or\n"
626 "False depending on whether the value is a member or the value of a member",
627 DeprecationWarning,
628 stacklevel=2,
629 )
Rahul Jha94306522018-09-10 23:51:04 +0530630 raise TypeError(
631 "unsupported operand type(s) for 'in': '%s' and '%s'" % (
632 type(member).__qualname__, cls.__class__.__qualname__))
Ethan Furman0081f232014-09-16 17:31:23 -0700633 return isinstance(member, cls) and member._name_ in cls._member_map_
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700634
Ethan Furman64a99722013-09-22 16:18:19 -0700635 def __delattr__(cls, attr):
636 # nicer error message when someone tries to delete an attribute
637 # (see issue19025).
638 if attr in cls._member_map_:
Ethan Furman6d3dfee2020-12-08 12:26:56 -0800639 raise AttributeError("%s: cannot delete Enum member %r." % (cls.__name__, attr))
Ethan Furman64a99722013-09-22 16:18:19 -0700640 super().__delattr__(attr)
641
Ethan Furman388a3922013-08-12 06:51:41 -0700642 def __dir__(self):
Ethan Furman6d3dfee2020-12-08 12:26:56 -0800643 return (
644 ['__class__', '__doc__', '__members__', '__module__']
645 + self._member_names_
646 )
Ethan Furman388a3922013-08-12 06:51:41 -0700647
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700648 def __getattr__(cls, name):
Ethan Furman6d3dfee2020-12-08 12:26:56 -0800649 """
650 Return the enum member matching `name`
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700651
652 We use __getattr__ instead of descriptors or inserting into the enum
653 class' __dict__ in order to support `name` and `value` being both
654 properties for enum members (which live in the class' __dict__) and
655 enum members themselves.
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700656 """
657 if _is_dunder(name):
658 raise AttributeError(name)
659 try:
Ethan Furman520ad572013-07-19 19:47:21 -0700660 return cls._member_map_[name]
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700661 except KeyError:
662 raise AttributeError(name) from None
663
664 def __getitem__(cls, name):
Ethan Furman520ad572013-07-19 19:47:21 -0700665 return cls._member_map_[name]
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700666
667 def __iter__(cls):
Ethan Furman6d3dfee2020-12-08 12:26:56 -0800668 """
669 Returns members in definition order.
670 """
Ethan Furman520ad572013-07-19 19:47:21 -0700671 return (cls._member_map_[name] for name in cls._member_names_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700672
673 def __len__(cls):
Ethan Furman520ad572013-07-19 19:47:21 -0700674 return len(cls._member_names_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700675
Ethan Furmanc314e602021-01-12 23:47:57 -0800676 @_bltin_property
Ethan Furman2131a4a2013-09-14 18:11:24 -0700677 def __members__(cls):
Ethan Furman6d3dfee2020-12-08 12:26:56 -0800678 """
679 Returns a mapping of member name->value.
Ethan Furman2131a4a2013-09-14 18:11:24 -0700680
681 This mapping lists all enum members, including aliases. Note that this
682 is a read-only view of the internal mapping.
Ethan Furman2131a4a2013-09-14 18:11:24 -0700683 """
684 return MappingProxyType(cls._member_map_)
685
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700686 def __repr__(cls):
Ethan Furman74964862021-06-10 07:24:20 -0700687 if Flag is not None and issubclass(cls, Flag):
688 return "<flag %r>" % cls.__name__
689 else:
690 return "<enum %r>" % cls.__name__
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700691
Ethan Furman2131a4a2013-09-14 18:11:24 -0700692 def __reversed__(cls):
Ethan Furman6d3dfee2020-12-08 12:26:56 -0800693 """
694 Returns members in reverse definition order.
695 """
Ethan Furman2131a4a2013-09-14 18:11:24 -0700696 return (cls._member_map_[name] for name in reversed(cls._member_names_))
697
Ethan Furmanf203f2d2013-09-06 07:16:48 -0700698 def __setattr__(cls, name, value):
Ethan Furman6d3dfee2020-12-08 12:26:56 -0800699 """
700 Block attempts to reassign Enum members.
Ethan Furmanf203f2d2013-09-06 07:16:48 -0700701
702 A simple assignment to the class namespace only changes one of the
703 several possible ways to get an Enum member from the Enum class,
704 resulting in an inconsistent Enumeration.
Ethan Furmanf203f2d2013-09-06 07:16:48 -0700705 """
706 member_map = cls.__dict__.get('_member_map_', {})
707 if name in member_map:
Ethan Furmana02cb472021-04-21 10:20:44 -0700708 raise AttributeError('Cannot reassign member %r.' % (name, ))
Ethan Furmanf203f2d2013-09-06 07:16:48 -0700709 super().__setattr__(name, value)
710
Ethan Furman7aaeb2a2021-01-25 14:26:19 -0800711 def _create_(cls, class_name, names, *, module=None, qualname=None, type=None, start=1, boundary=None):
Ethan Furman6d3dfee2020-12-08 12:26:56 -0800712 """
713 Convenience method to create a new Enum class.
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700714
715 `names` can be:
716
717 * A string containing member names, separated either with spaces or
Ethan Furmand9925a12014-09-16 20:35:55 -0700718 commas. Values are incremented by 1 from `start`.
719 * An iterable of member names. Values are incremented by 1 from `start`.
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700720 * An iterable of (member name, value) pairs.
Ethan Furmand9925a12014-09-16 20:35:55 -0700721 * A mapping of member name -> value pairs.
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700722 """
723 metacls = cls.__class__
724 bases = (cls, ) if type is None else (type, cls)
Ethan Furman3064dbf2020-09-16 07:11:57 -0700725 _, first_enum = cls._get_mixins_(cls, bases)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700726 classdict = metacls.__prepare__(class_name, bases)
727
728 # special processing needed for names?
729 if isinstance(names, str):
730 names = names.replace(',', ' ').split()
Dong-hee Nadcc8ce42017-06-22 01:52:32 +0900731 if isinstance(names, (tuple, list)) and names and isinstance(names[0], str):
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700732 original_names, names = names, []
Ethan Furmanc16595e2016-09-10 23:36:59 -0700733 last_values = []
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700734 for count, name in enumerate(original_names):
Ethan Furmanc16595e2016-09-10 23:36:59 -0700735 value = first_enum._generate_next_value_(name, start, count, last_values[:])
736 last_values.append(value)
737 names.append((name, value))
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700738
739 # Here, names is either an iterable of (name, value) or a mapping.
740 for item in names:
741 if isinstance(item, str):
742 member_name, member_value = item, names[item]
743 else:
744 member_name, member_value = item
745 classdict[member_name] = member_value
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700746
747 # TODO: replace the frame hack if a blessed way to know the calling
748 # module is ever developed
749 if module is None:
750 try:
751 module = sys._getframe(2).f_globals['__name__']
Pablo Galindo293dd232019-11-19 21:34:03 +0000752 except (AttributeError, ValueError, KeyError):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700753 pass
754 if module is None:
Ethan Furmanc314e602021-01-12 23:47:57 -0800755 _make_class_unpicklable(classdict)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700756 else:
Ethan Furmanc314e602021-01-12 23:47:57 -0800757 classdict['__module__'] = module
Ethan Furmanca1b7942014-02-08 11:36:27 -0800758 if qualname is not None:
Ethan Furmanc314e602021-01-12 23:47:57 -0800759 classdict['__qualname__'] = qualname
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700760
Ethan Furman7aaeb2a2021-01-25 14:26:19 -0800761 return metacls.__new__(metacls, class_name, bases, classdict, boundary=boundary)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700762
Ethan Furmana02cb472021-04-21 10:20:44 -0700763 def _convert_(cls, name, module, filter, source=None, *, boundary=None):
764
orlnub1230fb9fad2018-09-12 20:28:53 +0300765 """
766 Create a new Enum subclass that replaces a collection of global constants
767 """
768 # convert all constants from source (or module) that pass filter() to
769 # a new Enum called name, and export the enum and its members back to
770 # module;
771 # also, replace the __reduce_ex__ method so unpickling works in
772 # previous Python versions
Ethan Furmanb7751062021-03-30 21:17:26 -0700773 module_globals = sys.modules[module].__dict__
orlnub1230fb9fad2018-09-12 20:28:53 +0300774 if source:
Ethan Furmanb7751062021-03-30 21:17:26 -0700775 source = source.__dict__
orlnub1230fb9fad2018-09-12 20:28:53 +0300776 else:
777 source = module_globals
778 # _value2member_map_ is populated in the same order every time
779 # for a consistent reverse mapping of number to name when there
780 # are multiple names for the same number.
781 members = [
782 (name, value)
783 for name, value in source.items()
784 if filter(name)]
785 try:
786 # sort by value
787 members.sort(key=lambda t: (t[1], t[0]))
788 except TypeError:
789 # unless some values aren't comparable, in which case sort by name
790 members.sort(key=lambda t: t[0])
Ethan Furmana02cb472021-04-21 10:20:44 -0700791 body = {t[0]: t[1] for t in members}
792 body['__module__'] = module
793 tmp_cls = type(name, (object, ), body)
794 cls = _simple_enum(etype=cls, boundary=boundary or KEEP)(tmp_cls)
orlnub1230fb9fad2018-09-12 20:28:53 +0300795 cls.__reduce_ex__ = _reduce_ex_by_name
Ethan Furmanb7751062021-03-30 21:17:26 -0700796 global_enum(cls)
orlnub1230fb9fad2018-09-12 20:28:53 +0300797 module_globals[name] = cls
798 return cls
799
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700800 @staticmethod
Ethan Furman3064dbf2020-09-16 07:11:57 -0700801 def _check_for_existing_members(class_name, bases):
802 for chain in bases:
803 for base in chain.__mro__:
804 if issubclass(base, Enum) and base._member_names_:
Ethan Furman6d3dfee2020-12-08 12:26:56 -0800805 raise TypeError(
806 "%s: cannot extend enumeration %r"
807 % (class_name, base.__name__)
808 )
Ethan Furman3064dbf2020-09-16 07:11:57 -0700809
810 @staticmethod
811 def _get_mixins_(class_name, bases):
Ethan Furman6d3dfee2020-12-08 12:26:56 -0800812 """
813 Returns the type for creating enum members, and the first inherited
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700814 enum class.
815
816 bases: the tuple of bases that was given to __new__
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700817 """
818 if not bases:
819 return object, Enum
820
Ethan Furman5bdab642018-09-21 19:03:09 -0700821 def _find_data_type(bases):
Miss Islington (bot)01286012021-06-10 15:01:03 -0700822 data_types = set()
Ethan Furman5bdab642018-09-21 19:03:09 -0700823 for chain in bases:
Ethan Furmanbff01f32020-09-15 15:56:26 -0700824 candidate = None
Ethan Furman5bdab642018-09-21 19:03:09 -0700825 for base in chain.__mro__:
826 if base is object:
827 continue
Ethan Furmanc2667362020-12-07 00:17:31 -0800828 elif issubclass(base, Enum):
829 if base._member_type_ is not object:
Miss Islington (bot)01286012021-06-10 15:01:03 -0700830 data_types.add(base._member_type_)
Ethan Furmanc2667362020-12-07 00:17:31 -0800831 break
Ethan Furman5bdab642018-09-21 19:03:09 -0700832 elif '__new__' in base.__dict__:
Ethan Furmancd453852018-10-05 23:29:36 -0700833 if issubclass(base, Enum):
Ethan Furman5bdab642018-09-21 19:03:09 -0700834 continue
Miss Islington (bot)01286012021-06-10 15:01:03 -0700835 data_types.add(candidate or base)
Ethan Furmanbff01f32020-09-15 15:56:26 -0700836 break
Ethan Furmanc2667362020-12-07 00:17:31 -0800837 else:
Ethan Furmanbff01f32020-09-15 15:56:26 -0700838 candidate = base
839 if len(data_types) > 1:
Ethan Furman3064dbf2020-09-16 07:11:57 -0700840 raise TypeError('%r: too many data types: %r' % (class_name, data_types))
Ethan Furmanbff01f32020-09-15 15:56:26 -0700841 elif data_types:
Miss Islington (bot)01286012021-06-10 15:01:03 -0700842 return data_types.pop()
Ethan Furmanbff01f32020-09-15 15:56:26 -0700843 else:
844 return None
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700845
Ethan Furman5bdab642018-09-21 19:03:09 -0700846 # ensure final parent class is an Enum derivative, find any concrete
847 # data type, and check that Enum has no members
848 first_enum = bases[-1]
849 if not issubclass(first_enum, Enum):
850 raise TypeError("new enumerations should be created as "
851 "`EnumName([mixin_type, ...] [data_type,] enum_type)`")
852 member_type = _find_data_type(bases) or object
853 if first_enum._member_names_:
854 raise TypeError("Cannot extend enumerations")
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700855 return member_type, first_enum
856
857 @staticmethod
858 def _find_new_(classdict, member_type, first_enum):
Ethan Furman6d3dfee2020-12-08 12:26:56 -0800859 """
860 Returns the __new__ to be used for creating the enum members.
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700861
862 classdict: the class dictionary given to __new__
863 member_type: the data type whose __new__ will be used by default
864 first_enum: enumeration to check for an overriding __new__
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700865 """
866 # now find the correct __new__, checking to see of one was defined
867 # by the user; also check earlier enum classes in case a __new__ was
868 # saved as __new_member__
869 __new__ = classdict.get('__new__', None)
870
871 # should __new__ be saved as __new_member__ later?
Ethan Furmana02cb472021-04-21 10:20:44 -0700872 save_new = first_enum is not None and __new__ is not None
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700873
874 if __new__ is None:
875 # check all possibles for __new_member__ before falling back to
876 # __new__
877 for method in ('__new_member__', '__new__'):
878 for possible in (member_type, first_enum):
879 target = getattr(possible, method, None)
880 if target not in {
881 None,
882 None.__new__,
883 object.__new__,
884 Enum.__new__,
885 }:
886 __new__ = target
887 break
888 if __new__ is not None:
889 break
890 else:
891 __new__ = object.__new__
892
893 # if a non-object.__new__ is used then whatever value/tuple was
894 # assigned to the enum member name will be passed to __new__ and to the
895 # new enum member's __init__
Ethan Furmana02cb472021-04-21 10:20:44 -0700896 if first_enum is None or __new__ in (Enum.__new__, object.__new__):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700897 use_args = False
898 else:
899 use_args = True
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700900 return __new__, save_new, use_args
Ethan Furmanb7751062021-03-30 21:17:26 -0700901EnumMeta = EnumType
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700902
903
Ethan Furmanb7751062021-03-30 21:17:26 -0700904class Enum(metaclass=EnumType):
Ethan Furman6d3dfee2020-12-08 12:26:56 -0800905 """
906 Generic enumeration.
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700907
908 Derive from this class to define new enumerations.
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700909 """
Ethan Furman7aaeb2a2021-01-25 14:26:19 -0800910
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700911 def __new__(cls, value):
912 # all enum instances are actually created during class construction
913 # without calling this method; this method is called by the metaclass'
914 # __call__ (i.e. Color(3) ), and by pickle
915 if type(value) is cls:
Ethan Furman23bb6f42016-11-21 09:22:05 -0800916 # For lookups like Color(Color.RED)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700917 return value
918 # by-value search for a matching enum member
919 # see if it's in the reverse mapping (for hashable values)
Ethan Furman2aa27322013-07-19 19:35:56 -0700920 try:
Andrew Svetlov34ae04f2018-12-26 20:45:33 +0200921 return cls._value2member_map_[value]
922 except KeyError:
923 # Not found, no need to do long O(n) search
924 pass
Ethan Furman2aa27322013-07-19 19:35:56 -0700925 except TypeError:
926 # not there, now do long search -- O(n) behavior
Ethan Furman520ad572013-07-19 19:47:21 -0700927 for member in cls._member_map_.values():
Ethan Furman0081f232014-09-16 17:31:23 -0700928 if member._value_ == value:
Ethan Furman2aa27322013-07-19 19:35:56 -0700929 return member
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700930 # still not found -- try _missing_ hook
Ethan Furman019f0a02018-09-12 11:43:34 -0700931 try:
932 exc = None
933 result = cls._missing_(value)
934 except Exception as e:
935 exc = e
936 result = None
Ethan Furman8c14f5a2021-04-12 08:51:20 -0700937 try:
938 if isinstance(result, cls):
939 return result
940 elif (
941 Flag is not None and issubclass(cls, Flag)
942 and cls._boundary_ is EJECT and isinstance(result, int)
943 ):
944 return result
945 else:
946 ve_exc = ValueError("%r is not a valid %s" % (value, cls.__qualname__))
947 if result is None and exc is None:
948 raise ve_exc
949 elif exc is None:
950 exc = TypeError(
951 'error in %s._missing_: returned %r instead of None or a valid member'
952 % (cls.__name__, result)
953 )
954 if not isinstance(exc, ValueError):
955 exc.__context__ = ve_exc
956 raise exc
957 finally:
958 # ensure all variables that could hold an exception are destroyed
959 exc = None
960 ve_exc = None
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700961
Ethan Furmanc16595e2016-09-10 23:36:59 -0700962 def _generate_next_value_(name, start, count, last_values):
Ethan Furman6d3dfee2020-12-08 12:26:56 -0800963 """
964 Generate the next value when not given.
965
966 name: the name of the member
967 start: the initial start value or None
968 count: the number of existing members
969 last_value: the last value assigned or None
970 """
Ethan Furmanc16595e2016-09-10 23:36:59 -0700971 for last_value in reversed(last_values):
972 try:
973 return last_value + 1
974 except TypeError:
975 pass
976 else:
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700977 return start
Ethan Furmanc16595e2016-09-10 23:36:59 -0700978
Ethan Furmanee47e5c2016-08-31 00:12:15 -0700979 @classmethod
980 def _missing_(cls, value):
Ethan Furmanc95ad7a2020-09-16 10:26:50 -0700981 return None
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700982
983 def __repr__(self):
Ethan Furmanb7751062021-03-30 21:17:26 -0700984 return "%s.%s" % ( self.__class__.__name__, self._name_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700985
986 def __str__(self):
Ethan Furmanb7751062021-03-30 21:17:26 -0700987 return "%s" % (self._name_, )
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700988
Ethan Furman388a3922013-08-12 06:51:41 -0700989 def __dir__(self):
Ethan Furman6d3dfee2020-12-08 12:26:56 -0800990 """
991 Returns all members and all public methods
992 """
Ethan Furman0ae550b2014-10-14 08:58:32 -0700993 added_behavior = [
994 m
995 for cls in self.__class__.mro()
996 for m in cls.__dict__
Ethan Furman354ecf12015-03-11 08:43:12 -0700997 if m[0] != '_' and m not in self._member_map_
Angelin BOOZ68526fe2020-09-21 15:11:06 +0200998 ] + [m for m in self.__dict__ if m[0] != '_']
Ethan Furmanec5f8eb2014-10-21 13:40:35 -0700999 return (['__class__', '__doc__', '__module__'] + added_behavior)
Ethan Furman388a3922013-08-12 06:51:41 -07001000
Ethan Furmanec15a822013-08-31 19:17:41 -07001001 def __format__(self, format_spec):
Ethan Furman6d3dfee2020-12-08 12:26:56 -08001002 """
1003 Returns format using actual value type unless __str__ has been overridden.
1004 """
Ethan Furmanec15a822013-08-31 19:17:41 -07001005 # mixed-in Enums should use the mixed-in type's __format__, otherwise
1006 # we can get strange results with the Enum name showing up instead of
1007 # the value
1008
thatneat2f19e822019-07-04 11:28:37 -07001009 # pure Enum branch, or branch with __str__ explicitly overridden
Ethan Furman37440ee2020-12-08 11:14:10 -08001010 str_overridden = type(self).__str__ not in (Enum.__str__, Flag.__str__)
thatneat2f19e822019-07-04 11:28:37 -07001011 if self._member_type_ is object or str_overridden:
Ethan Furmanec15a822013-08-31 19:17:41 -07001012 cls = str
1013 val = str(self)
1014 # mix-in branch
1015 else:
Ethan Furman6bd92882021-04-27 13:05:08 -07001016 if not format_spec or format_spec in ('{}','{:}'):
1017 import warnings
1018 warnings.warn(
1019 "in 3.12 format() will use the enum member, not the enum member's value;\n"
Pablo Galindo9a42d502021-05-01 20:26:09 +01001020 "use a format specifier, such as :d for an IntEnum member, to maintain "
Ethan Furman6bd92882021-04-27 13:05:08 -07001021 "the current display",
1022 DeprecationWarning,
1023 stacklevel=2,
1024 )
Ethan Furmanec15a822013-08-31 19:17:41 -07001025 cls = self._member_type_
Ethan Furman0081f232014-09-16 17:31:23 -07001026 val = self._value_
Ethan Furmanec15a822013-08-31 19:17:41 -07001027 return cls.__format__(val, format_spec)
1028
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001029 def __hash__(self):
Ethan Furman520ad572013-07-19 19:47:21 -07001030 return hash(self._name_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001031
Ethan Furmanca1b7942014-02-08 11:36:27 -08001032 def __reduce_ex__(self, proto):
Ethan Furmandc870522014-02-18 12:37:12 -08001033 return self.__class__, (self._value_, )
Ethan Furmanca1b7942014-02-08 11:36:27 -08001034
Ethan Furmanc314e602021-01-12 23:47:57 -08001035 # enum.property is used to provide access to the `name` and
1036 # `value` attributes of enum members while keeping some measure of
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001037 # protection from modification, while still allowing for an enumeration
1038 # to have members named `name` and `value`. This works because enumeration
Ethan Furmanc314e602021-01-12 23:47:57 -08001039 # members are not set directly on the enum class; they are kept in a
1040 # separate structure, _member_map_, which is where enum.property looks for
1041 # them
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001042
Ethan Furmanc314e602021-01-12 23:47:57 -08001043 @property
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001044 def name(self):
Ethan Furmanc850f342013-09-15 16:59:35 -07001045 """The name of the Enum member."""
Ethan Furman520ad572013-07-19 19:47:21 -07001046 return self._name_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001047
Ethan Furmanc314e602021-01-12 23:47:57 -08001048 @property
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001049 def value(self):
Ethan Furmanc850f342013-09-15 16:59:35 -07001050 """The value of the Enum member."""
Ethan Furman520ad572013-07-19 19:47:21 -07001051 return self._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001052
1053
1054class IntEnum(int, Enum):
Ethan Furman0063ff42020-09-21 17:23:13 -07001055 """
1056 Enum where members are also (and must be) ints
1057 """
1058
1059
1060class StrEnum(str, Enum):
1061 """
1062 Enum where members are also (and must be) strings
1063 """
1064
1065 def __new__(cls, *values):
1066 if len(values) > 3:
1067 raise TypeError('too many arguments for str(): %r' % (values, ))
1068 if len(values) == 1:
1069 # it must be a string
1070 if not isinstance(values[0], str):
1071 raise TypeError('%r is not a string' % (values[0], ))
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08001072 if len(values) >= 2:
Ethan Furman0063ff42020-09-21 17:23:13 -07001073 # check that encoding argument is a string
1074 if not isinstance(values[1], str):
1075 raise TypeError('encoding must be a string, not %r' % (values[1], ))
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08001076 if len(values) == 3:
1077 # check that errors argument is a string
1078 if not isinstance(values[2], str):
1079 raise TypeError('errors must be a string, not %r' % (values[2]))
Ethan Furman0063ff42020-09-21 17:23:13 -07001080 value = str(*values)
1081 member = str.__new__(cls, value)
1082 member._value_ = value
1083 return member
Ethan Furmanf24bb352013-07-18 17:05:39 -07001084
Ethan Furmand986d162020-09-22 13:00:07 -07001085 __str__ = str.__str__
1086
Ethan Furmanefb13be2020-12-10 12:20:06 -08001087 def _generate_next_value_(name, start, count, last_values):
1088 """
1089 Return the lower-cased version of the member name.
1090 """
1091 return name.lower()
1092
Ethan Furmanf24bb352013-07-18 17:05:39 -07001093
Ethan Furman24e837f2015-03-18 17:27:57 -07001094def _reduce_ex_by_name(self, proto):
1095 return self.name
1096
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08001097class FlagBoundary(StrEnum):
1098 """
1099 control how out of range values are handled
1100 "strict" -> error is raised [default for Flag]
1101 "conform" -> extra bits are discarded
1102 "eject" -> lose flag status [default for IntFlag]
1103 "keep" -> keep flag status and all bits
1104 """
1105 STRICT = auto()
1106 CONFORM = auto()
1107 EJECT = auto()
1108 KEEP = auto()
1109STRICT, CONFORM, EJECT, KEEP = FlagBoundary
1110
1111
1112class Flag(Enum, boundary=STRICT):
Ethan Furman6d3dfee2020-12-08 12:26:56 -08001113 """
1114 Support for flags
1115 """
Ethan Furmanc16595e2016-09-10 23:36:59 -07001116
1117 def _generate_next_value_(name, start, count, last_values):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001118 """
1119 Generate the next value when not given.
1120
1121 name: the name of the member
HongWeipengbb16fb22019-09-21 13:22:54 +08001122 start: the initial start value or None
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001123 count: the number of existing members
1124 last_value: the last value assigned or None
1125 """
1126 if not count:
1127 return start if start is not None else 1
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08001128 last_value = max(last_values)
1129 try:
1130 high_bit = _high_bit(last_value)
1131 except Exception:
1132 raise TypeError('Invalid Flag value: %r' % last_value) from None
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001133 return 2 ** (high_bit+1)
1134
1135 @classmethod
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08001136 def _iter_member_by_value_(cls, value):
1137 """
1138 Extract all members from the value in definition (i.e. increasing value) order.
1139 """
1140 for val in _iter_bits_lsb(value & cls._flag_mask_):
1141 yield cls._value2member_map_.get(val)
1142
1143 _iter_member_ = _iter_member_by_value_
1144
1145 @classmethod
1146 def _iter_member_by_def_(cls, value):
1147 """
1148 Extract all members from the value in definition order.
1149 """
1150 yield from sorted(
1151 cls._iter_member_by_value_(value),
1152 key=lambda m: m._sort_order_,
1153 )
1154
1155 @classmethod
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001156 def _missing_(cls, value):
Ethan Furman6d3dfee2020-12-08 12:26:56 -08001157 """
Ethan Furman0dca5eb2021-04-15 06:49:54 -07001158 Create a composite member containing all canonical members present in `value`.
1159
1160 If non-member values are present, result depends on `_boundary_` setting.
Ethan Furman3515dcc2016-09-18 13:15:41 -07001161 """
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08001162 if not isinstance(value, int):
1163 raise ValueError(
1164 "%r is not a valid %s" % (value, cls.__qualname__)
1165 )
1166 # check boundaries
1167 # - value must be in range (e.g. -16 <-> +15, i.e. ~15 <-> 15)
1168 # - value must not include any skipped flags (e.g. if bit 2 is not
1169 # defined, then 0d10 is invalid)
1170 flag_mask = cls._flag_mask_
1171 all_bits = cls._all_bits_
1172 neg_value = None
1173 if (
1174 not ~all_bits <= value <= all_bits
1175 or value & (all_bits ^ flag_mask)
1176 ):
1177 if cls._boundary_ is STRICT:
1178 max_bits = max(value.bit_length(), flag_mask.bit_length())
1179 raise ValueError(
1180 "%s: invalid value: %r\n given %s\n allowed %s" % (
1181 cls.__name__, value, bin(value, max_bits), bin(flag_mask, max_bits),
1182 ))
1183 elif cls._boundary_ is CONFORM:
1184 value = value & flag_mask
1185 elif cls._boundary_ is EJECT:
1186 return value
1187 elif cls._boundary_ is KEEP:
1188 if value < 0:
1189 value = (
1190 max(all_bits+1, 2**(value.bit_length()))
1191 + value
1192 )
1193 else:
1194 raise ValueError(
1195 'unknown flag boundary: %r' % (cls._boundary_, )
1196 )
1197 if value < 0:
1198 neg_value = value
1199 value = all_bits + 1 + value
1200 # get members and unknown
1201 unknown = value & ~flag_mask
1202 member_value = value & flag_mask
1203 if unknown and cls._boundary_ is not KEEP:
1204 raise ValueError(
1205 '%s(%r) --> unknown values %r [%s]'
1206 % (cls.__name__, value, unknown, bin(unknown))
1207 )
1208 # normal Flag?
1209 __new__ = getattr(cls, '__new_member__', None)
1210 if cls._member_type_ is object and not __new__:
Ethan Furman3515dcc2016-09-18 13:15:41 -07001211 # construct a singleton enum pseudo-member
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001212 pseudo_member = object.__new__(cls)
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08001213 else:
1214 pseudo_member = (__new__ or cls._member_type_.__new__)(cls, value)
Ethan Furmana02cb472021-04-21 10:20:44 -07001215 if not hasattr(pseudo_member, '_value_'):
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001216 pseudo_member._value_ = value
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08001217 if member_value:
1218 pseudo_member._name_ = '|'.join([
1219 m._name_ for m in cls._iter_member_(member_value)
1220 ])
1221 if unknown:
1222 pseudo_member._name_ += '|0x%x' % unknown
1223 else:
1224 pseudo_member._name_ = None
1225 # use setdefault in case another thread already created a composite
1226 # with this value, but only if all members are known
1227 # note: zero is a special case -- add it
1228 if not unknown:
Ethan Furman28cf6632017-01-24 12:12:06 -08001229 pseudo_member = cls._value2member_map_.setdefault(value, pseudo_member)
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08001230 if neg_value is not None:
1231 cls._value2member_map_[neg_value] = pseudo_member
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001232 return pseudo_member
1233
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001234 def __contains__(self, other):
Ethan Furman6d3dfee2020-12-08 12:26:56 -08001235 """
1236 Returns True if self has at least the same flags set as other.
1237 """
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001238 if not isinstance(other, self.__class__):
Rahul Jha94306522018-09-10 23:51:04 +05301239 raise TypeError(
1240 "unsupported operand type(s) for 'in': '%s' and '%s'" % (
1241 type(other).__qualname__, self.__class__.__qualname__))
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08001242 if other._value_ == 0 or self._value_ == 0:
1243 return False
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001244 return other._value_ & self._value_ == other._value_
1245
Ethan Furman7219e272020-09-16 13:01:00 -07001246 def __iter__(self):
Ethan Furman6d3dfee2020-12-08 12:26:56 -08001247 """
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08001248 Returns flags in definition order.
Ethan Furman6d3dfee2020-12-08 12:26:56 -08001249 """
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08001250 yield from self._iter_member_(self._value_)
1251
1252 def __len__(self):
1253 return self._value_.bit_count()
Ethan Furman7219e272020-09-16 13:01:00 -07001254
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001255 def __repr__(self):
Ethan Furmanb7751062021-03-30 21:17:26 -07001256 cls_name = self.__class__.__name__
1257 if self._name_ is None:
1258 return "0x%x" % (self._value_, )
1259 if _is_single_bit(self._value_):
1260 return '%s.%s' % (cls_name, self._name_)
1261 if self._boundary_ is not FlagBoundary.KEEP:
1262 return '%s.' % cls_name + ('|%s.' % cls_name).join(self.name.split('|'))
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08001263 else:
Ethan Furmanb7751062021-03-30 21:17:26 -07001264 name = []
1265 for n in self._name_.split('|'):
1266 if n.startswith('0'):
1267 name.append(n)
1268 else:
1269 name.append('%s.%s' % (cls_name, n))
1270 return '|'.join(name)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001271
1272 def __str__(self):
1273 cls = self.__class__
Ethan Furmanb7751062021-03-30 21:17:26 -07001274 if self._name_ is None:
1275 return '%s(%x)' % (cls.__name__, self._value_)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001276 else:
Ethan Furmanb7751062021-03-30 21:17:26 -07001277 return self._name_
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001278
Ethan Furman25d94bb2016-09-02 16:32:32 -07001279 def __bool__(self):
1280 return bool(self._value_)
1281
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001282 def __or__(self, other):
1283 if not isinstance(other, self.__class__):
1284 return NotImplemented
1285 return self.__class__(self._value_ | other._value_)
1286
1287 def __and__(self, other):
1288 if not isinstance(other, self.__class__):
1289 return NotImplemented
1290 return self.__class__(self._value_ & other._value_)
1291
1292 def __xor__(self, other):
1293 if not isinstance(other, self.__class__):
1294 return NotImplemented
1295 return self.__class__(self._value_ ^ other._value_)
1296
1297 def __invert__(self):
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08001298 if self._inverted_ is None:
1299 if self._boundary_ is KEEP:
1300 # use all bits
1301 self._inverted_ = self.__class__(~self._value_)
1302 else:
1303 # calculate flags not in this member
1304 self._inverted_ = self.__class__(self._flag_mask_ ^ self._value_)
Ethan Furman74964862021-06-10 07:24:20 -07001305 if isinstance(self._inverted_, self.__class__):
1306 self._inverted_._inverted_ = self
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08001307 return self._inverted_
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001308
1309
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08001310class IntFlag(int, Flag, boundary=EJECT):
Ethan Furman6d3dfee2020-12-08 12:26:56 -08001311 """
1312 Support for integer-based Flags
1313 """
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001314
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001315 def __or__(self, other):
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08001316 if isinstance(other, self.__class__):
1317 other = other._value_
1318 elif isinstance(other, int):
1319 other = other
1320 else:
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001321 return NotImplemented
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08001322 value = self._value_
1323 return self.__class__(value | other)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001324
1325 def __and__(self, other):
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08001326 if isinstance(other, self.__class__):
1327 other = other._value_
1328 elif isinstance(other, int):
1329 other = other
1330 else:
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001331 return NotImplemented
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08001332 value = self._value_
1333 return self.__class__(value & other)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001334
1335 def __xor__(self, other):
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08001336 if isinstance(other, self.__class__):
1337 other = other._value_
1338 elif isinstance(other, int):
1339 other = other
1340 else:
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001341 return NotImplemented
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08001342 value = self._value_
1343 return self.__class__(value ^ other)
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001344
1345 __ror__ = __or__
1346 __rand__ = __and__
1347 __rxor__ = __xor__
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08001348 __invert__ = Flag.__invert__
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001349
1350def _high_bit(value):
Ethan Furman6d3dfee2020-12-08 12:26:56 -08001351 """
1352 returns index of highest bit, or -1 if value is zero or negative
1353 """
Ethan Furman3515dcc2016-09-18 13:15:41 -07001354 return value.bit_length() - 1
Ethan Furmanee47e5c2016-08-31 00:12:15 -07001355
Ethan Furmanf24bb352013-07-18 17:05:39 -07001356def unique(enumeration):
Ethan Furman6d3dfee2020-12-08 12:26:56 -08001357 """
1358 Class decorator for enumerations ensuring unique member values.
1359 """
Ethan Furmanf24bb352013-07-18 17:05:39 -07001360 duplicates = []
1361 for name, member in enumeration.__members__.items():
1362 if name != member.name:
1363 duplicates.append((name, member.name))
1364 if duplicates:
1365 alias_details = ', '.join(
1366 ["%s -> %s" % (alias, name) for (alias, name) in duplicates])
1367 raise ValueError('duplicate values found in %r: %s' %
1368 (enumeration, alias_details))
1369 return enumeration
Ethan Furman3515dcc2016-09-18 13:15:41 -07001370
Ethan Furman7aaeb2a2021-01-25 14:26:19 -08001371def _power_of_two(value):
1372 if value < 1:
1373 return False
1374 return value == 2 ** _high_bit(value)
Ethan Furmanb7751062021-03-30 21:17:26 -07001375
1376def global_enum_repr(self):
1377 return '%s.%s' % (self.__class__.__module__, self._name_)
1378
1379def global_flag_repr(self):
1380 module = self.__class__.__module__
1381 cls_name = self.__class__.__name__
1382 if self._name_ is None:
1383 return "%x" % (module, cls_name, self._value_)
1384 if _is_single_bit(self):
1385 return '%s.%s' % (module, self._name_)
1386 if self._boundary_ is not FlagBoundary.KEEP:
1387 return module + module.join(self.name.split('|'))
1388 else:
1389 name = []
1390 for n in self._name_.split('|'):
1391 if n.startswith('0'):
1392 name.append(n)
1393 else:
1394 name.append('%s.%s' % (module, n))
1395 return '|'.join(name)
1396
1397
1398def global_enum(cls):
1399 """
1400 decorator that makes the repr() of an enum member reference its module
1401 instead of its class; also exports all members to the enum's module's
1402 global namespace
1403 """
1404 if issubclass(cls, Flag):
1405 cls.__repr__ = global_flag_repr
1406 else:
1407 cls.__repr__ = global_enum_repr
1408 sys.modules[cls.__module__].__dict__.update(cls.__members__)
1409 return cls
Ethan Furmana02cb472021-04-21 10:20:44 -07001410
1411def _simple_enum(etype=Enum, *, boundary=None, use_args=None):
1412 """
1413 Class decorator that converts a normal class into an :class:`Enum`. No
1414 safety checks are done, and some advanced behavior (such as
1415 :func:`__init_subclass__`) is not available. Enum creation can be faster
1416 using :func:`simple_enum`.
1417
1418 >>> from enum import Enum, _simple_enum
1419 >>> @_simple_enum(Enum)
1420 ... class Color:
1421 ... RED = auto()
1422 ... GREEN = auto()
1423 ... BLUE = auto()
1424 >>> Color
1425 <enum 'Color'>
1426 """
1427 def convert_class(cls):
1428 nonlocal use_args
1429 cls_name = cls.__name__
1430 if use_args is None:
1431 use_args = etype._use_args_
1432 __new__ = cls.__dict__.get('__new__')
1433 if __new__ is not None:
1434 new_member = __new__.__func__
1435 else:
1436 new_member = etype._member_type_.__new__
1437 attrs = {}
1438 body = {}
1439 if __new__ is not None:
1440 body['__new_member__'] = new_member
1441 body['_new_member_'] = new_member
1442 body['_use_args_'] = use_args
1443 body['_generate_next_value_'] = gnv = etype._generate_next_value_
1444 body['_member_names_'] = member_names = []
1445 body['_member_map_'] = member_map = {}
1446 body['_value2member_map_'] = value2member_map = {}
Ethan Furman6bd92882021-04-27 13:05:08 -07001447 body['_unhashable_values_'] = []
Ethan Furmana02cb472021-04-21 10:20:44 -07001448 body['_member_type_'] = member_type = etype._member_type_
1449 if issubclass(etype, Flag):
1450 body['_boundary_'] = boundary or etype._boundary_
1451 body['_flag_mask_'] = None
1452 body['_all_bits_'] = None
1453 body['_inverted_'] = None
1454 for name, obj in cls.__dict__.items():
1455 if name in ('__dict__', '__weakref__'):
1456 continue
1457 if _is_dunder(name) or _is_private(cls_name, name) or _is_sunder(name) or _is_descriptor(obj):
1458 body[name] = obj
1459 else:
1460 attrs[name] = obj
1461 if cls.__dict__.get('__doc__') is None:
1462 body['__doc__'] = 'An enumeration.'
1463 #
1464 # double check that repr and friends are not the mixin's or various
1465 # things break (such as pickle)
1466 # however, if the method is defined in the Enum itself, don't replace
1467 # it
1468 enum_class = type(cls_name, (etype, ), body, boundary=boundary, _simple=True)
1469 for name in ('__repr__', '__str__', '__format__', '__reduce_ex__'):
1470 if name in body:
1471 continue
1472 class_method = getattr(enum_class, name)
1473 obj_method = getattr(member_type, name, None)
1474 enum_method = getattr(etype, name, None)
1475 if obj_method is not None and obj_method is class_method:
1476 setattr(enum_class, name, enum_method)
1477 gnv_last_values = []
1478 if issubclass(enum_class, Flag):
1479 # Flag / IntFlag
1480 single_bits = multi_bits = 0
1481 for name, value in attrs.items():
1482 if isinstance(value, auto) and auto.value is _auto_null:
1483 value = gnv(name, 1, len(member_names), gnv_last_values)
1484 if value in value2member_map:
1485 # an alias to an existing member
1486 redirect = property()
1487 redirect.__set_name__(enum_class, name)
1488 setattr(enum_class, name, redirect)
1489 member_map[name] = value2member_map[value]
1490 else:
1491 # create the member
1492 if use_args:
1493 if not isinstance(value, tuple):
1494 value = (value, )
1495 member = new_member(enum_class, *value)
1496 value = value[0]
1497 else:
1498 member = new_member(enum_class)
1499 if __new__ is None:
1500 member._value_ = value
1501 member._name_ = name
1502 member.__objclass__ = enum_class
1503 member.__init__(value)
1504 redirect = property()
1505 redirect.__set_name__(enum_class, name)
1506 setattr(enum_class, name, redirect)
1507 member_map[name] = member
1508 member._sort_order_ = len(member_names)
1509 value2member_map[value] = member
1510 if _is_single_bit(value):
1511 # not a multi-bit alias, record in _member_names_ and _flag_mask_
1512 member_names.append(name)
1513 single_bits |= value
1514 else:
1515 multi_bits |= value
1516 gnv_last_values.append(value)
1517 enum_class._flag_mask_ = single_bits
1518 enum_class._all_bits_ = 2 ** ((single_bits|multi_bits).bit_length()) - 1
1519 # set correct __iter__
1520 member_list = [m._value_ for m in enum_class]
1521 if member_list != sorted(member_list):
1522 enum_class._iter_member_ = enum_class._iter_member_by_def_
1523 else:
1524 # Enum / IntEnum / StrEnum
1525 for name, value in attrs.items():
1526 if isinstance(value, auto):
1527 if value.value is _auto_null:
1528 value.value = gnv(name, 1, len(member_names), gnv_last_values)
1529 value = value.value
1530 if value in value2member_map:
1531 # an alias to an existing member
1532 redirect = property()
1533 redirect.__set_name__(enum_class, name)
1534 setattr(enum_class, name, redirect)
1535 member_map[name] = value2member_map[value]
1536 else:
1537 # create the member
1538 if use_args:
1539 if not isinstance(value, tuple):
1540 value = (value, )
1541 member = new_member(enum_class, *value)
1542 value = value[0]
1543 else:
1544 member = new_member(enum_class)
1545 if __new__ is None:
1546 member._value_ = value
1547 member._name_ = name
1548 member.__objclass__ = enum_class
1549 member.__init__(value)
1550 member._sort_order_ = len(member_names)
1551 redirect = property()
1552 redirect.__set_name__(enum_class, name)
1553 setattr(enum_class, name, redirect)
1554 member_map[name] = member
1555 value2member_map[value] = member
1556 member_names.append(name)
1557 gnv_last_values.append(value)
1558 if '__new__' in body:
1559 enum_class.__new_member__ = enum_class.__new__
1560 enum_class.__new__ = Enum.__new__
1561 return enum_class
1562 return convert_class
1563
Ethan Furman74964862021-06-10 07:24:20 -07001564@_simple_enum(StrEnum)
1565class EnumCheck:
1566 """
1567 various conditions to check an enumeration for
1568 """
1569 CONTINUOUS = "no skipped integer values"
1570 NAMED_FLAGS = "multi-flag aliases may not contain unnamed flags"
1571 UNIQUE = "one name per value"
1572CONTINUOUS, NAMED_FLAGS, UNIQUE = EnumCheck
1573
1574
1575class verify:
1576 """
1577 Check an enumeration for various constraints. (see EnumCheck)
1578 """
1579 def __init__(self, *checks):
1580 self.checks = checks
1581 def __call__(self, enumeration):
1582 checks = self.checks
1583 cls_name = enumeration.__name__
1584 if Flag is not None and issubclass(enumeration, Flag):
1585 enum_type = 'flag'
1586 elif issubclass(enumeration, Enum):
1587 enum_type = 'enum'
1588 else:
1589 raise TypeError("the 'verify' decorator only works with Enum and Flag")
1590 for check in checks:
1591 if check is UNIQUE:
1592 # check for duplicate names
1593 duplicates = []
1594 for name, member in enumeration.__members__.items():
1595 if name != member.name:
1596 duplicates.append((name, member.name))
1597 if duplicates:
1598 alias_details = ', '.join(
1599 ["%s -> %s" % (alias, name) for (alias, name) in duplicates])
1600 raise ValueError('aliases found in %r: %s' %
1601 (enumeration, alias_details))
1602 elif check is CONTINUOUS:
1603 values = set(e.value for e in enumeration)
1604 if len(values) < 2:
1605 continue
1606 low, high = min(values), max(values)
1607 missing = []
1608 if enum_type == 'flag':
1609 # check for powers of two
1610 for i in range(_high_bit(low)+1, _high_bit(high)):
1611 if 2**i not in values:
1612 missing.append(2**i)
1613 elif enum_type == 'enum':
1614 # check for powers of one
1615 for i in range(low+1, high):
1616 if i not in values:
1617 missing.append(i)
1618 else:
1619 raise Exception('verify: unknown type %r' % enum_type)
1620 if missing:
1621 raise ValueError('invalid %s %r: missing values %s' % (
1622 enum_type, cls_name, ', '.join((str(m) for m in missing)))
1623 )
1624 elif check is NAMED_FLAGS:
1625 # examine each alias and check for unnamed flags
1626 member_names = enumeration._member_names_
1627 member_values = [m.value for m in enumeration]
1628 missing = []
1629 for name, alias in enumeration._member_map_.items():
1630 if name in member_names:
1631 # not an alias
1632 continue
1633 values = list(_iter_bits_lsb(alias.value))
1634 missed = [v for v in values if v not in member_values]
1635 if missed:
1636 plural = ('', 's')[len(missed) > 1]
1637 a = ('a ', '')[len(missed) > 1]
1638 missing.append('%r is missing %snamed flag%s for value%s %s' % (
1639 name, a, plural, plural,
1640 ', '.join(str(v) for v in missed)
1641 ))
1642 if missing:
1643 raise ValueError(
1644 'invalid Flag %r: %s'
1645 % (cls_name, '; '.join(missing))
1646 )
1647 return enumeration
1648
Ethan Furmana02cb472021-04-21 10:20:44 -07001649def _test_simple_enum(checked_enum, simple_enum):
1650 """
1651 A function that can be used to test an enum created with :func:`_simple_enum`
1652 against the version created by subclassing :class:`Enum`::
1653
1654 >>> from enum import Enum, _simple_enum, _test_simple_enum
1655 >>> @_simple_enum(Enum)
1656 ... class Color:
1657 ... RED = auto()
1658 ... GREEN = auto()
1659 ... BLUE = auto()
1660 >>> class CheckedColor(Enum):
1661 ... RED = auto()
1662 ... GREEN = auto()
1663 ... BLUE = auto()
1664 >>> _test_simple_enum(CheckedColor, Color)
1665
1666 If differences are found, a :exc:`TypeError` is raised.
1667 """
1668 failed = []
1669 if checked_enum.__dict__ != simple_enum.__dict__:
1670 checked_dict = checked_enum.__dict__
1671 checked_keys = list(checked_dict.keys())
1672 simple_dict = simple_enum.__dict__
1673 simple_keys = list(simple_dict.keys())
1674 member_names = set(
1675 list(checked_enum._member_map_.keys())
1676 + list(simple_enum._member_map_.keys())
1677 )
1678 for key in set(checked_keys + simple_keys):
1679 if key in ('__module__', '_member_map_', '_value2member_map_'):
1680 # keys known to be different
1681 continue
1682 elif key in member_names:
1683 # members are checked below
1684 continue
1685 elif key not in simple_keys:
1686 failed.append("missing key: %r" % (key, ))
1687 elif key not in checked_keys:
1688 failed.append("extra key: %r" % (key, ))
1689 else:
1690 checked_value = checked_dict[key]
1691 simple_value = simple_dict[key]
1692 if callable(checked_value):
1693 continue
1694 if key == '__doc__':
1695 # remove all spaces/tabs
1696 compressed_checked_value = checked_value.replace(' ','').replace('\t','')
1697 compressed_simple_value = simple_value.replace(' ','').replace('\t','')
1698 if compressed_checked_value != compressed_simple_value:
1699 failed.append("%r:\n %s\n %s" % (
1700 key,
1701 "checked -> %r" % (checked_value, ),
1702 "simple -> %r" % (simple_value, ),
1703 ))
1704 elif checked_value != simple_value:
1705 failed.append("%r:\n %s\n %s" % (
1706 key,
1707 "checked -> %r" % (checked_value, ),
1708 "simple -> %r" % (simple_value, ),
1709 ))
1710 failed.sort()
1711 for name in member_names:
1712 failed_member = []
1713 if name not in simple_keys:
1714 failed.append('missing member from simple enum: %r' % name)
1715 elif name not in checked_keys:
1716 failed.append('extra member in simple enum: %r' % name)
1717 else:
1718 checked_member_dict = checked_enum[name].__dict__
1719 checked_member_keys = list(checked_member_dict.keys())
1720 simple_member_dict = simple_enum[name].__dict__
1721 simple_member_keys = list(simple_member_dict.keys())
1722 for key in set(checked_member_keys + simple_member_keys):
Ethan Furman6c681e12021-04-23 19:08:22 -07001723 if key in ('__module__', '__objclass__', '_inverted_'):
1724 # keys known to be different or absent
Ethan Furmana02cb472021-04-21 10:20:44 -07001725 continue
1726 elif key not in simple_member_keys:
1727 failed_member.append("missing key %r not in the simple enum member %r" % (key, name))
1728 elif key not in checked_member_keys:
1729 failed_member.append("extra key %r in simple enum member %r" % (key, name))
1730 else:
1731 checked_value = checked_member_dict[key]
1732 simple_value = simple_member_dict[key]
1733 if checked_value != simple_value:
1734 failed_member.append("%r:\n %s\n %s" % (
1735 key,
1736 "checked member -> %r" % (checked_value, ),
1737 "simple member -> %r" % (simple_value, ),
1738 ))
1739 if failed_member:
1740 failed.append('%r member mismatch:\n %s' % (
1741 name, '\n '.join(failed_member),
1742 ))
1743 for method in (
1744 '__str__', '__repr__', '__reduce_ex__', '__format__',
1745 '__getnewargs_ex__', '__getnewargs__', '__reduce_ex__', '__reduce__'
1746 ):
1747 if method in simple_keys and method in checked_keys:
1748 # cannot compare functions, and it exists in both, so we're good
1749 continue
1750 elif method not in simple_keys and method not in checked_keys:
1751 # method is inherited -- check it out
1752 checked_method = getattr(checked_enum, method, None)
1753 simple_method = getattr(simple_enum, method, None)
1754 if hasattr(checked_method, '__func__'):
1755 checked_method = checked_method.__func__
1756 simple_method = simple_method.__func__
1757 if checked_method != simple_method:
1758 failed.append("%r: %-30s %s" % (
1759 method,
1760 "checked -> %r" % (checked_method, ),
1761 "simple -> %r" % (simple_method, ),
1762 ))
1763 else:
1764 # if the method existed in only one of the enums, it will have been caught
1765 # in the first checks above
1766 pass
1767 if failed:
1768 raise TypeError('enum mismatch:\n %s' % '\n '.join(failed))
1769
1770def _old_convert_(etype, name, module, filter, source=None, *, boundary=None):
1771 """
1772 Create a new Enum subclass that replaces a collection of global constants
1773 """
1774 # convert all constants from source (or module) that pass filter() to
1775 # a new Enum called name, and export the enum and its members back to
1776 # module;
1777 # also, replace the __reduce_ex__ method so unpickling works in
1778 # previous Python versions
1779 module_globals = sys.modules[module].__dict__
1780 if source:
1781 source = source.__dict__
1782 else:
1783 source = module_globals
1784 # _value2member_map_ is populated in the same order every time
1785 # for a consistent reverse mapping of number to name when there
1786 # are multiple names for the same number.
1787 members = [
1788 (name, value)
1789 for name, value in source.items()
1790 if filter(name)]
1791 try:
1792 # sort by value
1793 members.sort(key=lambda t: (t[1], t[0]))
1794 except TypeError:
1795 # unless some values aren't comparable, in which case sort by name
1796 members.sort(key=lambda t: t[0])
1797 cls = etype(name, members, module=module, boundary=boundary or KEEP)
1798 cls.__reduce_ex__ = _reduce_ex_by_name
1799 cls.__repr__ = global_enum_repr
1800 return cls