blob: 6284b9bb7eb0090773d6ed1f5ba7aaf38a6edd16 [file] [log] [blame]
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001import sys
Ethan Furmane03ea372013-09-25 07:14:41 -07002from types import MappingProxyType, DynamicClassAttribute
Ethan Furman6b3d64a2013-06-14 16:55:46 -07003
Ethan Furmane5754ab2015-09-17 22:03:52 -07004try:
5 from _collections import OrderedDict
6except ImportError:
7 from collections import OrderedDict
8
9
Ethan Furmanf24bb352013-07-18 17:05:39 -070010__all__ = ['Enum', 'IntEnum', 'unique']
Ethan Furman6b3d64a2013-06-14 16:55:46 -070011
12
Ethan Furman101e0742013-09-15 12:34:36 -070013def _is_descriptor(obj):
14 """Returns True if obj is a descriptor, False otherwise."""
15 return (
16 hasattr(obj, '__get__') or
17 hasattr(obj, '__set__') or
18 hasattr(obj, '__delete__'))
19
20
Ethan Furman6b3d64a2013-06-14 16:55:46 -070021def _is_dunder(name):
22 """Returns True if a __dunder__ name, False otherwise."""
23 return (name[:2] == name[-2:] == '__' and
24 name[2:3] != '_' and
Ethan Furman648f8602013-10-06 17:19:54 -070025 name[-3:-2] != '_' and
26 len(name) > 4)
Ethan Furman6b3d64a2013-06-14 16:55:46 -070027
28
29def _is_sunder(name):
30 """Returns True if a _sunder_ name, False otherwise."""
31 return (name[0] == name[-1] == '_' and
32 name[1:2] != '_' and
Ethan Furman648f8602013-10-06 17:19:54 -070033 name[-2:-1] != '_' and
34 len(name) > 2)
Ethan Furman6b3d64a2013-06-14 16:55:46 -070035
36
37def _make_class_unpicklable(cls):
38 """Make the given class un-picklable."""
Ethan Furmanca1b7942014-02-08 11:36:27 -080039 def _break_on_call_reduce(self, proto):
Ethan Furman6b3d64a2013-06-14 16:55:46 -070040 raise TypeError('%r cannot be pickled' % self)
Ethan Furmanca1b7942014-02-08 11:36:27 -080041 cls.__reduce_ex__ = _break_on_call_reduce
Ethan Furman6b3d64a2013-06-14 16:55:46 -070042 cls.__module__ = '<unknown>'
43
Ethan Furman101e0742013-09-15 12:34:36 -070044
Ethan Furman6b3d64a2013-06-14 16:55:46 -070045class _EnumDict(dict):
Ethan Furman101e0742013-09-15 12:34:36 -070046 """Track enum member order and ensure member names are not reused.
Ethan Furman6b3d64a2013-06-14 16:55:46 -070047
48 EnumMeta will use the names found in self._member_names as the
49 enumeration member names.
50
51 """
52 def __init__(self):
53 super().__init__()
54 self._member_names = []
55
56 def __setitem__(self, key, value):
Ethan Furman101e0742013-09-15 12:34:36 -070057 """Changes anything not dundered or not a descriptor.
Ethan Furman6b3d64a2013-06-14 16:55:46 -070058
59 If an enum member name is used twice, an error is raised; duplicate
60 values are not checked for.
61
62 Single underscore (sunder) names are reserved.
63
64 """
65 if _is_sunder(key):
66 raise ValueError('_names_ are reserved for future Enum use')
Ethan Furman101e0742013-09-15 12:34:36 -070067 elif _is_dunder(key):
68 pass
69 elif key in self._member_names:
70 # descriptor overwriting an enum?
71 raise TypeError('Attempted to reuse key: %r' % key)
72 elif not _is_descriptor(value):
73 if key in self:
74 # enum overwriting a descriptor?
75 raise TypeError('Key already defined as: %r' % self[key])
Ethan Furman6b3d64a2013-06-14 16:55:46 -070076 self._member_names.append(key)
77 super().__setitem__(key, value)
78
79
Ethan Furman101e0742013-09-15 12:34:36 -070080
Ezio Melotti9a3777e2013-08-17 15:53:55 +030081# Dummy value for Enum as EnumMeta explicitly checks for it, but of course
82# until EnumMeta finishes running the first time the Enum class doesn't exist.
83# This is also why there are checks in EnumMeta like `if Enum is not None`
Ethan Furman6b3d64a2013-06-14 16:55:46 -070084Enum = None
85
86
87class EnumMeta(type):
88 """Metaclass for Enum"""
89 @classmethod
90 def __prepare__(metacls, cls, bases):
91 return _EnumDict()
92
93 def __new__(metacls, cls, bases, classdict):
94 # an Enum class is final once enumeration items have been defined; it
95 # cannot be mixed with other types (int, float, etc.) if it has an
96 # inherited __new__ unless a new __new__ is defined (or the resulting
97 # class will fail).
98 member_type, first_enum = metacls._get_mixins_(bases)
99 __new__, save_new, use_args = metacls._find_new_(classdict, member_type,
100 first_enum)
101
102 # save enum items into separate mapping so they don't get baked into
103 # the new class
104 members = {k: classdict[k] for k in classdict._member_names}
105 for name in classdict._member_names:
106 del classdict[name]
107
108 # check for illegal enum names (any others?)
109 invalid_names = set(members) & {'mro', }
110 if invalid_names:
111 raise ValueError('Invalid enum member name: {0}'.format(
112 ','.join(invalid_names)))
113
Ethan Furman48a724f2015-04-11 23:23:06 -0700114 # create a default docstring if one has not been provided
115 if '__doc__' not in classdict:
116 classdict['__doc__'] = 'An enumeration.'
117
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700118 # create our new Enum type
119 enum_class = super().__new__(metacls, cls, bases, classdict)
Ethan Furman520ad572013-07-19 19:47:21 -0700120 enum_class._member_names_ = [] # names in definition order
121 enum_class._member_map_ = OrderedDict() # name->value map
Ethan Furman5e5a8232013-08-04 08:42:23 -0700122 enum_class._member_type_ = member_type
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700123
Ethan Furman354ecf12015-03-11 08:43:12 -0700124 # save attributes from super classes so we know if we can take
125 # the shortcut of storing members in the class dict
126 base_attributes = {a for b in bases for a in b.__dict__}
127
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700128 # Reverse value->name map for hashable values.
Ethan Furman520ad572013-07-19 19:47:21 -0700129 enum_class._value2member_map_ = {}
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700130
Ethan Furman2da95042014-03-03 12:42:52 -0800131 # If a custom type is mixed into the Enum, and it does not know how
132 # to pickle itself, pickle.dumps will succeed but pickle.loads will
133 # fail. Rather than have the error show up later and possibly far
134 # from the source, sabotage the pickle protocol for this class so
135 # that pickle.dumps also fails.
136 #
137 # However, if the new class implements its own __reduce_ex__, do not
138 # sabotage -- it's on them to make sure it works correctly. We use
139 # __reduce_ex__ instead of any of the others as it is preferred by
140 # pickle over __reduce__, and it handles all pickle protocols.
141 if '__reduce_ex__' not in classdict:
Ethan Furmandc870522014-02-18 12:37:12 -0800142 if member_type is not object:
143 methods = ('__getnewargs_ex__', '__getnewargs__',
144 '__reduce_ex__', '__reduce__')
Ethan Furman2da95042014-03-03 12:42:52 -0800145 if not any(m in member_type.__dict__ for m in methods):
Ethan Furmandc870522014-02-18 12:37:12 -0800146 _make_class_unpicklable(enum_class)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700147
148 # instantiate them, checking for duplicates as we go
149 # we instantiate first instead of checking for duplicates first in case
150 # a custom __new__ is doing something funky with the values -- such as
151 # auto-numbering ;)
152 for member_name in classdict._member_names:
153 value = members[member_name]
154 if not isinstance(value, tuple):
155 args = (value, )
156 else:
157 args = value
158 if member_type is tuple: # special case for tuple enums
159 args = (args, ) # wrap it one more time
160 if not use_args:
161 enum_member = __new__(enum_class)
Ethan Furmanb41803e2013-07-25 13:50:45 -0700162 if not hasattr(enum_member, '_value_'):
163 enum_member._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700164 else:
165 enum_member = __new__(enum_class, *args)
Ethan Furmanb41803e2013-07-25 13:50:45 -0700166 if not hasattr(enum_member, '_value_'):
167 enum_member._value_ = member_type(*args)
Ethan Furman520ad572013-07-19 19:47:21 -0700168 value = enum_member._value_
Ethan Furman520ad572013-07-19 19:47:21 -0700169 enum_member._name_ = member_name
Ethan Furmanc850f342013-09-15 16:59:35 -0700170 enum_member.__objclass__ = enum_class
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700171 enum_member.__init__(*args)
172 # If another member with the same value was already defined, the
173 # new member becomes an alias to the existing one.
Ethan Furman520ad572013-07-19 19:47:21 -0700174 for name, canonical_member in enum_class._member_map_.items():
Ethan Furman0081f232014-09-16 17:31:23 -0700175 if canonical_member._value_ == enum_member._value_:
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700176 enum_member = canonical_member
177 break
178 else:
179 # Aliases don't appear in member names (only in __members__).
Ethan Furman520ad572013-07-19 19:47:21 -0700180 enum_class._member_names_.append(member_name)
Ethan Furman354ecf12015-03-11 08:43:12 -0700181 # performance boost for any member that would not shadow
182 # a DynamicClassAttribute
183 if member_name not in base_attributes:
184 setattr(enum_class, member_name, enum_member)
185 # now add to _member_map_
Ethan Furman520ad572013-07-19 19:47:21 -0700186 enum_class._member_map_[member_name] = enum_member
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700187 try:
188 # This may fail if value is not hashable. We can't add the value
189 # to the map, and by-value lookups for this value will be
190 # linear.
Ethan Furman520ad572013-07-19 19:47:21 -0700191 enum_class._value2member_map_[value] = enum_member
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700192 except TypeError:
193 pass
194
195 # double check that repr and friends are not the mixin's or various
196 # things break (such as pickle)
Ethan Furmandc870522014-02-18 12:37:12 -0800197 for name in ('__repr__', '__str__', '__format__', '__reduce_ex__'):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700198 class_method = getattr(enum_class, name)
199 obj_method = getattr(member_type, name, None)
200 enum_method = getattr(first_enum, name, None)
201 if obj_method is not None and obj_method is class_method:
202 setattr(enum_class, name, enum_method)
203
204 # replace any other __new__ with our own (as long as Enum is not None,
205 # anyway) -- again, this is to support pickle
206 if Enum is not None:
207 # if the user defined their own __new__, save it before it gets
208 # clobbered in case they subclass later
209 if save_new:
210 enum_class.__new_member__ = __new__
211 enum_class.__new__ = Enum.__new__
212 return enum_class
213
Ethan Furmand9925a12014-09-16 20:35:55 -0700214 def __call__(cls, value, names=None, *, module=None, qualname=None, type=None, start=1):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700215 """Either returns an existing member, or creates a new enum class.
216
217 This method is used both when an enum class is given a value to match
218 to an enumeration member (i.e. Color(3)) and for the functional API
219 (i.e. Color = Enum('Color', names='red green blue')).
220
Ethan Furman2da95042014-03-03 12:42:52 -0800221 When used for the functional API:
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700222
Ethan Furman2da95042014-03-03 12:42:52 -0800223 `value` will be the name of the new class.
224
225 `names` should be either a string of white-space/comma delimited names
Ethan Furmand9925a12014-09-16 20:35:55 -0700226 (values will start at `start`), or an iterator/mapping of name, value pairs.
Ethan Furman2da95042014-03-03 12:42:52 -0800227
228 `module` should be set to the module this class is being created in;
229 if it is not set, an attempt to find that module will be made, but if
230 it fails the class will not be picklable.
231
232 `qualname` should be set to the actual location this class can be found
233 at in its module; by default it is set to the global scope. If this is
234 not correct, unpickling will fail in some circumstances.
235
236 `type`, if set, will be mixed in as the first base class.
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700237
238 """
239 if names is None: # simple value lookup
240 return cls.__new__(cls, value)
241 # otherwise, functional API: we're creating a new Enum type
Ethan Furmand9925a12014-09-16 20:35:55 -0700242 return cls._create_(value, names, module=module, qualname=qualname, type=type, start=start)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700243
244 def __contains__(cls, member):
Ethan Furman0081f232014-09-16 17:31:23 -0700245 return isinstance(member, cls) and member._name_ in cls._member_map_
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700246
Ethan Furman64a99722013-09-22 16:18:19 -0700247 def __delattr__(cls, attr):
248 # nicer error message when someone tries to delete an attribute
249 # (see issue19025).
250 if attr in cls._member_map_:
251 raise AttributeError(
252 "%s: cannot delete Enum member." % cls.__name__)
253 super().__delattr__(attr)
254
Ethan Furman388a3922013-08-12 06:51:41 -0700255 def __dir__(self):
Ethan Furman64a99722013-09-22 16:18:19 -0700256 return (['__class__', '__doc__', '__members__', '__module__'] +
257 self._member_names_)
Ethan Furman388a3922013-08-12 06:51:41 -0700258
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700259 def __getattr__(cls, name):
260 """Return the enum member matching `name`
261
262 We use __getattr__ instead of descriptors or inserting into the enum
263 class' __dict__ in order to support `name` and `value` being both
264 properties for enum members (which live in the class' __dict__) and
265 enum members themselves.
266
267 """
268 if _is_dunder(name):
269 raise AttributeError(name)
270 try:
Ethan Furman520ad572013-07-19 19:47:21 -0700271 return cls._member_map_[name]
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700272 except KeyError:
273 raise AttributeError(name) from None
274
275 def __getitem__(cls, name):
Ethan Furman520ad572013-07-19 19:47:21 -0700276 return cls._member_map_[name]
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700277
278 def __iter__(cls):
Ethan Furman520ad572013-07-19 19:47:21 -0700279 return (cls._member_map_[name] for name in cls._member_names_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700280
281 def __len__(cls):
Ethan Furman520ad572013-07-19 19:47:21 -0700282 return len(cls._member_names_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700283
Ethan Furman2131a4a2013-09-14 18:11:24 -0700284 @property
285 def __members__(cls):
286 """Returns a mapping of member name->value.
287
288 This mapping lists all enum members, including aliases. Note that this
289 is a read-only view of the internal mapping.
290
291 """
292 return MappingProxyType(cls._member_map_)
293
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700294 def __repr__(cls):
295 return "<enum %r>" % cls.__name__
296
Ethan Furman2131a4a2013-09-14 18:11:24 -0700297 def __reversed__(cls):
298 return (cls._member_map_[name] for name in reversed(cls._member_names_))
299
Ethan Furmanf203f2d2013-09-06 07:16:48 -0700300 def __setattr__(cls, name, value):
301 """Block attempts to reassign Enum members.
302
303 A simple assignment to the class namespace only changes one of the
304 several possible ways to get an Enum member from the Enum class,
305 resulting in an inconsistent Enumeration.
306
307 """
308 member_map = cls.__dict__.get('_member_map_', {})
309 if name in member_map:
310 raise AttributeError('Cannot reassign members.')
311 super().__setattr__(name, value)
312
Ethan Furmand9925a12014-09-16 20:35:55 -0700313 def _create_(cls, class_name, names=None, *, module=None, qualname=None, type=None, start=1):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700314 """Convenience method to create a new Enum class.
315
316 `names` can be:
317
318 * A string containing member names, separated either with spaces or
Ethan Furmand9925a12014-09-16 20:35:55 -0700319 commas. Values are incremented by 1 from `start`.
320 * An iterable of member names. Values are incremented by 1 from `start`.
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700321 * An iterable of (member name, value) pairs.
Ethan Furmand9925a12014-09-16 20:35:55 -0700322 * A mapping of member name -> value pairs.
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700323
324 """
325 metacls = cls.__class__
326 bases = (cls, ) if type is None else (type, cls)
327 classdict = metacls.__prepare__(class_name, bases)
328
329 # special processing needed for names?
330 if isinstance(names, str):
331 names = names.replace(',', ' ').split()
332 if isinstance(names, (tuple, list)) and isinstance(names[0], str):
Ethan Furmand9925a12014-09-16 20:35:55 -0700333 names = [(e, i) for (i, e) in enumerate(names, start)]
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700334
335 # Here, names is either an iterable of (name, value) or a mapping.
336 for item in names:
337 if isinstance(item, str):
338 member_name, member_value = item, names[item]
339 else:
340 member_name, member_value = item
341 classdict[member_name] = member_value
342 enum_class = metacls.__new__(metacls, class_name, bases, classdict)
343
344 # TODO: replace the frame hack if a blessed way to know the calling
345 # module is ever developed
346 if module is None:
347 try:
348 module = sys._getframe(2).f_globals['__name__']
349 except (AttributeError, ValueError) as exc:
350 pass
351 if module is None:
352 _make_class_unpicklable(enum_class)
353 else:
354 enum_class.__module__ = module
Ethan Furmanca1b7942014-02-08 11:36:27 -0800355 if qualname is not None:
356 enum_class.__qualname__ = qualname
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700357
358 return enum_class
359
360 @staticmethod
361 def _get_mixins_(bases):
362 """Returns the type for creating enum members, and the first inherited
363 enum class.
364
365 bases: the tuple of bases that was given to __new__
366
367 """
368 if not bases:
369 return object, Enum
370
371 # double check that we are not subclassing a class with existing
372 # enumeration members; while we're at it, see if any other data
373 # type has been mixed in so we can use the correct __new__
374 member_type = first_enum = None
375 for base in bases:
376 if (base is not Enum and
377 issubclass(base, Enum) and
Ethan Furman520ad572013-07-19 19:47:21 -0700378 base._member_names_):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700379 raise TypeError("Cannot extend enumerations")
380 # base is now the last base in bases
381 if not issubclass(base, Enum):
382 raise TypeError("new enumerations must be created as "
383 "`ClassName([mixin_type,] enum_type)`")
384
385 # get correct mix-in type (either mix-in type of Enum subclass, or
386 # first base if last base is Enum)
387 if not issubclass(bases[0], Enum):
388 member_type = bases[0] # first data type
389 first_enum = bases[-1] # enum type
390 else:
391 for base in bases[0].__mro__:
392 # most common: (IntEnum, int, Enum, object)
393 # possible: (<Enum 'AutoIntEnum'>, <Enum 'IntEnum'>,
394 # <class 'int'>, <Enum 'Enum'>,
395 # <class 'object'>)
396 if issubclass(base, Enum):
397 if first_enum is None:
398 first_enum = base
399 else:
400 if member_type is None:
401 member_type = base
402
403 return member_type, first_enum
404
405 @staticmethod
406 def _find_new_(classdict, member_type, first_enum):
407 """Returns the __new__ to be used for creating the enum members.
408
409 classdict: the class dictionary given to __new__
410 member_type: the data type whose __new__ will be used by default
411 first_enum: enumeration to check for an overriding __new__
412
413 """
414 # now find the correct __new__, checking to see of one was defined
415 # by the user; also check earlier enum classes in case a __new__ was
416 # saved as __new_member__
417 __new__ = classdict.get('__new__', None)
418
419 # should __new__ be saved as __new_member__ later?
420 save_new = __new__ is not None
421
422 if __new__ is None:
423 # check all possibles for __new_member__ before falling back to
424 # __new__
425 for method in ('__new_member__', '__new__'):
426 for possible in (member_type, first_enum):
427 target = getattr(possible, method, None)
428 if target not in {
429 None,
430 None.__new__,
431 object.__new__,
432 Enum.__new__,
433 }:
434 __new__ = target
435 break
436 if __new__ is not None:
437 break
438 else:
439 __new__ = object.__new__
440
441 # if a non-object.__new__ is used then whatever value/tuple was
442 # assigned to the enum member name will be passed to __new__ and to the
443 # new enum member's __init__
444 if __new__ is object.__new__:
445 use_args = False
446 else:
447 use_args = True
448
449 return __new__, save_new, use_args
450
451
452class Enum(metaclass=EnumMeta):
453 """Generic enumeration.
454
455 Derive from this class to define new enumerations.
456
457 """
458 def __new__(cls, value):
459 # all enum instances are actually created during class construction
460 # without calling this method; this method is called by the metaclass'
461 # __call__ (i.e. Color(3) ), and by pickle
462 if type(value) is cls:
463 # For lookups like Color(Color.red)
464 return value
465 # by-value search for a matching enum member
466 # see if it's in the reverse mapping (for hashable values)
Ethan Furman2aa27322013-07-19 19:35:56 -0700467 try:
Ethan Furman520ad572013-07-19 19:47:21 -0700468 if value in cls._value2member_map_:
469 return cls._value2member_map_[value]
Ethan Furman2aa27322013-07-19 19:35:56 -0700470 except TypeError:
471 # not there, now do long search -- O(n) behavior
Ethan Furman520ad572013-07-19 19:47:21 -0700472 for member in cls._member_map_.values():
Ethan Furman0081f232014-09-16 17:31:23 -0700473 if member._value_ == value:
Ethan Furman2aa27322013-07-19 19:35:56 -0700474 return member
Ethan Furman0081f232014-09-16 17:31:23 -0700475 raise ValueError("%r is not a valid %s" % (value, cls.__name__))
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700476
477 def __repr__(self):
478 return "<%s.%s: %r>" % (
Ethan Furman520ad572013-07-19 19:47:21 -0700479 self.__class__.__name__, self._name_, self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700480
481 def __str__(self):
Ethan Furman520ad572013-07-19 19:47:21 -0700482 return "%s.%s" % (self.__class__.__name__, self._name_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700483
Ethan Furman6db1fd52015-09-17 21:49:12 -0700484 def __bool__(self):
485 return bool(self._value_)
486
Ethan Furman388a3922013-08-12 06:51:41 -0700487 def __dir__(self):
Ethan Furman0ae550b2014-10-14 08:58:32 -0700488 added_behavior = [
489 m
490 for cls in self.__class__.mro()
491 for m in cls.__dict__
Ethan Furman354ecf12015-03-11 08:43:12 -0700492 if m[0] != '_' and m not in self._member_map_
Ethan Furman0ae550b2014-10-14 08:58:32 -0700493 ]
Ethan Furmanec5f8eb2014-10-21 13:40:35 -0700494 return (['__class__', '__doc__', '__module__'] + added_behavior)
Ethan Furman388a3922013-08-12 06:51:41 -0700495
Ethan Furmanec15a822013-08-31 19:17:41 -0700496 def __format__(self, format_spec):
497 # mixed-in Enums should use the mixed-in type's __format__, otherwise
498 # we can get strange results with the Enum name showing up instead of
499 # the value
500
501 # pure Enum branch
502 if self._member_type_ is object:
503 cls = str
504 val = str(self)
505 # mix-in branch
506 else:
507 cls = self._member_type_
Ethan Furman0081f232014-09-16 17:31:23 -0700508 val = self._value_
Ethan Furmanec15a822013-08-31 19:17:41 -0700509 return cls.__format__(val, format_spec)
510
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700511 def __hash__(self):
Ethan Furman520ad572013-07-19 19:47:21 -0700512 return hash(self._name_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700513
Ethan Furmanca1b7942014-02-08 11:36:27 -0800514 def __reduce_ex__(self, proto):
Ethan Furmandc870522014-02-18 12:37:12 -0800515 return self.__class__, (self._value_, )
Ethan Furmanca1b7942014-02-08 11:36:27 -0800516
Ethan Furman33918c12013-09-27 23:02:02 -0700517 # DynamicClassAttribute is used to provide access to the `name` and
518 # `value` properties of enum members while keeping some measure of
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700519 # protection from modification, while still allowing for an enumeration
520 # to have members named `name` and `value`. This works because enumeration
521 # members are not set directly on the enum class -- __getattr__ is
522 # used to look them up.
523
Ethan Furmane03ea372013-09-25 07:14:41 -0700524 @DynamicClassAttribute
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700525 def name(self):
Ethan Furmanc850f342013-09-15 16:59:35 -0700526 """The name of the Enum member."""
Ethan Furman520ad572013-07-19 19:47:21 -0700527 return self._name_
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700528
Ethan Furmane03ea372013-09-25 07:14:41 -0700529 @DynamicClassAttribute
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700530 def value(self):
Ethan Furmanc850f342013-09-15 16:59:35 -0700531 """The value of the Enum member."""
Ethan Furman520ad572013-07-19 19:47:21 -0700532 return self._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700533
Ethan Furman24e837f2015-03-18 17:27:57 -0700534 @classmethod
535 def _convert(cls, name, module, filter, source=None):
536 """
537 Create a new Enum subclass that replaces a collection of global constants
538 """
539 # convert all constants from source (or module) that pass filter() to
540 # a new Enum called name, and export the enum and its members back to
541 # module;
542 # also, replace the __reduce_ex__ method so unpickling works in
543 # previous Python versions
544 module_globals = vars(sys.modules[module])
545 if source:
546 source = vars(source)
547 else:
548 source = module_globals
549 members = {name: value for name, value in source.items()
550 if filter(name)}
551 cls = cls(name, members, module=module)
552 cls.__reduce_ex__ = _reduce_ex_by_name
553 module_globals.update(cls.__members__)
554 module_globals[name] = cls
555 return cls
556
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700557
558class IntEnum(int, Enum):
559 """Enum where members are also (and must be) ints"""
Ethan Furmanf24bb352013-07-18 17:05:39 -0700560
561
Ethan Furman24e837f2015-03-18 17:27:57 -0700562def _reduce_ex_by_name(self, proto):
563 return self.name
564
Ethan Furmanf24bb352013-07-18 17:05:39 -0700565def unique(enumeration):
566 """Class decorator for enumerations ensuring unique member values."""
567 duplicates = []
568 for name, member in enumeration.__members__.items():
569 if name != member.name:
570 duplicates.append((name, member.name))
571 if duplicates:
572 alias_details = ', '.join(
573 ["%s -> %s" % (alias, name) for (alias, name) in duplicates])
574 raise ValueError('duplicate values found in %r: %s' %
575 (enumeration, alias_details))
576 return enumeration