blob: eaf50403d2c2b1a1b55e06d2ff113cc4f2d35434 [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 Furmanc7915072015-09-17 22:55:40 -07004# try _collections first to reduce startup cost
Ethan Furmane5754ab2015-09-17 22:03:52 -07005try:
6 from _collections import OrderedDict
7except ImportError:
8 from collections import OrderedDict
9
10
Ethan Furman73fc5862016-08-05 16:03:16 -070011__all__ = [
12 'EnumMeta', 'Enum', 'IntEnum', 'AutoEnum', 'unique',
13 ]
Ethan Furman6b3d64a2013-06-14 16:55:46 -070014
15
Ethan Furman101e0742013-09-15 12:34:36 -070016def _is_descriptor(obj):
17 """Returns True if obj is a descriptor, False otherwise."""
18 return (
19 hasattr(obj, '__get__') or
20 hasattr(obj, '__set__') or
21 hasattr(obj, '__delete__'))
22
23
Ethan Furman6b3d64a2013-06-14 16:55:46 -070024def _is_dunder(name):
25 """Returns True if a __dunder__ name, False otherwise."""
26 return (name[:2] == name[-2:] == '__' and
27 name[2:3] != '_' and
Ethan Furman648f8602013-10-06 17:19:54 -070028 name[-3:-2] != '_' and
29 len(name) > 4)
Ethan Furman6b3d64a2013-06-14 16:55:46 -070030
31
32def _is_sunder(name):
33 """Returns True if a _sunder_ name, False otherwise."""
34 return (name[0] == name[-1] == '_' and
35 name[1:2] != '_' and
Ethan Furman648f8602013-10-06 17:19:54 -070036 name[-2:-1] != '_' and
37 len(name) > 2)
Ethan Furman6b3d64a2013-06-14 16:55:46 -070038
39
40def _make_class_unpicklable(cls):
41 """Make the given class un-picklable."""
Ethan Furmanca1b7942014-02-08 11:36:27 -080042 def _break_on_call_reduce(self, proto):
Ethan Furman6b3d64a2013-06-14 16:55:46 -070043 raise TypeError('%r cannot be pickled' % self)
Ethan Furmanca1b7942014-02-08 11:36:27 -080044 cls.__reduce_ex__ = _break_on_call_reduce
Ethan Furman6b3d64a2013-06-14 16:55:46 -070045 cls.__module__ = '<unknown>'
46
Ethan Furman101e0742013-09-15 12:34:36 -070047
Ethan Furman6b3d64a2013-06-14 16:55:46 -070048class _EnumDict(dict):
Ethan Furman101e0742013-09-15 12:34:36 -070049 """Track enum member order and ensure member names are not reused.
Ethan Furman6b3d64a2013-06-14 16:55:46 -070050
51 EnumMeta will use the names found in self._member_names as the
52 enumeration member names.
53
54 """
55 def __init__(self):
56 super().__init__()
Ethan Furman73fc5862016-08-05 16:03:16 -070057 # list of enum members
Ethan Furman6b3d64a2013-06-14 16:55:46 -070058 self._member_names = []
Ethan Furman73fc5862016-08-05 16:03:16 -070059 # starting value
60 self._start = None
61 # last assigned value
62 self._last_value = None
63 # when the magic turns off
64 self._locked = True
65 # list of temporary names
66 self._ignore = []
67
68 def __getitem__(self, key):
69 if (
70 self._generate_next_value_ is None
71 or self._locked
72 or key in self
73 or key in self._ignore
74 or _is_sunder(key)
75 or _is_dunder(key)
76 ):
77 return super(_EnumDict, self).__getitem__(key)
78 next_value = self._generate_next_value_(key, self._start, len(self._member_names), self._last_value)
79 self[key] = next_value
80 return next_value
Ethan Furman6b3d64a2013-06-14 16:55:46 -070081
82 def __setitem__(self, key, value):
Ethan Furman101e0742013-09-15 12:34:36 -070083 """Changes anything not dundered or not a descriptor.
Ethan Furman6b3d64a2013-06-14 16:55:46 -070084
85 If an enum member name is used twice, an error is raised; duplicate
86 values are not checked for.
87
88 Single underscore (sunder) names are reserved.
89
90 """
91 if _is_sunder(key):
Ethan Furman73fc5862016-08-05 16:03:16 -070092 if key not in ('_settings_', '_order_', '_ignore_', '_start_', '_generate_next_value_'):
93 raise ValueError('_names_ are reserved for future Enum use')
94 elif key == '_generate_next_value_':
95 if isinstance(value, staticmethod):
96 value = value.__get__(None, self)
97 self._generate_next_value_ = value
98 self._locked = False
99 elif key == '_ignore_':
100 if isinstance(value, str):
101 value = value.split()
102 else:
103 value = list(value)
104 self._ignore = value
105 already = set(value) & set(self._member_names)
106 if already:
107 raise ValueError(
108 '_ignore_ cannot specify already set names: %r'
109 % (already, ))
110 elif key == '_start_':
111 self._start = value
112 self._locked = False
Ethan Furman101e0742013-09-15 12:34:36 -0700113 elif _is_dunder(key):
Ethan Furman73fc5862016-08-05 16:03:16 -0700114 if key == '__order__':
115 key = '_order_'
116 if _is_descriptor(value):
117 self._locked = True
Ethan Furman101e0742013-09-15 12:34:36 -0700118 elif key in self._member_names:
119 # descriptor overwriting an enum?
120 raise TypeError('Attempted to reuse key: %r' % key)
Ethan Furman73fc5862016-08-05 16:03:16 -0700121 elif key in self._ignore:
122 pass
Ethan Furman101e0742013-09-15 12:34:36 -0700123 elif not _is_descriptor(value):
124 if key in self:
125 # enum overwriting a descriptor?
Ethan Furman73fc5862016-08-05 16:03:16 -0700126 raise TypeError('%r already defined as: %r' % (key, self[key]))
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700127 self._member_names.append(key)
Ethan Furman73fc5862016-08-05 16:03:16 -0700128 if self._generate_next_value_ is not None:
129 self._last_value = value
130 else:
131 # not a new member, turn off the autoassign magic
132 self._locked = True
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700133 super().__setitem__(key, value)
134
Ethan Furman73fc5862016-08-05 16:03:16 -0700135 # for magic "auto values" an Enum class should specify a `_generate_next_value_`
136 # method; that method will be used to generate missing values, and is
137 # implicitly a staticmethod;
138 # the signature should be `def _generate_next_value_(name, last_value)`
139 # last_value will be the last value created and/or assigned, or None
140 _generate_next_value_ = None
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700141
Ethan Furman101e0742013-09-15 12:34:36 -0700142
Ezio Melotti9a3777e2013-08-17 15:53:55 +0300143# Dummy value for Enum as EnumMeta explicitly checks for it, but of course
144# until EnumMeta finishes running the first time the Enum class doesn't exist.
145# This is also why there are checks in EnumMeta like `if Enum is not None`
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700146Enum = None
147
Ethan Furman73fc5862016-08-05 16:03:16 -0700148_ignore_sentinel = object()
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700149class EnumMeta(type):
150 """Metaclass for Enum"""
151 @classmethod
Ethan Furman73fc5862016-08-05 16:03:16 -0700152 def __prepare__(metacls, cls, bases, start=None, ignore=_ignore_sentinel):
153 # create the namespace dict
154 enum_dict = _EnumDict()
155 # inherit previous flags and _generate_next_value_ function
156 member_type, first_enum = metacls._get_mixins_(bases)
157 if first_enum is not None:
158 enum_dict['_generate_next_value_'] = getattr(first_enum, '_generate_next_value_', None)
159 if start is None:
160 start = getattr(first_enum, '_start_', None)
161 if ignore is _ignore_sentinel:
162 enum_dict['_ignore_'] = 'property classmethod staticmethod'.split()
163 elif ignore:
164 enum_dict['_ignore_'] = ignore
165 if start is not None:
166 enum_dict['_start_'] = start
167 return enum_dict
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700168
Ethan Furman73fc5862016-08-05 16:03:16 -0700169 def __init__(cls, *args , **kwds):
170 super(EnumMeta, cls).__init__(*args)
171
172 def __new__(metacls, cls, bases, classdict, **kwds):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700173 # an Enum class is final once enumeration items have been defined; it
174 # cannot be mixed with other types (int, float, etc.) if it has an
175 # inherited __new__ unless a new __new__ is defined (or the resulting
176 # class will fail).
177 member_type, first_enum = metacls._get_mixins_(bases)
178 __new__, save_new, use_args = metacls._find_new_(classdict, member_type,
179 first_enum)
180
181 # save enum items into separate mapping so they don't get baked into
182 # the new class
Ethan Furman73fc5862016-08-05 16:03:16 -0700183 enum_members = {k: classdict[k] for k in classdict._member_names}
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700184 for name in classdict._member_names:
185 del classdict[name]
186
Ethan Furman73fc5862016-08-05 16:03:16 -0700187 # adjust the sunders
188 _order_ = classdict.pop('_order_', None)
189 classdict.pop('_ignore_', None)
190
191 # py3 support for definition order (helps keep py2/py3 code in sync)
192 if _order_ is not None:
193 if isinstance(_order_, str):
194 _order_ = _order_.replace(',', ' ').split()
195 unique_members = [n for n in clsdict._member_names if n in _order_]
196 if _order_ != unique_members:
197 raise TypeError('member order does not match _order_')
198
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700199 # check for illegal enum names (any others?)
Ethan Furman73fc5862016-08-05 16:03:16 -0700200 invalid_names = set(enum_members) & {'mro', }
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700201 if invalid_names:
202 raise ValueError('Invalid enum member name: {0}'.format(
203 ','.join(invalid_names)))
204
Ethan Furman48a724f2015-04-11 23:23:06 -0700205 # create a default docstring if one has not been provided
206 if '__doc__' not in classdict:
207 classdict['__doc__'] = 'An enumeration.'
208
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700209 # create our new Enum type
210 enum_class = super().__new__(metacls, cls, bases, classdict)
Ethan Furman520ad572013-07-19 19:47:21 -0700211 enum_class._member_names_ = [] # names in definition order
212 enum_class._member_map_ = OrderedDict() # name->value map
Ethan Furman5e5a8232013-08-04 08:42:23 -0700213 enum_class._member_type_ = member_type
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700214
Ethan Furman354ecf12015-03-11 08:43:12 -0700215 # save attributes from super classes so we know if we can take
216 # the shortcut of storing members in the class dict
Ethan Furman3803ad42016-05-01 10:03:53 -0700217 base_attributes = {a for b in enum_class.mro() for a in b.__dict__}
Ethan Furman354ecf12015-03-11 08:43:12 -0700218
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700219 # Reverse value->name map for hashable values.
Ethan Furman520ad572013-07-19 19:47:21 -0700220 enum_class._value2member_map_ = {}
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700221
Ethan Furman2da95042014-03-03 12:42:52 -0800222 # If a custom type is mixed into the Enum, and it does not know how
223 # to pickle itself, pickle.dumps will succeed but pickle.loads will
224 # fail. Rather than have the error show up later and possibly far
225 # from the source, sabotage the pickle protocol for this class so
226 # that pickle.dumps also fails.
227 #
228 # However, if the new class implements its own __reduce_ex__, do not
229 # sabotage -- it's on them to make sure it works correctly. We use
230 # __reduce_ex__ instead of any of the others as it is preferred by
231 # pickle over __reduce__, and it handles all pickle protocols.
232 if '__reduce_ex__' not in classdict:
Ethan Furmandc870522014-02-18 12:37:12 -0800233 if member_type is not object:
234 methods = ('__getnewargs_ex__', '__getnewargs__',
235 '__reduce_ex__', '__reduce__')
Ethan Furman2da95042014-03-03 12:42:52 -0800236 if not any(m in member_type.__dict__ for m in methods):
Ethan Furmandc870522014-02-18 12:37:12 -0800237 _make_class_unpicklable(enum_class)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700238
239 # instantiate them, checking for duplicates as we go
240 # we instantiate first instead of checking for duplicates first in case
241 # a custom __new__ is doing something funky with the values -- such as
242 # auto-numbering ;)
243 for member_name in classdict._member_names:
Ethan Furman73fc5862016-08-05 16:03:16 -0700244 value = enum_members[member_name]
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700245 if not isinstance(value, tuple):
246 args = (value, )
247 else:
248 args = value
249 if member_type is tuple: # special case for tuple enums
250 args = (args, ) # wrap it one more time
251 if not use_args:
252 enum_member = __new__(enum_class)
Ethan Furmanb41803e2013-07-25 13:50:45 -0700253 if not hasattr(enum_member, '_value_'):
254 enum_member._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700255 else:
256 enum_member = __new__(enum_class, *args)
Ethan Furmanb41803e2013-07-25 13:50:45 -0700257 if not hasattr(enum_member, '_value_'):
Ethan Furman73fc5862016-08-05 16:03:16 -0700258 if member_type is object:
259 enum_member._value_ = value
260 else:
261 enum_member._value_ = member_type(*args)
Ethan Furman520ad572013-07-19 19:47:21 -0700262 value = enum_member._value_
Ethan Furman520ad572013-07-19 19:47:21 -0700263 enum_member._name_ = member_name
Ethan Furmanc850f342013-09-15 16:59:35 -0700264 enum_member.__objclass__ = enum_class
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700265 enum_member.__init__(*args)
266 # If another member with the same value was already defined, the
267 # new member becomes an alias to the existing one.
Ethan Furman520ad572013-07-19 19:47:21 -0700268 for name, canonical_member in enum_class._member_map_.items():
Ethan Furman0081f232014-09-16 17:31:23 -0700269 if canonical_member._value_ == enum_member._value_:
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700270 enum_member = canonical_member
271 break
272 else:
273 # Aliases don't appear in member names (only in __members__).
Ethan Furman520ad572013-07-19 19:47:21 -0700274 enum_class._member_names_.append(member_name)
Ethan Furman354ecf12015-03-11 08:43:12 -0700275 # performance boost for any member that would not shadow
276 # a DynamicClassAttribute
277 if member_name not in base_attributes:
278 setattr(enum_class, member_name, enum_member)
279 # now add to _member_map_
Ethan Furman520ad572013-07-19 19:47:21 -0700280 enum_class._member_map_[member_name] = enum_member
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700281 try:
282 # This may fail if value is not hashable. We can't add the value
283 # to the map, and by-value lookups for this value will be
284 # linear.
Ethan Furman520ad572013-07-19 19:47:21 -0700285 enum_class._value2member_map_[value] = enum_member
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700286 except TypeError:
287 pass
288
289 # double check that repr and friends are not the mixin's or various
290 # things break (such as pickle)
Ethan Furmandc870522014-02-18 12:37:12 -0800291 for name in ('__repr__', '__str__', '__format__', '__reduce_ex__'):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700292 class_method = getattr(enum_class, name)
293 obj_method = getattr(member_type, name, None)
294 enum_method = getattr(first_enum, name, None)
295 if obj_method is not None and obj_method is class_method:
296 setattr(enum_class, name, enum_method)
297
298 # replace any other __new__ with our own (as long as Enum is not None,
299 # anyway) -- again, this is to support pickle
300 if Enum is not None:
301 # if the user defined their own __new__, save it before it gets
302 # clobbered in case they subclass later
303 if save_new:
304 enum_class.__new_member__ = __new__
305 enum_class.__new__ = Enum.__new__
306 return enum_class
307
Ethan Furman5de67b12016-04-13 23:52:09 -0700308 def __bool__(self):
309 """
310 classes/types should always be True.
311 """
312 return True
313
Ethan Furmand9925a12014-09-16 20:35:55 -0700314 def __call__(cls, value, names=None, *, module=None, qualname=None, type=None, start=1):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700315 """Either returns an existing member, or creates a new enum class.
316
317 This method is used both when an enum class is given a value to match
318 to an enumeration member (i.e. Color(3)) and for the functional API
319 (i.e. Color = Enum('Color', names='red green blue')).
320
Ethan Furman2da95042014-03-03 12:42:52 -0800321 When used for the functional API:
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700322
Ethan Furman2da95042014-03-03 12:42:52 -0800323 `value` will be the name of the new class.
324
325 `names` should be either a string of white-space/comma delimited names
Ethan Furmand9925a12014-09-16 20:35:55 -0700326 (values will start at `start`), or an iterator/mapping of name, value pairs.
Ethan Furman2da95042014-03-03 12:42:52 -0800327
328 `module` should be set to the module this class is being created in;
329 if it is not set, an attempt to find that module will be made, but if
330 it fails the class will not be picklable.
331
332 `qualname` should be set to the actual location this class can be found
333 at in its module; by default it is set to the global scope. If this is
334 not correct, unpickling will fail in some circumstances.
335
336 `type`, if set, will be mixed in as the first base class.
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700337
338 """
339 if names is None: # simple value lookup
340 return cls.__new__(cls, value)
341 # otherwise, functional API: we're creating a new Enum type
Ethan Furmand9925a12014-09-16 20:35:55 -0700342 return cls._create_(value, names, module=module, qualname=qualname, type=type, start=start)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700343
344 def __contains__(cls, member):
Ethan Furman0081f232014-09-16 17:31:23 -0700345 return isinstance(member, cls) and member._name_ in cls._member_map_
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700346
Ethan Furman64a99722013-09-22 16:18:19 -0700347 def __delattr__(cls, attr):
348 # nicer error message when someone tries to delete an attribute
349 # (see issue19025).
350 if attr in cls._member_map_:
351 raise AttributeError(
352 "%s: cannot delete Enum member." % cls.__name__)
353 super().__delattr__(attr)
354
Ethan Furman388a3922013-08-12 06:51:41 -0700355 def __dir__(self):
Ethan Furman64a99722013-09-22 16:18:19 -0700356 return (['__class__', '__doc__', '__members__', '__module__'] +
357 self._member_names_)
Ethan Furman388a3922013-08-12 06:51:41 -0700358
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700359 def __getattr__(cls, name):
360 """Return the enum member matching `name`
361
362 We use __getattr__ instead of descriptors or inserting into the enum
363 class' __dict__ in order to support `name` and `value` being both
364 properties for enum members (which live in the class' __dict__) and
365 enum members themselves.
366
367 """
368 if _is_dunder(name):
369 raise AttributeError(name)
370 try:
Ethan Furman520ad572013-07-19 19:47:21 -0700371 return cls._member_map_[name]
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700372 except KeyError:
373 raise AttributeError(name) from None
374
375 def __getitem__(cls, name):
Ethan Furman520ad572013-07-19 19:47:21 -0700376 return cls._member_map_[name]
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700377
378 def __iter__(cls):
Ethan Furman520ad572013-07-19 19:47:21 -0700379 return (cls._member_map_[name] for name in cls._member_names_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700380
381 def __len__(cls):
Ethan Furman520ad572013-07-19 19:47:21 -0700382 return len(cls._member_names_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700383
Ethan Furman2131a4a2013-09-14 18:11:24 -0700384 @property
385 def __members__(cls):
386 """Returns a mapping of member name->value.
387
388 This mapping lists all enum members, including aliases. Note that this
389 is a read-only view of the internal mapping.
390
391 """
392 return MappingProxyType(cls._member_map_)
393
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700394 def __repr__(cls):
395 return "<enum %r>" % cls.__name__
396
Ethan Furman2131a4a2013-09-14 18:11:24 -0700397 def __reversed__(cls):
398 return (cls._member_map_[name] for name in reversed(cls._member_names_))
399
Ethan Furmanf203f2d2013-09-06 07:16:48 -0700400 def __setattr__(cls, name, value):
401 """Block attempts to reassign Enum members.
402
403 A simple assignment to the class namespace only changes one of the
404 several possible ways to get an Enum member from the Enum class,
405 resulting in an inconsistent Enumeration.
406
407 """
408 member_map = cls.__dict__.get('_member_map_', {})
409 if name in member_map:
410 raise AttributeError('Cannot reassign members.')
411 super().__setattr__(name, value)
412
Ethan Furmand9925a12014-09-16 20:35:55 -0700413 def _create_(cls, class_name, names=None, *, module=None, qualname=None, type=None, start=1):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700414 """Convenience method to create a new Enum class.
415
416 `names` can be:
417
418 * A string containing member names, separated either with spaces or
Ethan Furmand9925a12014-09-16 20:35:55 -0700419 commas. Values are incremented by 1 from `start`.
420 * An iterable of member names. Values are incremented by 1 from `start`.
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700421 * An iterable of (member name, value) pairs.
Ethan Furmand9925a12014-09-16 20:35:55 -0700422 * A mapping of member name -> value pairs.
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700423
424 """
425 metacls = cls.__class__
426 bases = (cls, ) if type is None else (type, cls)
427 classdict = metacls.__prepare__(class_name, bases)
428
429 # special processing needed for names?
430 if isinstance(names, str):
431 names = names.replace(',', ' ').split()
432 if isinstance(names, (tuple, list)) and isinstance(names[0], str):
Ethan Furmand9925a12014-09-16 20:35:55 -0700433 names = [(e, i) for (i, e) in enumerate(names, start)]
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700434
435 # Here, names is either an iterable of (name, value) or a mapping.
436 for item in names:
437 if isinstance(item, str):
438 member_name, member_value = item, names[item]
439 else:
440 member_name, member_value = item
441 classdict[member_name] = member_value
442 enum_class = metacls.__new__(metacls, class_name, bases, classdict)
443
444 # TODO: replace the frame hack if a blessed way to know the calling
445 # module is ever developed
446 if module is None:
447 try:
448 module = sys._getframe(2).f_globals['__name__']
449 except (AttributeError, ValueError) as exc:
450 pass
451 if module is None:
452 _make_class_unpicklable(enum_class)
453 else:
454 enum_class.__module__ = module
Ethan Furmanca1b7942014-02-08 11:36:27 -0800455 if qualname is not None:
456 enum_class.__qualname__ = qualname
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700457
458 return enum_class
459
460 @staticmethod
461 def _get_mixins_(bases):
462 """Returns the type for creating enum members, and the first inherited
463 enum class.
464
465 bases: the tuple of bases that was given to __new__
466
467 """
468 if not bases:
469 return object, Enum
470
471 # double check that we are not subclassing a class with existing
472 # enumeration members; while we're at it, see if any other data
473 # type has been mixed in so we can use the correct __new__
474 member_type = first_enum = None
475 for base in bases:
476 if (base is not Enum and
477 issubclass(base, Enum) and
Ethan Furman520ad572013-07-19 19:47:21 -0700478 base._member_names_):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700479 raise TypeError("Cannot extend enumerations")
480 # base is now the last base in bases
481 if not issubclass(base, Enum):
482 raise TypeError("new enumerations must be created as "
483 "`ClassName([mixin_type,] enum_type)`")
484
485 # get correct mix-in type (either mix-in type of Enum subclass, or
486 # first base if last base is Enum)
487 if not issubclass(bases[0], Enum):
488 member_type = bases[0] # first data type
489 first_enum = bases[-1] # enum type
490 else:
491 for base in bases[0].__mro__:
492 # most common: (IntEnum, int, Enum, object)
493 # possible: (<Enum 'AutoIntEnum'>, <Enum 'IntEnum'>,
494 # <class 'int'>, <Enum 'Enum'>,
495 # <class 'object'>)
496 if issubclass(base, Enum):
497 if first_enum is None:
498 first_enum = base
499 else:
500 if member_type is None:
501 member_type = base
502
503 return member_type, first_enum
504
505 @staticmethod
506 def _find_new_(classdict, member_type, first_enum):
507 """Returns the __new__ to be used for creating the enum members.
508
509 classdict: the class dictionary given to __new__
510 member_type: the data type whose __new__ will be used by default
511 first_enum: enumeration to check for an overriding __new__
512
513 """
514 # now find the correct __new__, checking to see of one was defined
515 # by the user; also check earlier enum classes in case a __new__ was
516 # saved as __new_member__
517 __new__ = classdict.get('__new__', None)
518
519 # should __new__ be saved as __new_member__ later?
520 save_new = __new__ is not None
521
522 if __new__ is None:
523 # check all possibles for __new_member__ before falling back to
524 # __new__
525 for method in ('__new_member__', '__new__'):
526 for possible in (member_type, first_enum):
527 target = getattr(possible, method, None)
528 if target not in {
529 None,
530 None.__new__,
531 object.__new__,
532 Enum.__new__,
533 }:
534 __new__ = target
535 break
536 if __new__ is not None:
537 break
538 else:
539 __new__ = object.__new__
540
541 # if a non-object.__new__ is used then whatever value/tuple was
542 # assigned to the enum member name will be passed to __new__ and to the
543 # new enum member's __init__
544 if __new__ is object.__new__:
545 use_args = False
546 else:
547 use_args = True
548
549 return __new__, save_new, use_args
550
551
552class Enum(metaclass=EnumMeta):
553 """Generic enumeration.
554
555 Derive from this class to define new enumerations.
556
557 """
558 def __new__(cls, value):
559 # all enum instances are actually created during class construction
560 # without calling this method; this method is called by the metaclass'
561 # __call__ (i.e. Color(3) ), and by pickle
562 if type(value) is cls:
563 # For lookups like Color(Color.red)
564 return value
565 # by-value search for a matching enum member
566 # see if it's in the reverse mapping (for hashable values)
Ethan Furman2aa27322013-07-19 19:35:56 -0700567 try:
Ethan Furman520ad572013-07-19 19:47:21 -0700568 if value in cls._value2member_map_:
569 return cls._value2member_map_[value]
Ethan Furman2aa27322013-07-19 19:35:56 -0700570 except TypeError:
571 # not there, now do long search -- O(n) behavior
Ethan Furman520ad572013-07-19 19:47:21 -0700572 for member in cls._member_map_.values():
Ethan Furman0081f232014-09-16 17:31:23 -0700573 if member._value_ == value:
Ethan Furman2aa27322013-07-19 19:35:56 -0700574 return member
Ethan Furman0081f232014-09-16 17:31:23 -0700575 raise ValueError("%r is not a valid %s" % (value, cls.__name__))
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700576
577 def __repr__(self):
578 return "<%s.%s: %r>" % (
Ethan Furman520ad572013-07-19 19:47:21 -0700579 self.__class__.__name__, self._name_, self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700580
581 def __str__(self):
Ethan Furman520ad572013-07-19 19:47:21 -0700582 return "%s.%s" % (self.__class__.__name__, self._name_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700583
Ethan Furman388a3922013-08-12 06:51:41 -0700584 def __dir__(self):
Ethan Furman0ae550b2014-10-14 08:58:32 -0700585 added_behavior = [
586 m
587 for cls in self.__class__.mro()
588 for m in cls.__dict__
Ethan Furman354ecf12015-03-11 08:43:12 -0700589 if m[0] != '_' and m not in self._member_map_
Ethan Furman0ae550b2014-10-14 08:58:32 -0700590 ]
Ethan Furmanec5f8eb2014-10-21 13:40:35 -0700591 return (['__class__', '__doc__', '__module__'] + added_behavior)
Ethan Furman388a3922013-08-12 06:51:41 -0700592
Ethan Furmanec15a822013-08-31 19:17:41 -0700593 def __format__(self, format_spec):
594 # mixed-in Enums should use the mixed-in type's __format__, otherwise
595 # we can get strange results with the Enum name showing up instead of
596 # the value
597
598 # pure Enum branch
599 if self._member_type_ is object:
600 cls = str
601 val = str(self)
602 # mix-in branch
603 else:
604 cls = self._member_type_
Ethan Furman0081f232014-09-16 17:31:23 -0700605 val = self._value_
Ethan Furmanec15a822013-08-31 19:17:41 -0700606 return cls.__format__(val, format_spec)
607
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700608 def __hash__(self):
Ethan Furman520ad572013-07-19 19:47:21 -0700609 return hash(self._name_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700610
Ethan Furmanca1b7942014-02-08 11:36:27 -0800611 def __reduce_ex__(self, proto):
Ethan Furmandc870522014-02-18 12:37:12 -0800612 return self.__class__, (self._value_, )
Ethan Furmanca1b7942014-02-08 11:36:27 -0800613
Ethan Furman33918c12013-09-27 23:02:02 -0700614 # DynamicClassAttribute is used to provide access to the `name` and
615 # `value` properties of enum members while keeping some measure of
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700616 # protection from modification, while still allowing for an enumeration
617 # to have members named `name` and `value`. This works because enumeration
618 # members are not set directly on the enum class -- __getattr__ is
619 # used to look them up.
620
Ethan Furmane03ea372013-09-25 07:14:41 -0700621 @DynamicClassAttribute
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700622 def name(self):
Ethan Furmanc850f342013-09-15 16:59:35 -0700623 """The name of the Enum member."""
Ethan Furman520ad572013-07-19 19:47:21 -0700624 return self._name_
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700625
Ethan Furmane03ea372013-09-25 07:14:41 -0700626 @DynamicClassAttribute
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700627 def value(self):
Ethan Furmanc850f342013-09-15 16:59:35 -0700628 """The value of the Enum member."""
Ethan Furman520ad572013-07-19 19:47:21 -0700629 return self._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700630
Ethan Furman24e837f2015-03-18 17:27:57 -0700631 @classmethod
632 def _convert(cls, name, module, filter, source=None):
633 """
634 Create a new Enum subclass that replaces a collection of global constants
635 """
636 # convert all constants from source (or module) that pass filter() to
637 # a new Enum called name, and export the enum and its members back to
638 # module;
639 # also, replace the __reduce_ex__ method so unpickling works in
640 # previous Python versions
641 module_globals = vars(sys.modules[module])
642 if source:
643 source = vars(source)
644 else:
645 source = module_globals
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +0000646 # We use an OrderedDict of sorted source keys so that the
647 # _value2member_map is populated in the same order every time
648 # for a consistent reverse mapping of number to name when there
649 # are multiple names for the same number rather than varying
650 # between runs due to hash randomization of the module dictionary.
651 members = OrderedDict((name, source[name])
652 for name in sorted(source.keys())
653 if filter(name))
Ethan Furman24e837f2015-03-18 17:27:57 -0700654 cls = cls(name, members, module=module)
655 cls.__reduce_ex__ = _reduce_ex_by_name
656 module_globals.update(cls.__members__)
657 module_globals[name] = cls
658 return cls
659
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700660
661class IntEnum(int, Enum):
662 """Enum where members are also (and must be) ints"""
Ethan Furmanf24bb352013-07-18 17:05:39 -0700663
664
Ethan Furman24e837f2015-03-18 17:27:57 -0700665def _reduce_ex_by_name(self, proto):
666 return self.name
667
Ethan Furman73fc5862016-08-05 16:03:16 -0700668class AutoEnum(Enum):
669 """Enum where values are automatically assigned."""
670 def _generate_next_value_(name, start, count, last_value):
671 """
672 Generate the next value when not given.
673
674 name: the name of the member
675 start: the initital start value or None
676 count: the number of existing members
677 last_value: the last value assigned or None
678 """
679 # add one to the last assigned value
680 if not count:
681 return start if start is not None else 1
682 return last_value + 1
683
Ethan Furmanf24bb352013-07-18 17:05:39 -0700684def unique(enumeration):
685 """Class decorator for enumerations ensuring unique member values."""
686 duplicates = []
687 for name, member in enumeration.__members__.items():
688 if name != member.name:
689 duplicates.append((name, member.name))
690 if duplicates:
691 alias_details = ', '.join(
692 ["%s -> %s" % (alias, name) for (alias, name) in duplicates])
693 raise ValueError('duplicate values found in %r: %s' %
694 (enumeration, alias_details))
695 return enumeration