--- 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