blob: e7889a8dc77113289ed0917da988bdac54c59186 [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 Furman332dbc72016-08-20 00:00:52 -070011__all__ = ['EnumMeta', 'Enum', 'IntEnum', 'unique']
Ethan Furman6b3d64a2013-06-14 16:55:46 -070012
13
Ethan Furman101e0742013-09-15 12:34:36 -070014def _is_descriptor(obj):
15 """Returns True if obj is a descriptor, False otherwise."""
16 return (
17 hasattr(obj, '__get__') or
18 hasattr(obj, '__set__') or
19 hasattr(obj, '__delete__'))
20
21
Ethan Furman6b3d64a2013-06-14 16:55:46 -070022def _is_dunder(name):
23 """Returns True if a __dunder__ name, False otherwise."""
24 return (name[:2] == name[-2:] == '__' and
25 name[2:3] != '_' and
Ethan Furman648f8602013-10-06 17:19:54 -070026 name[-3:-2] != '_' and
27 len(name) > 4)
Ethan Furman6b3d64a2013-06-14 16:55:46 -070028
29
30def _is_sunder(name):
31 """Returns True if a _sunder_ name, False otherwise."""
32 return (name[0] == name[-1] == '_' and
33 name[1:2] != '_' and
Ethan Furman648f8602013-10-06 17:19:54 -070034 name[-2:-1] != '_' and
35 len(name) > 2)
Ethan Furman6b3d64a2013-06-14 16:55:46 -070036
37
38def _make_class_unpicklable(cls):
39 """Make the given class un-picklable."""
Ethan Furmanca1b7942014-02-08 11:36:27 -080040 def _break_on_call_reduce(self, proto):
Ethan Furman6b3d64a2013-06-14 16:55:46 -070041 raise TypeError('%r cannot be pickled' % self)
Ethan Furmanca1b7942014-02-08 11:36:27 -080042 cls.__reduce_ex__ = _break_on_call_reduce
Ethan Furman6b3d64a2013-06-14 16:55:46 -070043 cls.__module__ = '<unknown>'
44
Ethan Furman101e0742013-09-15 12:34:36 -070045
Ethan Furman6b3d64a2013-06-14 16:55:46 -070046class _EnumDict(dict):
Ethan Furman101e0742013-09-15 12:34:36 -070047 """Track enum member order and ensure member names are not reused.
Ethan Furman6b3d64a2013-06-14 16:55:46 -070048
49 EnumMeta will use the names found in self._member_names as the
50 enumeration member names.
51
52 """
53 def __init__(self):
54 super().__init__()
55 self._member_names = []
56
57 def __setitem__(self, key, value):
Ethan Furman101e0742013-09-15 12:34:36 -070058 """Changes anything not dundered or not a descriptor.
Ethan Furman6b3d64a2013-06-14 16:55:46 -070059
60 If an enum member name is used twice, an error is raised; duplicate
61 values are not checked for.
62
63 Single underscore (sunder) names are reserved.
64
65 """
66 if _is_sunder(key):
Ethan Furmane8e61272016-08-20 07:19:31 -070067 if key not in ('_order_', ):
68 raise ValueError('_names_ are reserved for future Enum use')
Ethan Furman101e0742013-09-15 12:34:36 -070069 elif _is_dunder(key):
Ethan Furmane8e61272016-08-20 07:19:31 -070070 if key == '__order__':
71 key = '_order_'
Ethan Furman101e0742013-09-15 12:34:36 -070072 elif key in self._member_names:
73 # descriptor overwriting an enum?
74 raise TypeError('Attempted to reuse key: %r' % key)
75 elif not _is_descriptor(value):
76 if key in self:
77 # enum overwriting a descriptor?
Ethan Furman332dbc72016-08-20 00:00:52 -070078 raise TypeError('Key already defined as: %r' % self[key])
Ethan Furman6b3d64a2013-06-14 16:55:46 -070079 self._member_names.append(key)
80 super().__setitem__(key, value)
81
82
Ethan Furman101e0742013-09-15 12:34:36 -070083
Ezio Melotti9a3777e2013-08-17 15:53:55 +030084# Dummy value for Enum as EnumMeta explicitly checks for it, but of course
85# until EnumMeta finishes running the first time the Enum class doesn't exist.
86# This is also why there are checks in EnumMeta like `if Enum is not None`
Ethan Furman6b3d64a2013-06-14 16:55:46 -070087Enum = None
88
Ethan Furman332dbc72016-08-20 00:00:52 -070089
Ethan Furman6b3d64a2013-06-14 16:55:46 -070090class EnumMeta(type):
91 """Metaclass for Enum"""
92 @classmethod
Ethan Furman332dbc72016-08-20 00:00:52 -070093 def __prepare__(metacls, cls, bases):
94 return _EnumDict()
Ethan Furman6b3d64a2013-06-14 16:55:46 -070095
Ethan Furman332dbc72016-08-20 00:00:52 -070096 def __new__(metacls, cls, bases, classdict):
Ethan Furman6b3d64a2013-06-14 16:55:46 -070097 # an Enum class is final once enumeration items have been defined; it
98 # cannot be mixed with other types (int, float, etc.) if it has an
99 # inherited __new__ unless a new __new__ is defined (or the resulting
100 # class will fail).
101 member_type, first_enum = metacls._get_mixins_(bases)
102 __new__, save_new, use_args = metacls._find_new_(classdict, member_type,
103 first_enum)
104
105 # save enum items into separate mapping so they don't get baked into
106 # the new class
Ethan Furman332dbc72016-08-20 00:00:52 -0700107 members = {k: classdict[k] for k in classdict._member_names}
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700108 for name in classdict._member_names:
109 del classdict[name]
110
Ethan Furmane8e61272016-08-20 07:19:31 -0700111 # adjust the sunders
112 _order_ = classdict.pop('_order_', None)
113
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700114 # check for illegal enum names (any others?)
Ethan Furman332dbc72016-08-20 00:00:52 -0700115 invalid_names = set(members) & {'mro', }
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700116 if invalid_names:
117 raise ValueError('Invalid enum member name: {0}'.format(
118 ','.join(invalid_names)))
119
Ethan Furman48a724f2015-04-11 23:23:06 -0700120 # create a default docstring if one has not been provided
121 if '__doc__' not in classdict:
122 classdict['__doc__'] = 'An enumeration.'
123
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700124 # create our new Enum type
125 enum_class = super().__new__(metacls, cls, bases, classdict)
Ethan Furman520ad572013-07-19 19:47:21 -0700126 enum_class._member_names_ = [] # names in definition order
127 enum_class._member_map_ = OrderedDict() # name->value map
Ethan Furman5e5a8232013-08-04 08:42:23 -0700128 enum_class._member_type_ = member_type
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700129
Ethan Furman354ecf12015-03-11 08:43:12 -0700130 # save attributes from super classes so we know if we can take
131 # the shortcut of storing members in the class dict
Ethan Furman3803ad42016-05-01 10:03:53 -0700132 base_attributes = {a for b in enum_class.mro() for a in b.__dict__}
Ethan Furman354ecf12015-03-11 08:43:12 -0700133
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700134 # Reverse value->name map for hashable values.
Ethan Furman520ad572013-07-19 19:47:21 -0700135 enum_class._value2member_map_ = {}
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700136
Ethan Furman2da95042014-03-03 12:42:52 -0800137 # If a custom type is mixed into the Enum, and it does not know how
138 # to pickle itself, pickle.dumps will succeed but pickle.loads will
139 # fail. Rather than have the error show up later and possibly far
140 # from the source, sabotage the pickle protocol for this class so
141 # that pickle.dumps also fails.
142 #
143 # However, if the new class implements its own __reduce_ex__, do not
144 # sabotage -- it's on them to make sure it works correctly. We use
145 # __reduce_ex__ instead of any of the others as it is preferred by
146 # pickle over __reduce__, and it handles all pickle protocols.
147 if '__reduce_ex__' not in classdict:
Ethan Furmandc870522014-02-18 12:37:12 -0800148 if member_type is not object:
149 methods = ('__getnewargs_ex__', '__getnewargs__',
150 '__reduce_ex__', '__reduce__')
Ethan Furman2da95042014-03-03 12:42:52 -0800151 if not any(m in member_type.__dict__ for m in methods):
Ethan Furmandc870522014-02-18 12:37:12 -0800152 _make_class_unpicklable(enum_class)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700153
154 # instantiate them, checking for duplicates as we go
155 # we instantiate first instead of checking for duplicates first in case
156 # a custom __new__ is doing something funky with the values -- such as
157 # auto-numbering ;)
158 for member_name in classdict._member_names:
Ethan Furman332dbc72016-08-20 00:00:52 -0700159 value = members[member_name]
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700160 if not isinstance(value, tuple):
161 args = (value, )
162 else:
163 args = value
164 if member_type is tuple: # special case for tuple enums
165 args = (args, ) # wrap it one more time
166 if not use_args:
167 enum_member = __new__(enum_class)
Ethan Furmanb41803e2013-07-25 13:50:45 -0700168 if not hasattr(enum_member, '_value_'):
169 enum_member._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700170 else:
171 enum_member = __new__(enum_class, *args)
Ethan Furmanb41803e2013-07-25 13:50:45 -0700172 if not hasattr(enum_member, '_value_'):
Ethan Furman332dbc72016-08-20 00:00:52 -0700173 enum_member._value_ = member_type(*args)
Ethan Furman520ad572013-07-19 19:47:21 -0700174 value = enum_member._value_
Ethan Furman520ad572013-07-19 19:47:21 -0700175 enum_member._name_ = member_name
Ethan Furmanc850f342013-09-15 16:59:35 -0700176 enum_member.__objclass__ = enum_class
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700177 enum_member.__init__(*args)
178 # If another member with the same value was already defined, the
179 # new member becomes an alias to the existing one.
Ethan Furman520ad572013-07-19 19:47:21 -0700180 for name, canonical_member in enum_class._member_map_.items():
Ethan Furman0081f232014-09-16 17:31:23 -0700181 if canonical_member._value_ == enum_member._value_:
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700182 enum_member = canonical_member
183 break
184 else:
185 # Aliases don't appear in member names (only in __members__).
Ethan Furman520ad572013-07-19 19:47:21 -0700186 enum_class._member_names_.append(member_name)
Ethan Furman354ecf12015-03-11 08:43:12 -0700187 # performance boost for any member that would not shadow
188 # a DynamicClassAttribute
189 if member_name not in base_attributes:
190 setattr(enum_class, member_name, enum_member)
191 # now add to _member_map_
Ethan Furman520ad572013-07-19 19:47:21 -0700192 enum_class._member_map_[member_name] = enum_member
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700193 try:
194 # This may fail if value is not hashable. We can't add the value
195 # to the map, and by-value lookups for this value will be
196 # linear.
Ethan Furman520ad572013-07-19 19:47:21 -0700197 enum_class._value2member_map_[value] = enum_member
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700198 except TypeError:
199 pass
200
201 # double check that repr and friends are not the mixin's or various
202 # things break (such as pickle)
Ethan Furmandc870522014-02-18 12:37:12 -0800203 for name in ('__repr__', '__str__', '__format__', '__reduce_ex__'):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700204 class_method = getattr(enum_class, name)
205 obj_method = getattr(member_type, name, None)
206 enum_method = getattr(first_enum, name, None)
207 if obj_method is not None and obj_method is class_method:
208 setattr(enum_class, name, enum_method)
209
210 # replace any other __new__ with our own (as long as Enum is not None,
211 # anyway) -- again, this is to support pickle
212 if Enum is not None:
213 # if the user defined their own __new__, save it before it gets
214 # clobbered in case they subclass later
215 if save_new:
216 enum_class.__new_member__ = __new__
217 enum_class.__new__ = Enum.__new__
Ethan Furmane8e61272016-08-20 07:19:31 -0700218
219 # py3 support for definition order (helps keep py2/py3 code in sync)
220 if _order_ is not None:
221 if isinstance(_order_, str):
222 _order_ = _order_.replace(',', ' ').split()
223 if _order_ != enum_class._member_names_:
224 raise TypeError('member order does not match _order_')
225
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700226 return enum_class
227
Ethan Furman5de67b12016-04-13 23:52:09 -0700228 def __bool__(self):
229 """
230 classes/types should always be True.
231 """
232 return True
233
Ethan Furmand9925a12014-09-16 20:35:55 -0700234 def __call__(cls, value, names=None, *, module=None, qualname=None, type=None, start=1):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700235 """Either returns an existing member, or creates a new enum class.
236
237 This method is used both when an enum class is given a value to match
238 to an enumeration member (i.e. Color(3)) and for the functional API
239 (i.e. Color = Enum('Color', names='red green blue')).
240
Ethan Furman2da95042014-03-03 12:42:52 -0800241 When used for the functional API:
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700242
Ethan Furman2da95042014-03-03 12:42:52 -0800243 `value` will be the name of the new class.
244
245 `names` should be either a string of white-space/comma delimited names
Ethan Furmand9925a12014-09-16 20:35:55 -0700246 (values will start at `start`), or an iterator/mapping of name, value pairs.
Ethan Furman2da95042014-03-03 12:42:52 -0800247
248 `module` should be set to the module this class is being created in;
249 if it is not set, an attempt to find that module will be made, but if
250 it fails the class will not be picklable.
251
252 `qualname` should be set to the actual location this class can be found
253 at in its module; by default it is set to the global scope. If this is
254 not correct, unpickling will fail in some circumstances.
255
256 `type`, if set, will be mixed in as the first base class.
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700257
258 """
259 if names is None: # simple value lookup
260 return cls.__new__(cls, value)
261 # otherwise, functional API: we're creating a new Enum type
Ethan Furmand9925a12014-09-16 20:35:55 -0700262 return cls._create_(value, names, module=module, qualname=qualname, type=type, start=start)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700263
264 def __contains__(cls, member):
Ethan Furman0081f232014-09-16 17:31:23 -0700265 return isinstance(member, cls) and member._name_ in cls._member_map_
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700266
Ethan Furman64a99722013-09-22 16:18:19 -0700267 def __delattr__(cls, attr):
268 # nicer error message when someone tries to delete an attribute
269 # (see issue19025).
270 if attr in cls._member_map_:
271 raise AttributeError(
272 "%s: cannot delete Enum member." % cls.__name__)
273 super().__delattr__(attr)
274
Ethan Furman388a3922013-08-12 06:51:41 -0700275 def __dir__(self):
Ethan Furman64a99722013-09-22 16:18:19 -0700276 return (['__class__', '__doc__', '__members__', '__module__'] +
277 self._member_names_)
Ethan Furman388a3922013-08-12 06:51:41 -0700278
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700279 def __getattr__(cls, name):
280 """Return the enum member matching `name`
281
282 We use __getattr__ instead of descriptors or inserting into the enum
283 class' __dict__ in order to support `name` and `value` being both
284 properties for enum members (which live in the class' __dict__) and
285 enum members themselves.
286
287 """
288 if _is_dunder(name):
289 raise AttributeError(name)
290 try:
Ethan Furman520ad572013-07-19 19:47:21 -0700291 return cls._member_map_[name]
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700292 except KeyError:
293 raise AttributeError(name) from None
294
295 def __getitem__(cls, name):
Ethan Furman520ad572013-07-19 19:47:21 -0700296 return cls._member_map_[name]
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700297
298 def __iter__(cls):
Ethan Furman520ad572013-07-19 19:47:21 -0700299 return (cls._member_map_[name] for name in cls._member_names_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700300
301 def __len__(cls):
Ethan Furman520ad572013-07-19 19:47:21 -0700302 return len(cls._member_names_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700303
Ethan Furman2131a4a2013-09-14 18:11:24 -0700304 @property
305 def __members__(cls):
306 """Returns a mapping of member name->value.
307
308 This mapping lists all enum members, including aliases. Note that this
309 is a read-only view of the internal mapping.
310
311 """
312 return MappingProxyType(cls._member_map_)
313
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700314 def __repr__(cls):
315 return "<enum %r>" % cls.__name__
316
Ethan Furman2131a4a2013-09-14 18:11:24 -0700317 def __reversed__(cls):
318 return (cls._member_map_[name] for name in reversed(cls._member_names_))
319
Ethan Furmanf203f2d2013-09-06 07:16:48 -0700320 def __setattr__(cls, name, value):
321 """Block attempts to reassign Enum members.
322
323 A simple assignment to the class namespace only changes one of the
324 several possible ways to get an Enum member from the Enum class,
325 resulting in an inconsistent Enumeration.
326
327 """
328 member_map = cls.__dict__.get('_member_map_', {})
329 if name in member_map:
330 raise AttributeError('Cannot reassign members.')
331 super().__setattr__(name, value)
332
Ethan Furmand9925a12014-09-16 20:35:55 -0700333 def _create_(cls, class_name, names=None, *, module=None, qualname=None, type=None, start=1):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700334 """Convenience method to create a new Enum class.
335
336 `names` can be:
337
338 * A string containing member names, separated either with spaces or
Ethan Furmand9925a12014-09-16 20:35:55 -0700339 commas. Values are incremented by 1 from `start`.
340 * An iterable of member names. Values are incremented by 1 from `start`.
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700341 * An iterable of (member name, value) pairs.
Ethan Furmand9925a12014-09-16 20:35:55 -0700342 * A mapping of member name -> value pairs.
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700343
344 """
345 metacls = cls.__class__
346 bases = (cls, ) if type is None else (type, cls)
347 classdict = metacls.__prepare__(class_name, bases)
348
349 # special processing needed for names?
350 if isinstance(names, str):
351 names = names.replace(',', ' ').split()
352 if isinstance(names, (tuple, list)) and isinstance(names[0], str):
Ethan Furmand9925a12014-09-16 20:35:55 -0700353 names = [(e, i) for (i, e) in enumerate(names, start)]
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700354
355 # Here, names is either an iterable of (name, value) or a mapping.
356 for item in names:
357 if isinstance(item, str):
358 member_name, member_value = item, names[item]
359 else:
360 member_name, member_value = item
361 classdict[member_name] = member_value
362 enum_class = metacls.__new__(metacls, class_name, bases, classdict)
363
364 # TODO: replace the frame hack if a blessed way to know the calling
365 # module is ever developed
366 if module is None:
367 try:
368 module = sys._getframe(2).f_globals['__name__']
369 except (AttributeError, ValueError) as exc:
370 pass
371 if module is None:
372 _make_class_unpicklable(enum_class)
373 else:
374 enum_class.__module__ = module
Ethan Furmanca1b7942014-02-08 11:36:27 -0800375 if qualname is not None:
376 enum_class.__qualname__ = qualname
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700377
378 return enum_class
379
380 @staticmethod
381 def _get_mixins_(bases):
382 """Returns the type for creating enum members, and the first inherited
383 enum class.
384
385 bases: the tuple of bases that was given to __new__
386
387 """
388 if not bases:
389 return object, Enum
390
391 # double check that we are not subclassing a class with existing
392 # enumeration members; while we're at it, see if any other data
393 # type has been mixed in so we can use the correct __new__
394 member_type = first_enum = None
395 for base in bases:
396 if (base is not Enum and
397 issubclass(base, Enum) and
Ethan Furman520ad572013-07-19 19:47:21 -0700398 base._member_names_):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700399 raise TypeError("Cannot extend enumerations")
400 # base is now the last base in bases
401 if not issubclass(base, Enum):
402 raise TypeError("new enumerations must be created as "
403 "`ClassName([mixin_type,] enum_type)`")
404
405 # get correct mix-in type (either mix-in type of Enum subclass, or
406 # first base if last base is Enum)
407 if not issubclass(bases[0], Enum):
408 member_type = bases[0] # first data type
409 first_enum = bases[-1] # enum type
410 else:
411 for base in bases[0].__mro__:
412 # most common: (IntEnum, int, Enum, object)
413 # possible: (<Enum 'AutoIntEnum'>, <Enum 'IntEnum'>,
414 # <class 'int'>, <Enum 'Enum'>,
415 # <class 'object'>)
416 if issubclass(base, Enum):
417 if first_enum is None:
418 first_enum = base
419 else:
420 if member_type is None:
421 member_type = base
422
423 return member_type, first_enum
424
425 @staticmethod
426 def _find_new_(classdict, member_type, first_enum):
427 """Returns the __new__ to be used for creating the enum members.
428
429 classdict: the class dictionary given to __new__
430 member_type: the data type whose __new__ will be used by default
431 first_enum: enumeration to check for an overriding __new__
432
433 """
434 # now find the correct __new__, checking to see of one was defined
435 # by the user; also check earlier enum classes in case a __new__ was
436 # saved as __new_member__
437 __new__ = classdict.get('__new__', None)
438
439 # should __new__ be saved as __new_member__ later?
440 save_new = __new__ is not None
441
442 if __new__ is None:
443 # check all possibles for __new_member__ before falling back to
444 # __new__
445 for method in ('__new_member__', '__new__'):
446 for possible in (member_type, first_enum):
447 target = getattr(possible, method, None)
448 if target not in {
449 None,
450 None.__new__,
451 object.__new__,
452 Enum.__new__,
453 }:
454 __new__ = target
455 break
456 if __new__ is not None:
457 break
458 else:
459 __new__ = object.__new__
460
461 # if a non-object.__new__ is used then whatever value/tuple was
462 # assigned to the enum member name will be passed to __new__ and to the
463 # new enum member's __init__
464 if __new__ is object.__new__:
465 use_args = False
466 else:
467 use_args = True
468
469 return __new__, save_new, use_args
470
471
472class Enum(metaclass=EnumMeta):
473 """Generic enumeration.
474
475 Derive from this class to define new enumerations.
476
477 """
478 def __new__(cls, value):
479 # all enum instances are actually created during class construction
480 # without calling this method; this method is called by the metaclass'
481 # __call__ (i.e. Color(3) ), and by pickle
482 if type(value) is cls:
483 # For lookups like Color(Color.red)
484 return value
485 # by-value search for a matching enum member
486 # see if it's in the reverse mapping (for hashable values)
Ethan Furman2aa27322013-07-19 19:35:56 -0700487 try:
Ethan Furman520ad572013-07-19 19:47:21 -0700488 if value in cls._value2member_map_:
489 return cls._value2member_map_[value]
Ethan Furman2aa27322013-07-19 19:35:56 -0700490 except TypeError:
491 # not there, now do long search -- O(n) behavior
Ethan Furman520ad572013-07-19 19:47:21 -0700492 for member in cls._member_map_.values():
Ethan Furman0081f232014-09-16 17:31:23 -0700493 if member._value_ == value:
Ethan Furman2aa27322013-07-19 19:35:56 -0700494 return member
Ethan Furman0081f232014-09-16 17:31:23 -0700495 raise ValueError("%r is not a valid %s" % (value, cls.__name__))
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700496
497 def __repr__(self):
498 return "<%s.%s: %r>" % (
Ethan Furman520ad572013-07-19 19:47:21 -0700499 self.__class__.__name__, self._name_, self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700500
501 def __str__(self):
Ethan Furman520ad572013-07-19 19:47:21 -0700502 return "%s.%s" % (self.__class__.__name__, self._name_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700503
Ethan Furman388a3922013-08-12 06:51:41 -0700504 def __dir__(self):
Ethan Furman0ae550b2014-10-14 08:58:32 -0700505 added_behavior = [
506 m
507 for cls in self.__class__.mro()
508 for m in cls.__dict__
Ethan Furman354ecf12015-03-11 08:43:12 -0700509 if m[0] != '_' and m not in self._member_map_
Ethan Furman0ae550b2014-10-14 08:58:32 -0700510 ]
Ethan Furmanec5f8eb2014-10-21 13:40:35 -0700511 return (['__class__', '__doc__', '__module__'] + added_behavior)
Ethan Furman388a3922013-08-12 06:51:41 -0700512
Ethan Furmanec15a822013-08-31 19:17:41 -0700513 def __format__(self, format_spec):
514 # mixed-in Enums should use the mixed-in type's __format__, otherwise
515 # we can get strange results with the Enum name showing up instead of
516 # the value
517
518 # pure Enum branch
519 if self._member_type_ is object:
520 cls = str
521 val = str(self)
522 # mix-in branch
523 else:
524 cls = self._member_type_
Ethan Furman0081f232014-09-16 17:31:23 -0700525 val = self._value_
Ethan Furmanec15a822013-08-31 19:17:41 -0700526 return cls.__format__(val, format_spec)
527
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700528 def __hash__(self):
Ethan Furman520ad572013-07-19 19:47:21 -0700529 return hash(self._name_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700530
Ethan Furmanca1b7942014-02-08 11:36:27 -0800531 def __reduce_ex__(self, proto):
Ethan Furmandc870522014-02-18 12:37:12 -0800532 return self.__class__, (self._value_, )
Ethan Furmanca1b7942014-02-08 11:36:27 -0800533
Ethan Furman33918c12013-09-27 23:02:02 -0700534 # DynamicClassAttribute is used to provide access to the `name` and
535 # `value` properties of enum members while keeping some measure of
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700536 # protection from modification, while still allowing for an enumeration
537 # to have members named `name` and `value`. This works because enumeration
538 # members are not set directly on the enum class -- __getattr__ is
539 # used to look them up.
540
Ethan Furmane03ea372013-09-25 07:14:41 -0700541 @DynamicClassAttribute
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700542 def name(self):
Ethan Furmanc850f342013-09-15 16:59:35 -0700543 """The name of the Enum member."""
Ethan Furman520ad572013-07-19 19:47:21 -0700544 return self._name_
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700545
Ethan Furmane03ea372013-09-25 07:14:41 -0700546 @DynamicClassAttribute
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700547 def value(self):
Ethan Furmanc850f342013-09-15 16:59:35 -0700548 """The value of the Enum member."""
Ethan Furman520ad572013-07-19 19:47:21 -0700549 return self._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700550
Ethan Furman24e837f2015-03-18 17:27:57 -0700551 @classmethod
552 def _convert(cls, name, module, filter, source=None):
553 """
554 Create a new Enum subclass that replaces a collection of global constants
555 """
556 # convert all constants from source (or module) that pass filter() to
557 # a new Enum called name, and export the enum and its members back to
558 # module;
559 # also, replace the __reduce_ex__ method so unpickling works in
560 # previous Python versions
561 module_globals = vars(sys.modules[module])
562 if source:
563 source = vars(source)
564 else:
565 source = module_globals
Gregory P. Smith ext:(%20%5BGoogle%20Inc.%5D)6f20bd62016-06-03 19:14:52 +0000566 # We use an OrderedDict of sorted source keys so that the
567 # _value2member_map is populated in the same order every time
568 # for a consistent reverse mapping of number to name when there
569 # are multiple names for the same number rather than varying
570 # between runs due to hash randomization of the module dictionary.
571 members = OrderedDict((name, source[name])
572 for name in sorted(source.keys())
573 if filter(name))
Ethan Furman24e837f2015-03-18 17:27:57 -0700574 cls = cls(name, members, module=module)
575 cls.__reduce_ex__ = _reduce_ex_by_name
576 module_globals.update(cls.__members__)
577 module_globals[name] = cls
578 return cls
579
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700580
581class IntEnum(int, Enum):
582 """Enum where members are also (and must be) ints"""
Ethan Furmanf24bb352013-07-18 17:05:39 -0700583
584
Ethan Furman24e837f2015-03-18 17:27:57 -0700585def _reduce_ex_by_name(self, proto):
586 return self.name
587
Ethan Furmanf24bb352013-07-18 17:05:39 -0700588def unique(enumeration):
589 """Class decorator for enumerations ensuring unique member values."""
590 duplicates = []
591 for name, member in enumeration.__members__.items():
592 if name != member.name:
593 duplicates.append((name, member.name))
594 if duplicates:
595 alias_details = ', '.join(
596 ["%s -> %s" % (alias, name) for (alias, name) in duplicates])
597 raise ValueError('duplicate values found in %r: %s' %
598 (enumeration, alias_details))
599 return enumeration