1
2class EnumValue(object):
3    def __init__(self, value, name=None):
4        self.value = value
5        self.name = name
6
7    def __hash__(self):
8        return self.value
9
10    def __cmp__(self, other):
11        if isinstance(other, EnumValue):
12            return self.value.__cmp__(other.value)
13        else:
14            return self.value.__cmp__(other)
15
16    def __unicode__(self):
17        return self.name
18
19    def __str__(self):
20        return self.name
21
22    def __repr__(self):
23        return self.name
24
25
26class EnumMeta(type):
27    def __init__(self, name, bases, dict_):
28        self.registry = self.registry.copy()
29        self.name_registry = self.name_registry.copy()
30        for k, v in dict_.iteritems():
31            if isinstance(v, EnumValue) and v not in self.registry:
32                if v.name is None:
33                    v.name = k
34                self.registry[v.value] = v
35                self.name_registry[v.name] = v
36        return super(EnumMeta, self).__init__(name, bases, dict_)
37
38    def __iter__(self):
39        return self.registry.itervalues()
40
41    def __getitem__(self, key):
42        return self.registry[key]
43
44
45class Enum(object):
46    __metaclass__ = EnumMeta
47    registry = {}
48    name_registry = {}
49
50    @classmethod
51    def from_id(cls, value):
52        try:
53            return cls.registry[value]
54        except KeyError:
55            raise ValueError('Invalid value for {}: {}'.format(cls.__name__, value))
56
57    @classmethod
58    def from_string(cls, name):
59        try:
60            return cls.name_registry[name]
61        except KeyError:
62            raise ValueError('Invalid name for {}: {}'.format(cls.__name__, name))
63