blob: 3cd3df8428445d708ec6cd22b68c7e2bd2aeaffc [file] [log] [blame]
Ethan Furman6b3d64a2013-06-14 16:55:46 -07001import sys
2from collections import OrderedDict
Ethan Furmane03ea372013-09-25 07:14:41 -07003from types import MappingProxyType, DynamicClassAttribute
Ethan Furman6b3d64a2013-06-14 16:55:46 -07004
Ethan Furmanf24bb352013-07-18 17:05:39 -07005__all__ = ['Enum', 'IntEnum', 'unique']
Ethan Furman6b3d64a2013-06-14 16:55:46 -07006
7
Ethan Furman101e0742013-09-15 12:34:36 -07008def _is_descriptor(obj):
9 """Returns True if obj is a descriptor, False otherwise."""
10 return (
11 hasattr(obj, '__get__') or
12 hasattr(obj, '__set__') or
13 hasattr(obj, '__delete__'))
14
15
Ethan Furman6b3d64a2013-06-14 16:55:46 -070016def _is_dunder(name):
17 """Returns True if a __dunder__ name, False otherwise."""
18 return (name[:2] == name[-2:] == '__' and
19 name[2:3] != '_' and
Ethan Furman648f8602013-10-06 17:19:54 -070020 name[-3:-2] != '_' and
21 len(name) > 4)
Ethan Furman6b3d64a2013-06-14 16:55:46 -070022
23
24def _is_sunder(name):
25 """Returns True if a _sunder_ name, False otherwise."""
26 return (name[0] == name[-1] == '_' and
27 name[1:2] != '_' and
Ethan Furman648f8602013-10-06 17:19:54 -070028 name[-2:-1] != '_' and
29 len(name) > 2)
Ethan Furman6b3d64a2013-06-14 16:55:46 -070030
31
32def _make_class_unpicklable(cls):
33 """Make the given class un-picklable."""
Ethan Furmanca1b7942014-02-08 11:36:27 -080034 def _break_on_call_reduce(self, proto):
Ethan Furman6b3d64a2013-06-14 16:55:46 -070035 raise TypeError('%r cannot be pickled' % self)
Ethan Furmanca1b7942014-02-08 11:36:27 -080036 cls.__reduce_ex__ = _break_on_call_reduce
Ethan Furman6b3d64a2013-06-14 16:55:46 -070037 cls.__module__ = '<unknown>'
38
Ethan Furman101e0742013-09-15 12:34:36 -070039
Ethan Furman6b3d64a2013-06-14 16:55:46 -070040class _EnumDict(dict):
Ethan Furman101e0742013-09-15 12:34:36 -070041 """Track enum member order and ensure member names are not reused.
Ethan Furman6b3d64a2013-06-14 16:55:46 -070042
43 EnumMeta will use the names found in self._member_names as the
44 enumeration member names.
45
46 """
47 def __init__(self):
48 super().__init__()
49 self._member_names = []
50
51 def __setitem__(self, key, value):
Ethan Furman101e0742013-09-15 12:34:36 -070052 """Changes anything not dundered or not a descriptor.
Ethan Furman6b3d64a2013-06-14 16:55:46 -070053
54 If an enum member name is used twice, an error is raised; duplicate
55 values are not checked for.
56
57 Single underscore (sunder) names are reserved.
58
59 """
60 if _is_sunder(key):
61 raise ValueError('_names_ are reserved for future Enum use')
Ethan Furman101e0742013-09-15 12:34:36 -070062 elif _is_dunder(key):
63 pass
64 elif key in self._member_names:
65 # descriptor overwriting an enum?
66 raise TypeError('Attempted to reuse key: %r' % key)
67 elif not _is_descriptor(value):
68 if key in self:
69 # enum overwriting a descriptor?
70 raise TypeError('Key already defined as: %r' % self[key])
Ethan Furman6b3d64a2013-06-14 16:55:46 -070071 self._member_names.append(key)
72 super().__setitem__(key, value)
73
74
Ethan Furman101e0742013-09-15 12:34:36 -070075
Ezio Melotti9a3777e2013-08-17 15:53:55 +030076# Dummy value for Enum as EnumMeta explicitly checks for it, but of course
77# until EnumMeta finishes running the first time the Enum class doesn't exist.
78# This is also why there are checks in EnumMeta like `if Enum is not None`
Ethan Furman6b3d64a2013-06-14 16:55:46 -070079Enum = None
80
81
82class EnumMeta(type):
83 """Metaclass for Enum"""
84 @classmethod
85 def __prepare__(metacls, cls, bases):
86 return _EnumDict()
87
88 def __new__(metacls, cls, bases, classdict):
89 # an Enum class is final once enumeration items have been defined; it
90 # cannot be mixed with other types (int, float, etc.) if it has an
91 # inherited __new__ unless a new __new__ is defined (or the resulting
92 # class will fail).
93 member_type, first_enum = metacls._get_mixins_(bases)
94 __new__, save_new, use_args = metacls._find_new_(classdict, member_type,
95 first_enum)
96
97 # save enum items into separate mapping so they don't get baked into
98 # the new class
99 members = {k: classdict[k] for k in classdict._member_names}
100 for name in classdict._member_names:
101 del classdict[name]
102
103 # check for illegal enum names (any others?)
104 invalid_names = set(members) & {'mro', }
105 if invalid_names:
106 raise ValueError('Invalid enum member name: {0}'.format(
107 ','.join(invalid_names)))
108
109 # create our new Enum type
110 enum_class = super().__new__(metacls, cls, bases, classdict)
Ethan Furman520ad572013-07-19 19:47:21 -0700111 enum_class._member_names_ = [] # names in definition order
112 enum_class._member_map_ = OrderedDict() # name->value map
Ethan Furman5e5a8232013-08-04 08:42:23 -0700113 enum_class._member_type_ = member_type
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700114
115 # Reverse value->name map for hashable values.
Ethan Furman520ad572013-07-19 19:47:21 -0700116 enum_class._value2member_map_ = {}
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700117
Ethan Furman2da95042014-03-03 12:42:52 -0800118 # If a custom type is mixed into the Enum, and it does not know how
119 # to pickle itself, pickle.dumps will succeed but pickle.loads will
120 # fail. Rather than have the error show up later and possibly far
121 # from the source, sabotage the pickle protocol for this class so
122 # that pickle.dumps also fails.
123 #
124 # However, if the new class implements its own __reduce_ex__, do not
125 # sabotage -- it's on them to make sure it works correctly. We use
126 # __reduce_ex__ instead of any of the others as it is preferred by
127 # pickle over __reduce__, and it handles all pickle protocols.
128 if '__reduce_ex__' not in classdict:
Ethan Furmandc870522014-02-18 12:37:12 -0800129 if member_type is not object:
130 methods = ('__getnewargs_ex__', '__getnewargs__',
131 '__reduce_ex__', '__reduce__')
Ethan Furman2da95042014-03-03 12:42:52 -0800132 if not any(m in member_type.__dict__ for m in methods):
Ethan Furmandc870522014-02-18 12:37:12 -0800133 _make_class_unpicklable(enum_class)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700134
135 # instantiate them, checking for duplicates as we go
136 # we instantiate first instead of checking for duplicates first in case
137 # a custom __new__ is doing something funky with the values -- such as
138 # auto-numbering ;)
139 for member_name in classdict._member_names:
140 value = members[member_name]
141 if not isinstance(value, tuple):
142 args = (value, )
143 else:
144 args = value
145 if member_type is tuple: # special case for tuple enums
146 args = (args, ) # wrap it one more time
147 if not use_args:
148 enum_member = __new__(enum_class)
Ethan Furmanb41803e2013-07-25 13:50:45 -0700149 if not hasattr(enum_member, '_value_'):
150 enum_member._value_ = value
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700151 else:
152 enum_member = __new__(enum_class, *args)
Ethan Furmanb41803e2013-07-25 13:50:45 -0700153 if not hasattr(enum_member, '_value_'):
154 enum_member._value_ = member_type(*args)
Ethan Furman520ad572013-07-19 19:47:21 -0700155 value = enum_member._value_
Ethan Furman520ad572013-07-19 19:47:21 -0700156 enum_member._name_ = member_name
Ethan Furmanc850f342013-09-15 16:59:35 -0700157 enum_member.__objclass__ = enum_class
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700158 enum_member.__init__(*args)
159 # If another member with the same value was already defined, the
160 # new member becomes an alias to the existing one.
Ethan Furman520ad572013-07-19 19:47:21 -0700161 for name, canonical_member in enum_class._member_map_.items():
Ethan Furman0081f232014-09-16 17:31:23 -0700162 if canonical_member._value_ == enum_member._value_:
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700163 enum_member = canonical_member
164 break
165 else:
166 # Aliases don't appear in member names (only in __members__).
Ethan Furman520ad572013-07-19 19:47:21 -0700167 enum_class._member_names_.append(member_name)
168 enum_class._member_map_[member_name] = enum_member
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700169 try:
170 # This may fail if value is not hashable. We can't add the value
171 # to the map, and by-value lookups for this value will be
172 # linear.
Ethan Furman520ad572013-07-19 19:47:21 -0700173 enum_class._value2member_map_[value] = enum_member
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700174 except TypeError:
175 pass
176
177 # double check that repr and friends are not the mixin's or various
178 # things break (such as pickle)
Ethan Furmandc870522014-02-18 12:37:12 -0800179 for name in ('__repr__', '__str__', '__format__', '__reduce_ex__'):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700180 class_method = getattr(enum_class, name)
181 obj_method = getattr(member_type, name, None)
182 enum_method = getattr(first_enum, name, None)
183 if obj_method is not None and obj_method is class_method:
184 setattr(enum_class, name, enum_method)
185
186 # replace any other __new__ with our own (as long as Enum is not None,
187 # anyway) -- again, this is to support pickle
188 if Enum is not None:
189 # if the user defined their own __new__, save it before it gets
190 # clobbered in case they subclass later
191 if save_new:
192 enum_class.__new_member__ = __new__
193 enum_class.__new__ = Enum.__new__
194 return enum_class
195
Ethan Furmanca1b7942014-02-08 11:36:27 -0800196 def __call__(cls, value, names=None, *, module=None, qualname=None, type=None):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700197 """Either returns an existing member, or creates a new enum class.
198
199 This method is used both when an enum class is given a value to match
200 to an enumeration member (i.e. Color(3)) and for the functional API
201 (i.e. Color = Enum('Color', names='red green blue')).
202
Ethan Furman2da95042014-03-03 12:42:52 -0800203 When used for the functional API:
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700204
Ethan Furman2da95042014-03-03 12:42:52 -0800205 `value` will be the name of the new class.
206
207 `names` should be either a string of white-space/comma delimited names
208 (values will start at 1), or an iterator/mapping of name, value pairs.
209
210 `module` should be set to the module this class is being created in;
211 if it is not set, an attempt to find that module will be made, but if
212 it fails the class will not be picklable.
213
214 `qualname` should be set to the actual location this class can be found
215 at in its module; by default it is set to the global scope. If this is
216 not correct, unpickling will fail in some circumstances.
217
218 `type`, if set, will be mixed in as the first base class.
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700219
220 """
221 if names is None: # simple value lookup
222 return cls.__new__(cls, value)
223 # otherwise, functional API: we're creating a new Enum type
Ethan Furmanca1b7942014-02-08 11:36:27 -0800224 return cls._create_(value, names, module=module, qualname=qualname, type=type)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700225
226 def __contains__(cls, member):
Ethan Furman0081f232014-09-16 17:31:23 -0700227 return isinstance(member, cls) and member._name_ in cls._member_map_
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700228
Ethan Furman64a99722013-09-22 16:18:19 -0700229 def __delattr__(cls, attr):
230 # nicer error message when someone tries to delete an attribute
231 # (see issue19025).
232 if attr in cls._member_map_:
233 raise AttributeError(
234 "%s: cannot delete Enum member." % cls.__name__)
235 super().__delattr__(attr)
236
Ethan Furman388a3922013-08-12 06:51:41 -0700237 def __dir__(self):
Ethan Furman64a99722013-09-22 16:18:19 -0700238 return (['__class__', '__doc__', '__members__', '__module__'] +
239 self._member_names_)
Ethan Furman388a3922013-08-12 06:51:41 -0700240
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700241 def __getattr__(cls, name):
242 """Return the enum member matching `name`
243
244 We use __getattr__ instead of descriptors or inserting into the enum
245 class' __dict__ in order to support `name` and `value` being both
246 properties for enum members (which live in the class' __dict__) and
247 enum members themselves.
248
249 """
250 if _is_dunder(name):
251 raise AttributeError(name)
252 try:
Ethan Furman520ad572013-07-19 19:47:21 -0700253 return cls._member_map_[name]
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700254 except KeyError:
255 raise AttributeError(name) from None
256
257 def __getitem__(cls, name):
Ethan Furman520ad572013-07-19 19:47:21 -0700258 return cls._member_map_[name]
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700259
260 def __iter__(cls):
Ethan Furman520ad572013-07-19 19:47:21 -0700261 return (cls._member_map_[name] for name in cls._member_names_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700262
263 def __len__(cls):
Ethan Furman520ad572013-07-19 19:47:21 -0700264 return len(cls._member_names_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700265
Ethan Furman2131a4a2013-09-14 18:11:24 -0700266 @property
267 def __members__(cls):
268 """Returns a mapping of member name->value.
269
270 This mapping lists all enum members, including aliases. Note that this
271 is a read-only view of the internal mapping.
272
273 """
274 return MappingProxyType(cls._member_map_)
275
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700276 def __repr__(cls):
277 return "<enum %r>" % cls.__name__
278
Ethan Furman2131a4a2013-09-14 18:11:24 -0700279 def __reversed__(cls):
280 return (cls._member_map_[name] for name in reversed(cls._member_names_))
281
Ethan Furmanf203f2d2013-09-06 07:16:48 -0700282 def __setattr__(cls, name, value):
283 """Block attempts to reassign Enum members.
284
285 A simple assignment to the class namespace only changes one of the
286 several possible ways to get an Enum member from the Enum class,
287 resulting in an inconsistent Enumeration.
288
289 """
290 member_map = cls.__dict__.get('_member_map_', {})
291 if name in member_map:
292 raise AttributeError('Cannot reassign members.')
293 super().__setattr__(name, value)
294
Ethan Furmanca1b7942014-02-08 11:36:27 -0800295 def _create_(cls, class_name, names=None, *, module=None, qualname=None, type=None):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700296 """Convenience method to create a new Enum class.
297
298 `names` can be:
299
300 * A string containing member names, separated either with spaces or
301 commas. Values are auto-numbered from 1.
302 * An iterable of member names. Values are auto-numbered from 1.
303 * An iterable of (member name, value) pairs.
304 * A mapping of member name -> value.
305
306 """
307 metacls = cls.__class__
308 bases = (cls, ) if type is None else (type, cls)
309 classdict = metacls.__prepare__(class_name, bases)
310
311 # special processing needed for names?
312 if isinstance(names, str):
313 names = names.replace(',', ' ').split()
314 if isinstance(names, (tuple, list)) and isinstance(names[0], str):
315 names = [(e, i) for (i, e) in enumerate(names, 1)]
316
317 # Here, names is either an iterable of (name, value) or a mapping.
318 for item in names:
319 if isinstance(item, str):
320 member_name, member_value = item, names[item]
321 else:
322 member_name, member_value = item
323 classdict[member_name] = member_value
324 enum_class = metacls.__new__(metacls, class_name, bases, classdict)
325
326 # TODO: replace the frame hack if a blessed way to know the calling
327 # module is ever developed
328 if module is None:
329 try:
330 module = sys._getframe(2).f_globals['__name__']
331 except (AttributeError, ValueError) as exc:
332 pass
333 if module is None:
334 _make_class_unpicklable(enum_class)
335 else:
336 enum_class.__module__ = module
Ethan Furmanca1b7942014-02-08 11:36:27 -0800337 if qualname is not None:
338 enum_class.__qualname__ = qualname
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700339
340 return enum_class
341
342 @staticmethod
343 def _get_mixins_(bases):
344 """Returns the type for creating enum members, and the first inherited
345 enum class.
346
347 bases: the tuple of bases that was given to __new__
348
349 """
350 if not bases:
351 return object, Enum
352
353 # double check that we are not subclassing a class with existing
354 # enumeration members; while we're at it, see if any other data
355 # type has been mixed in so we can use the correct __new__
356 member_type = first_enum = None
357 for base in bases:
358 if (base is not Enum and
359 issubclass(base, Enum) and
Ethan Furman520ad572013-07-19 19:47:21 -0700360 base._member_names_):
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700361 raise TypeError("Cannot extend enumerations")
362 # base is now the last base in bases
363 if not issubclass(base, Enum):
364 raise TypeError("new enumerations must be created as "
365 "`ClassName([mixin_type,] enum_type)`")
366
367 # get correct mix-in type (either mix-in type of Enum subclass, or
368 # first base if last base is Enum)
369 if not issubclass(bases[0], Enum):
370 member_type = bases[0] # first data type
371 first_enum = bases[-1] # enum type
372 else:
373 for base in bases[0].__mro__:
374 # most common: (IntEnum, int, Enum, object)
375 # possible: (<Enum 'AutoIntEnum'>, <Enum 'IntEnum'>,
376 # <class 'int'>, <Enum 'Enum'>,
377 # <class 'object'>)
378 if issubclass(base, Enum):
379 if first_enum is None:
380 first_enum = base
381 else:
382 if member_type is None:
383 member_type = base
384
385 return member_type, first_enum
386
387 @staticmethod
388 def _find_new_(classdict, member_type, first_enum):
389 """Returns the __new__ to be used for creating the enum members.
390
391 classdict: the class dictionary given to __new__
392 member_type: the data type whose __new__ will be used by default
393 first_enum: enumeration to check for an overriding __new__
394
395 """
396 # now find the correct __new__, checking to see of one was defined
397 # by the user; also check earlier enum classes in case a __new__ was
398 # saved as __new_member__
399 __new__ = classdict.get('__new__', None)
400
401 # should __new__ be saved as __new_member__ later?
402 save_new = __new__ is not None
403
404 if __new__ is None:
405 # check all possibles for __new_member__ before falling back to
406 # __new__
407 for method in ('__new_member__', '__new__'):
408 for possible in (member_type, first_enum):
409 target = getattr(possible, method, None)
410 if target not in {
411 None,
412 None.__new__,
413 object.__new__,
414 Enum.__new__,
415 }:
416 __new__ = target
417 break
418 if __new__ is not None:
419 break
420 else:
421 __new__ = object.__new__
422
423 # if a non-object.__new__ is used then whatever value/tuple was
424 # assigned to the enum member name will be passed to __new__ and to the
425 # new enum member's __init__
426 if __new__ is object.__new__:
427 use_args = False
428 else:
429 use_args = True
430
431 return __new__, save_new, use_args
432
433
434class Enum(metaclass=EnumMeta):
435 """Generic enumeration.
436
437 Derive from this class to define new enumerations.
438
439 """
440 def __new__(cls, value):
441 # all enum instances are actually created during class construction
442 # without calling this method; this method is called by the metaclass'
443 # __call__ (i.e. Color(3) ), and by pickle
444 if type(value) is cls:
445 # For lookups like Color(Color.red)
446 return value
447 # by-value search for a matching enum member
448 # see if it's in the reverse mapping (for hashable values)
Ethan Furman2aa27322013-07-19 19:35:56 -0700449 try:
Ethan Furman520ad572013-07-19 19:47:21 -0700450 if value in cls._value2member_map_:
451 return cls._value2member_map_[value]
Ethan Furman2aa27322013-07-19 19:35:56 -0700452 except TypeError:
453 # not there, now do long search -- O(n) behavior
Ethan Furman520ad572013-07-19 19:47:21 -0700454 for member in cls._member_map_.values():
Ethan Furman0081f232014-09-16 17:31:23 -0700455 if member._value_ == value:
Ethan Furman2aa27322013-07-19 19:35:56 -0700456 return member
Ethan Furman0081f232014-09-16 17:31:23 -0700457 raise ValueError("%r is not a valid %s" % (value, cls.__name__))
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700458
459 def __repr__(self):
460 return "<%s.%s: %r>" % (
Ethan Furman520ad572013-07-19 19:47:21 -0700461 self.__class__.__name__, self._name_, self._value_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700462
463 def __str__(self):
Ethan Furman520ad572013-07-19 19:47:21 -0700464 return "%s.%s" % (self.__class__.__name__, self._name_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700465
Ethan Furman388a3922013-08-12 06:51:41 -0700466 def __dir__(self):
Ethan Furman0ae550b2014-10-14 08:58:32 -0700467 added_behavior = [
468 m
469 for cls in self.__class__.mro()
470 for m in cls.__dict__
471 if m[0] != '_'
472 ]
Ethan Furman64a99722013-09-22 16:18:19 -0700473 return (['__class__', '__doc__', '__module__', 'name', 'value'] +
474 added_behavior)
Ethan Furman388a3922013-08-12 06:51:41 -0700475
Ethan Furmanec15a822013-08-31 19:17:41 -0700476 def __format__(self, format_spec):
477 # mixed-in Enums should use the mixed-in type's __format__, otherwise
478 # we can get strange results with the Enum name showing up instead of
479 # the value
480
481 # pure Enum branch
482 if self._member_type_ is object:
483 cls = str
484 val = str(self)
485 # mix-in branch
486 else:
487 cls = self._member_type_
Ethan Furman0081f232014-09-16 17:31:23 -0700488 val = self._value_
Ethan Furmanec15a822013-08-31 19:17:41 -0700489 return cls.__format__(val, format_spec)
490
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700491 def __hash__(self):
Ethan Furman520ad572013-07-19 19:47:21 -0700492 return hash(self._name_)
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700493
Ethan Furmanca1b7942014-02-08 11:36:27 -0800494 def __reduce_ex__(self, proto):
Ethan Furmandc870522014-02-18 12:37:12 -0800495 return self.__class__, (self._value_, )
Ethan Furmanca1b7942014-02-08 11:36:27 -0800496
Ethan Furman33918c12013-09-27 23:02:02 -0700497 # DynamicClassAttribute is used to provide access to the `name` and
498 # `value` properties of enum members while keeping some measure of
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700499 # protection from modification, while still allowing for an enumeration
500 # to have members named `name` and `value`. This works because enumeration
501 # members are not set directly on the enum class -- __getattr__ is
502 # used to look them up.
503
Ethan Furmane03ea372013-09-25 07:14:41 -0700504 @DynamicClassAttribute
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700505 def name(self):
Ethan Furmanc850f342013-09-15 16:59:35 -0700506 """The name of the Enum member."""
Ethan Furman520ad572013-07-19 19:47:21 -0700507 return self._name_
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700508
Ethan Furmane03ea372013-09-25 07:14:41 -0700509 @DynamicClassAttribute
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700510 def value(self):
Ethan Furmanc850f342013-09-15 16:59:35 -0700511 """The value of the Enum member."""
Ethan Furman520ad572013-07-19 19:47:21 -0700512 return self._value_
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700513
Ethan Furman482fe042015-03-18 18:19:30 -0700514 @classmethod
515 def _convert(cls, name, module, filter, source=None):
516 """
517 Create a new Enum subclass that replaces a collection of global constants
518 """
519 # convert all constants from source (or module) that pass filter() to
520 # a new Enum called name, and export the enum and its members back to
521 # module;
522 # also, replace the __reduce_ex__ method so unpickling works in
523 # previous Python versions
524 module_globals = vars(sys.modules[module])
525 if source:
526 source = vars(source)
527 else:
528 source = module_globals
529 members = {name: value for name, value in source.items()
530 if filter(name)}
531 cls = cls(name, members, module=module)
532 cls.__reduce_ex__ = _reduce_ex_by_name
533 module_globals.update(cls.__members__)
534 module_globals[name] = cls
535 return cls
536
Ethan Furman6b3d64a2013-06-14 16:55:46 -0700537
538class IntEnum(int, Enum):
539 """Enum where members are also (and must be) ints"""
Ethan Furmanf24bb352013-07-18 17:05:39 -0700540
541
Ethan Furman482fe042015-03-18 18:19:30 -0700542def _reduce_ex_by_name(self, proto):
543 return self.name
544
Ethan Furmanf24bb352013-07-18 17:05:39 -0700545def unique(enumeration):
546 """Class decorator for enumerations ensuring unique member values."""
547 duplicates = []
548 for name, member in enumeration.__members__.items():
549 if name != member.name:
550 duplicates.append((name, member.name))
551 if duplicates:
552 alias_details = ', '.join(
553 ["%s -> %s" % (alias, name) for (alias, name) in duplicates])
554 raise ValueError('duplicate values found in %r: %s' %
555 (enumeration, alias_details))
556 return enumeration