1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
--- contrib/deprecated/python/enum34/enum/__init__.py (index)
+++ contrib/deprecated/python/enum34/enum/__init__.py (working tree)
@@ -8,6 +8,8 @@ version = 1, 1, 10
pyver = float('%s.%s' % _sys.version_info[:2])
+ALLOW_SYNONYMS = '__allow_synonyms__'
+
try:
any
except NameError:
@@ -161,6 +163,7 @@ class EnumMeta(type):
for k, v in original_dict.items():
classdict[k] = v
+ allow_synonyms = classdict.get(ALLOW_SYNONYMS, True)
member_type, first_enum = metacls._get_mixins_(bases)
__new__, save_new, use_args = metacls._find_new_(classdict, member_type,
first_enum)
@@ -215,8 +218,18 @@ class EnumMeta(type):
# auto-numbering ;)
if __new__ is None:
__new__ = enum_class.__new__
+
+ val2name = {}
for member_name in _order_:
value = members[member_name]
+ if not allow_synonyms:
+ if value in val2name:
+ raise ValueError(
+ 'allow_synonyms=False forbids multiple names of the same value; '
+ 'Members {!r} and {!r} break this'.format(val2name[value], member_name)
+ )
+ val2name[value] = member_name
+
if not isinstance(value, tuple):
args = (value, )
else:
@@ -237,7 +250,7 @@ class EnumMeta(type):
enum_member.__init__(*args)
# If another member with the same value was already defined, the
# new member becomes an alias to the existing one.
- for name, canonical_member in enum_class._member_map_.items():
+ for name, canonical_member in (enum_class._member_map_.items() if allow_synonyms else ()):
if canonical_member.value == enum_member._value_:
enum_member = canonical_member
break
@@ -328,7 +341,7 @@ class EnumMeta(type):
"""
return True
- def __call__(cls, value, names=None, module=None, type=None, start=1):
+ def __call__(cls, value, names=None, module=None, type=None, start=1, allow_synonyms=True):
"""Either returns an existing member, or creates a new enum class.
This method is used both when an enum class is given a value to match
@@ -347,7 +360,7 @@ class EnumMeta(type):
if names is None: # simple value lookup
return cls.__new__(cls, value)
# otherwise, functional API: we're creating a new Enum type
- return cls._create_(value, names, module=module, type=type, start=start)
+ return cls._create_(value, names, module=module, type=type, start=start, allow_synonyms=allow_synonyms)
def __contains__(cls, member):
return isinstance(member, cls) and member.name in cls._member_map_
@@ -420,7 +433,7 @@ class EnumMeta(type):
raise AttributeError('Cannot reassign members.')
super(EnumMeta, cls).__setattr__(name, value)
- def _create_(cls, class_name, names=None, module=None, type=None, start=1):
+ def _create_(cls, class_name, names=None, module=None, type=None, start=1, allow_synonyms=True):
"""Convenience method to create a new Enum class.
`names` can be:
@@ -465,6 +478,7 @@ class EnumMeta(type):
# only set _order_ in classdict if name/value was not from a mapping
if not isinstance(item, basestring):
classdict['_order_'] = _order_
+ classdict[ALLOW_SYNONYMS] = getattr(cls, ALLOW_SYNONYMS, allow_synonyms)
enum_class = metacls.__new__(metacls, class_name, bases, classdict)
# TODO: replace the frame hack if a blessed way to know the calling
|