blob: 476e3b31ba61cfca5ed1426dec0546ebb713e361 [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
Martin Panter19e69c52015-11-14 12:46:42 +000011__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):
67 raise ValueError('_names_ are reserved for future Enum use')
Ethan Furman101e0742013-09-15 12:34:36 -070068 elif _is_dunder(key):
69 pass
70 elif key in self._member_names:
71 # descriptor overwriting an enum?
72 raise TypeError('Attempted to reuse key: %r' % key)
73 elif not _is_descriptor(value):
74 if key in self:
75 # enum overwriting a descriptor?
76 raise TypeError('Key already defined as: %r' % self[key])
Ethan Furman6b3d64a2013-06-14 16:55:46 -070077 self._member_names.append(key)
78 super().__setitem__(key, value)
79
80
Ethan Furman101e0742013-09-15 12:34:36 -070081
Ezio Melotti9a3777e2013-08-17 15:53:55 +030082# Dummy value for Enum as EnumMeta explicitly checks for it, but of course
83# until EnumMeta finishes running the first time the Enum class doesn't exist.
84# This is also why there are checks in EnumMeta like `if Enum is not None`
Ethan Furman6b3d64a2013-06-14 16:55:46 -070085Enum = None
86
87
88class EnumMeta(type):
89 """Metaclass for Enum"""
90 @classmethod
91 def __prepare__(metacls, cls, bases):
92 return _EnumDict()
93
94 def __new__(metacls, cls, bases, classdict):
95 # an Enum class is final once enumeration items have been defined; it
96 # cannot be mixed with other types (int, float, etc.) if it has an
97 # inherited __new__ unless a new __new__ is defined (or the resulting
98 # class will fail).
99 member_type, first_enum = metacls._get_mixins_(bases)
100 __new__, save_new, use_args = metacls._find_new_(classdict, member_type,
101 first_enum)
102
103 # save enum items into separate mapping so they don't get baked into
104 # the new class
105 members = {k: classdict[k] for k in classdict._member_names}
106 for name in classdict._member_names:
107 del classdict[name]
108
109 # check for illegal enum names (any others?)
110 invalid_names = set(members) & {'mro', }
111 if invalid_names:
112 raise ValueError('Invalid enum member name: {0}'.format(
113 ','.join(invalid_names)))
114
Ethan Furman48a724f2015-04-11 23:23:06 -0700115 # create a default docstring if one has not been provided
116 if '__doc__' not in classdict:
117 classdict['__doc__'] = 'An enumeration.'
118
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700119 # create our new Enum type
120 enum_class = super().__new__(metacls, cls, bases, classdict)
Ethan Furman520ad572013-07-19 19:47:21 -0700121 enum_class._member_names_ = [] # names in definition order
122 enum_class._member_map_ = OrderedDict() # name->value map
Ethan Furman5e5a8232013-08-04 08:42:23 -0700123 enum_class._member_type_ = member_type
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700124
Ethan Furman354ecf12015-03-11 08:43:12 -0700125 # save attributes from super classes so we know if we can take
126 # the shortcut of storing members in the class dict
127 base_attributes = {a for b in bases for a in b.__dict__}
128
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700129 # Reverse value->name map for hashable values.
Ethan Furman520ad572013-07-19 19:47:21 -0700130 enum_class._value2member_map_ = {}
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700131
Ethan Furman2da95042014-03-03 12:42:52 -0800132 # If a custom type is mixed into the Enum, and it does not know how
133 # to pickle itself, pickle.dumps will succeed but pickle.loads will
134 # fail. Rather than have the error show up later and possibly far
135 # from the source, sabotage the pickle protocol for this class so
136 # that pickle.dumps also fails.
137 #
138 # However, if the new class implements its own __reduce_ex__, do not
139 # sabotage -- it's on them to make sure it works correctly. We use
140 # __reduce_ex__ instead of any of the others as it is preferred by
141 # pickle over __reduce__, and it handles all pickle protocols.
142 if '__reduce_ex__' not in classdict:
Ethan Furmandc870522014-02-18 12:37:12 -0800143 if member_type is not object:
144 methods = ('__getnewargs_ex__', '__getnewargs__',
145 '__reduce_ex__', '__reduce__')
Ethan Furman2da95042014-03-03 12:42:52 -0800146 if not any(m in member_type.__dict__ for m in methods):
Ethan Furmandc870522014-02-18 12:37:12 -0800147 _make_class_unpicklable(enum_class)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700148
149 # instantiate them, checking for duplicates as we go
150 # we instantiate first instead of checking for duplicates first in case
151 # a custom __new__ is doing something funky with the values -- such as
152 # auto-numbering ;)
153 for member_name in classdict._member_names:
154 value = members[member_name]
155 if not isinstance(value, tuple):
156 args = (value, )
157 else:
158 args = value
159 if member_type is tuple: # special case for tuple enums
160 args = (args, ) # wrap it one more time
161 if not use_args:
162 enum_member = __new__(enum_class)
Ethan Furmanb41803e2013-07-25 13:50:45 -0700163 if not hasattr(enum_member, '_value_'):
164 enum_member._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700165 else:
166 enum_member = __new__(enum_class, *args)
Ethan Furmanb41803e2013-07-25 13:50:45 -0700167 if not hasattr(enum_member, '_value_'):
168 enum_member._value_ = member_type(*args)
Ethan Furman520ad572013-07-19 19:47:21 -0700169 value = enum_member._value_
Ethan Furman520ad572013-07-19 19:47:21 -0700170 enum_member._name_ = member_name
Ethan Furmanc850f342013-09-15 16:59:35 -0700171 enum_member.__objclass__ = enum_class
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700172 enum_member.__init__(*args)
173 # If another member with the same value was already defined, the
174 # new member becomes an alias to the existing one.
Ethan Furman520ad572013-07-19 19:47:21 -0700175 for name, canonical_member in enum_class._member_map_.items():
Ethan Furman0081f232014-09-16 17:31:23 -0700176 if canonical_member._value_ == enum_member._value_:
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700177 enum_member = canonical_member
178 break
179 else:
180 # Aliases don't appear in member names (only in __members__).
Ethan Furman520ad572013-07-19 19:47:21 -0700181 enum_class._member_names_.append(member_name)
Ethan Furman354ecf12015-03-11 08:43:12 -0700182 # performance boost for any member that would not shadow
183 # a DynamicClassAttribute
184 if member_name not in base_attributes:
185 setattr(enum_class, member_name, enum_member)
186 # now add to _member_map_
Ethan Furman520ad572013-07-19 19:47:21 -0700187 enum_class._member_map_[member_name] = enum_member
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700188 try:
189 # This may fail if value is not hashable. We can't add the value
190 # to the map, and by-value lookups for this value will be
191 # linear.
Ethan Furman520ad572013-07-19 19:47:21 -0700192 enum_class._value2member_map_[value] = enum_member
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700193 except TypeError:
194 pass
195
196 # double check that repr and friends are not the mixin's or various
197 # things break (such as pickle)
Ethan Furmandc870522014-02-18 12:37:12 -0800198 for name in ('__repr__', '__str__', '__format__', '__reduce_ex__'):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700199 class_method = getattr(enum_class, name)
200 obj_method = getattr(member_type, name, None)
201 enum_method = getattr(first_enum, name, None)
202 if obj_method is not None and obj_method is class_method:
203 setattr(enum_class, name, enum_method)
204
205 # replace any other __new__ with our own (as long as Enum is not None,
206 # anyway) -- again, this is to support pickle
207 if Enum is not None:
208 # if the user defined their own __new__, save it before it gets
209 # clobbered in case they subclass later
210 if save_new:
211 enum_class.__new_member__ = __new__
212 enum_class.__new__ = Enum.__new__
213 return enum_class
214
Ethan Furman5de67b12016-04-13 23:52:09 -0700215 def __bool__(self):
216 """
217 classes/types should always be True.
218 """
219 return True
220
Ethan Furmand9925a12014-09-16 20:35:55 -0700221 def __call__(cls, value, names=None, *, module=None, qualname=None, type=None, start=1):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700222 """Either returns an existing member, or creates a new enum class.
223
224 This method is used both when an enum class is given a value to match
225 to an enumeration member (i.e. Color(3)) and for the functional API
226 (i.e. Color = Enum('Color', names='red green blue')).
227
Ethan Furman2da95042014-03-03 12:42:52 -0800228 When used for the functional API:
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700229
Ethan Furman2da95042014-03-03 12:42:52 -0800230 `value` will be the name of the new class.
231
232 `names` should be either a string of white-space/comma delimited names
Ethan Furmand9925a12014-09-16 20:35:55 -0700233 (values will start at `start`), or an iterator/mapping of name, value pairs.
Ethan Furman2da95042014-03-03 12:42:52 -0800234
235 `module` should be set to the module this class is being created in;
236 if it is not set, an attempt to find that module will be made, but if
237 it fails the class will not be picklable.
238
239 `qualname` should be set to the actual location this class can be found
240 at in its module; by default it is set to the global scope. If this is
241 not correct, unpickling will fail in some circumstances.
242
243 `type`, if set, will be mixed in as the first base class.
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700244
245 """
246 if names is None: # simple value lookup
247 return cls.__new__(cls, value)
248 # otherwise, functional API: we're creating a new Enum type
Ethan Furmand9925a12014-09-16 20:35:55 -0700249 return cls._create_(value, names, module=module, qualname=qualname, type=type, start=start)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700250
251 def __contains__(cls, member):
Ethan Furman0081f232014-09-16 17:31:23 -0700252 return isinstance(member, cls) and member._name_ in cls._member_map_
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700253
Ethan Furman64a99722013-09-22 16:18:19 -0700254 def __delattr__(cls, attr):
255 # nicer error message when someone tries to delete an attribute
256 # (see issue19025).
257 if attr in cls._member_map_:
258 raise AttributeError(
259 "%s: cannot delete Enum member." % cls.__name__)
260 super().__delattr__(attr)
261
Ethan Furman388a3922013-08-12 06:51:41 -0700262 def __dir__(self):
Ethan Furman64a99722013-09-22 16:18:19 -0700263 return (['__class__', '__doc__', '__members__', '__module__'] +
264 self._member_names_)
Ethan Furman388a3922013-08-12 06:51:41 -0700265
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700266 def __getattr__(cls, name):
267 """Return the enum member matching `name`
268
269 We use __getattr__ instead of descriptors or inserting into the enum
270 class' __dict__ in order to support `name` and `value` being both
271 properties for enum members (which live in the class' __dict__) and
272 enum members themselves.
273
274 """
275 if _is_dunder(name):
276 raise AttributeError(name)
277 try:
Ethan Furman520ad572013-07-19 19:47:21 -0700278 return cls._member_map_[name]
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700279 except KeyError:
280 raise AttributeError(name) from None
281
282 def __getitem__(cls, name):
Ethan Furman520ad572013-07-19 19:47:21 -0700283 return cls._member_map_[name]
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700284
285 def __iter__(cls):
Ethan Furman520ad572013-07-19 19:47:21 -0700286 return (cls._member_map_[name] for name in cls._member_names_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700287
288 def __len__(cls):
Ethan Furman520ad572013-07-19 19:47:21 -0700289 return len(cls._member_names_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700290
Ethan Furman2131a4a2013-09-14 18:11:24 -0700291 @property
292 def __members__(cls):
293 """Returns a mapping of member name->value.
294
295 This mapping lists all enum members, including aliases. Note that this
296 is a read-only view of the internal mapping.
297
298 """
299 return MappingProxyType(cls._member_map_)
300
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700301 def __repr__(cls):
302 return "<enum %r>" % cls.__name__
303
Ethan Furman2131a4a2013-09-14 18:11:24 -0700304 def __reversed__(cls):
305 return (cls._member_map_[name] for name in reversed(cls._member_names_))
306
Ethan Furmanf203f2d2013-09-06 07:16:48 -0700307 def __setattr__(cls, name, value):
308 """Block attempts to reassign Enum members.
309
310 A simple assignment to the class namespace only changes one of the
311 several possible ways to get an Enum member from the Enum class,
312 resulting in an inconsistent Enumeration.
313
314 """
315 member_map = cls.__dict__.get('_member_map_', {})
316 if name in member_map:
317 raise AttributeError('Cannot reassign members.')
318 super().__setattr__(name, value)
319
Ethan Furmand9925a12014-09-16 20:35:55 -0700320 def _create_(cls, class_name, names=None, *, module=None, qualname=None, type=None, start=1):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700321 """Convenience method to create a new Enum class.
322
323 `names` can be:
324
325 * A string containing member names, separated either with spaces or
Ethan Furmand9925a12014-09-16 20:35:55 -0700326 commas. Values are incremented by 1 from `start`.
327 * An iterable of member names. Values are incremented by 1 from `start`.
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700328 * An iterable of (member name, value) pairs.
Ethan Furmand9925a12014-09-16 20:35:55 -0700329 * A mapping of member name -> value pairs.
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700330
331 """
332 metacls = cls.__class__
333 bases = (cls, ) if type is None else (type, cls)
334 classdict = metacls.__prepare__(class_name, bases)
335
336 # special processing needed for names?
337 if isinstance(names, str):
338 names = names.replace(',', ' ').split()
339 if isinstance(names, (tuple, list)) and isinstance(names[0], str):
Ethan Furmand9925a12014-09-16 20:35:55 -0700340 names = [(e, i) for (i, e) in enumerate(names, start)]
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700341
342 # Here, names is either an iterable of (name, value) or a mapping.
343 for item in names:
344 if isinstance(item, str):
345 member_name, member_value = item, names[item]
346 else:
347 member_name, member_value = item
348 classdict[member_name] = member_value
349 enum_class = metacls.__new__(metacls, class_name, bases, classdict)
350
351 # TODO: replace the frame hack if a blessed way to know the calling
352 # module is ever developed
353 if module is None:
354 try:
355 module = sys._getframe(2).f_globals['__name__']
356 except (AttributeError, ValueError) as exc:
357 pass
358 if module is None:
359 _make_class_unpicklable(enum_class)
360 else:
361 enum_class.__module__ = module
Ethan Furmanca1b7942014-02-08 11:36:27 -0800362 if qualname is not None:
363 enum_class.__qualname__ = qualname
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700364
365 return enum_class
366
367 @staticmethod
368 def _get_mixins_(bases):
369 """Returns the type for creating enum members, and the first inherited
370 enum class.
371
372 bases: the tuple of bases that was given to __new__
373
374 """
375 if not bases:
376 return object, Enum
377
378 # double check that we are not subclassing a class with existing
379 # enumeration members; while we're at it, see if any other data
380 # type has been mixed in so we can use the correct __new__
381 member_type = first_enum = None
382 for base in bases:
383 if (base is not Enum and
384 issubclass(base, Enum) and
Ethan Furman520ad572013-07-19 19:47:21 -0700385 base._member_names_):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700386 raise TypeError("Cannot extend enumerations")
387 # base is now the last base in bases
388 if not issubclass(base, Enum):
389 raise TypeError("new enumerations must be created as "
390 "`ClassName([mixin_type,] enum_type)`")
391
392 # get correct mix-in type (either mix-in type of Enum subclass, or
393 # first base if last base is Enum)
394 if not issubclass(bases[0], Enum):
395 member_type = bases[0] # first data type
396 first_enum = bases[-1] # enum type
397 else:
398 for base in bases[0].__mro__:
399 # most common: (IntEnum, int, Enum, object)
400 # possible: (<Enum 'AutoIntEnum'>, <Enum 'IntEnum'>,
401 # <class 'int'>, <Enum 'Enum'>,
402 # <class 'object'>)
403 if issubclass(base, Enum):
404 if first_enum is None:
405 first_enum = base
406 else:
407 if member_type is None:
408 member_type = base
409
410 return member_type, first_enum
411
412 @staticmethod
413 def _find_new_(classdict, member_type, first_enum):
414 """Returns the __new__ to be used for creating the enum members.
415
416 classdict: the class dictionary given to __new__
417 member_type: the data type whose __new__ will be used by default
418 first_enum: enumeration to check for an overriding __new__
419
420 """
421 # now find the correct __new__, checking to see of one was defined
422 # by the user; also check earlier enum classes in case a __new__ was
423 # saved as __new_member__
424 __new__ = classdict.get('__new__', None)
425
426 # should __new__ be saved as __new_member__ later?
427 save_new = __new__ is not None
428
429 if __new__ is None:
430 # check all possibles for __new_member__ before falling back to
431 # __new__
432 for method in ('__new_member__', '__new__'):
433 for possible in (member_type, first_enum):
434 target = getattr(possible, method, None)
435 if target not in {
436 None,
437 None.__new__,
438 object.__new__,
439 Enum.__new__,
440 }:
441 __new__ = target
442 break
443 if __new__ is not None:
444 break
445 else:
446 __new__ = object.__new__
447
448 # if a non-object.__new__ is used then whatever value/tuple was
449 # assigned to the enum member name will be passed to __new__ and to the
450 # new enum member's __init__
451 if __new__ is object.__new__:
452 use_args = False
453 else:
454 use_args = True
455
456 return __new__, save_new, use_args
457
458
459class Enum(metaclass=EnumMeta):
460 """Generic enumeration.
461
462 Derive from this class to define new enumerations.
463
464 """
465 def __new__(cls, value):
466 # all enum instances are actually created during class construction
467 # without calling this method; this method is called by the metaclass'
468 # __call__ (i.e. Color(3) ), and by pickle
469 if type(value) is cls:
470 # For lookups like Color(Color.red)
471 return value
472 # by-value search for a matching enum member
473 # see if it's in the reverse mapping (for hashable values)
Ethan Furman2aa27322013-07-19 19:35:56 -0700474 try:
Ethan Furman520ad572013-07-19 19:47:21 -0700475 if value in cls._value2member_map_:
476 return cls._value2member_map_[value]
Ethan Furman2aa27322013-07-19 19:35:56 -0700477 except TypeError:
478 # not there, now do long search -- O(n) behavior
Ethan Furman520ad572013-07-19 19:47:21 -0700479 for member in cls._member_map_.values():
Ethan Furman0081f232014-09-16 17:31:23 -0700480 if member._value_ == value:
Ethan Furman2aa27322013-07-19 19:35:56 -0700481 return member
Ethan Furman0081f232014-09-16 17:31:23 -0700482 raise ValueError("%r is not a valid %s" % (value, cls.__name__))
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700483
484 def __repr__(self):
485 return "<%s.%s: %r>" % (
Ethan Furman520ad572013-07-19 19:47:21 -0700486 self.__class__.__name__, self._name_, self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700487
488 def __str__(self):
Ethan Furman520ad572013-07-19 19:47:21 -0700489 return "%s.%s" % (self.__class__.__name__, self._name_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700490
Ethan Furman388a3922013-08-12 06:51:41 -0700491 def __dir__(self):
Ethan Furman0ae550b2014-10-14 08:58:32 -0700492 added_behavior = [
493 m
494 for cls in self.__class__.mro()
495 for m in cls.__dict__
Ethan Furman354ecf12015-03-11 08:43:12 -0700496 if m[0] != '_' and m not in self._member_map_
Ethan Furman0ae550b2014-10-14 08:58:32 -0700497 ]
Ethan Furmanec5f8eb2014-10-21 13:40:35 -0700498 return (['__class__', '__doc__', '__module__'] + added_behavior)
Ethan Furman388a3922013-08-12 06:51:41 -0700499
Ethan Furmanec15a822013-08-31 19:17:41 -0700500 def __format__(self, format_spec):
501 # mixed-in Enums should use the mixed-in type's __format__, otherwise
502 # we can get strange results with the Enum name showing up instead of
503 # the value
504
505 # pure Enum branch
506 if self._member_type_ is object:
507 cls = str
508 val = str(self)
509 # mix-in branch
510 else:
511 cls = self._member_type_
Ethan Furman0081f232014-09-16 17:31:23 -0700512 val = self._value_
Ethan Furmanec15a822013-08-31 19:17:41 -0700513 return cls.__format__(val, format_spec)
514
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700515 def __hash__(self):
Ethan Furman520ad572013-07-19 19:47:21 -0700516 return hash(self._name_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700517
Ethan Furmanca1b7942014-02-08 11:36:27 -0800518 def __reduce_ex__(self, proto):
Ethan Furmandc870522014-02-18 12:37:12 -0800519 return self.__class__, (self._value_, )
Ethan Furmanca1b7942014-02-08 11:36:27 -0800520
Ethan Furman33918c12013-09-27 23:02:02 -0700521 # DynamicClassAttribute is used to provide access to the `name` and
522 # `value` properties of enum members while keeping some measure of
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700523 # protection from modification, while still allowing for an enumeration
524 # to have members named `name` and `value`. This works because enumeration
525 # members are not set directly on the enum class -- __getattr__ is
526 # used to look them up.
527
Ethan Furmane03ea372013-09-25 07:14:41 -0700528 @DynamicClassAttribute
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700529 def name(self):
Ethan Furmanc850f342013-09-15 16:59:35 -0700530 """The name of the Enum member."""
Ethan Furman520ad572013-07-19 19:47:21 -0700531 return self._name_
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700532
Ethan Furmane03ea372013-09-25 07:14:41 -0700533 @DynamicClassAttribute
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700534 def value(self):
Ethan Furmanc850f342013-09-15 16:59:35 -0700535 """The value of the Enum member."""
Ethan Furman520ad572013-07-19 19:47:21 -0700536 return self._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700537
Ethan Furman24e837f2015-03-18 17:27:57 -0700538 @classmethod
539 def _convert(cls, name, module, filter, source=None):
540 """
541 Create a new Enum subclass that replaces a collection of global constants
542 """
543 # convert all constants from source (or module) that pass filter() to
544 # a new Enum called name, and export the enum and its members back to
545 # module;
546 # also, replace the __reduce_ex__ method so unpickling works in
547 # previous Python versions
548 module_globals = vars(sys.modules[module])
549 if source:
550 source = vars(source)
551 else:
552 source = module_globals
553 members = {name: value for name, value in source.items()
554 if filter(name)}
555 cls = cls(name, members, module=module)
556 cls.__reduce_ex__ = _reduce_ex_by_name
557 module_globals.update(cls.__members__)
558 module_globals[name] = cls
559 return cls
560
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700561
562class IntEnum(int, Enum):
563 """Enum where members are also (and must be) ints"""
Ethan Furmanf24bb352013-07-18 17:05:39 -0700564
565
Ethan Furman24e837f2015-03-18 17:27:57 -0700566def _reduce_ex_by_name(self, proto):
567 return self.name
568
Ethan Furmanf24bb352013-07-18 17:05:39 -0700569def unique(enumeration):
570 """Class decorator for enumerations ensuring unique member values."""
571 duplicates = []
572 for name, member in enumeration.__members__.items():
573 if name != member.name:
574 duplicates.append((name, member.name))
575 if duplicates:
576 alias_details = ', '.join(
577 ["%s -> %s" % (alias, name) for (alias, name) in duplicates])
578 raise ValueError('duplicate values found in %r: %s' %
579 (enumeration, alias_details))
580 return enumeration