# -*- test-case-name: mv3d.test.util.test_enum -*- # Copyright (C) 2012 Mortal Coil Games # See LICENSE for details. """ Simple base enum utils! @author: mike """ class MetaEnum(type): """ Turns a class into an enum by assigning numbers to attributes that are set to None. See the Enum class for example usage. """ def __new__(cls, name, bases, attrs): start = 0 unnumbered = [] valueToName = {} nameToValue = {} for item, value in attrs.items(): if isinstance(value, classmethod): continue if item.startswith("_"): continue if value is None: unnumbered.append(item) continue elif value >= start: start = value + 1 valueToName[value] = item nameToValue[item] = value for value, item in enumerate(sorted(unnumbered)): attrs[item] = value + start valueToName[value + start] = item nameToValue[item] = value + start attrs["_valueToName"] = valueToName attrs["_nameToValue"] = nameToValue return type.__new__(cls, name, bases, attrs) def __len__(self): """ Return the number of enum items. """ return len(self._valueToName) def __getitem__(self, index): """ Returns the string representation for an index. """ if index < 0: return sorted(self._valueToName.items())[index][1] return self._valueToName[index] class Enum(object): """ Subclass to define a basic enum class. Assing values to enum items or assign them to None for auto-numbering. Note that numbering occurs in alphabetical order. Example: >>> class Weapon(Enum): ... shortSword = None ... dagger = 2 ... mace = 43 ... bow = None ... >>> Weapon.shortSword 45 >>> Weapon.mace 43 >>> Weapon.bow 44 See the unit tests for more examples. """ __metaclass__ = MetaEnum _valueToName = None _nameToValue = None @classmethod def values(self): """ Returns all the enum values. """ return self._nameToValue.values() @classmethod def keys(self): """ Returns all the enum names. """ return self._nameToValue.keys() @classmethod def items(self): """ Returns tuples of (name, value) for each enum entry. """ return self._nameToValue.items()