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
|
class MetaFastEnum(type):
def __new__(mcs, name, bases, dct):
if name == "FastEnum":
return type.__new__(mcs, name, bases, dct)
assert bases == (FastEnum,) , "Multiple inheritance with Fast enums is not currently supported."
dunder_values = {}
normal_values = {}
for key, value in dct.items():
if key.startswith("__") and key.endswith("__"):
dunder_values[key] = value
else:
normal_values[key] = value
kls = type.__new__(mcs, name, bases, dunder_values)
mcs.set_values(kls, normal_values)
return kls
@classmethod
def set_values(mcs, kls, data):
value_to_entry = {}
assert len(set(data.values())) == len(data.values()), "Values for {} are not unique".format(kls)
assert len(set(type(value) for value in data.values())) <= 1, \
"Values of {} are of heterogeneous types".format(kls)
for key, value in data.items():
new_value = object.__new__(kls)
object.__setattr__(new_value, "value", value)
object.__setattr__(new_value, "name", key)
type.__setattr__(kls, key, new_value)
value_to_entry[value] = new_value
type.__setattr__(kls, "_value_to_entry", value_to_entry)
def __repr__(self):
return "<fastenum '{}'>".format(self.__name__)
class FastEnum(metaclass=MetaFastEnum):
def __new__(cls, value):
try:
return cls._value_to_entry[value]
except KeyError:
if type(value) is cls:
return value
raise
def __setattr__(self, key, value):
raise ValueError("Adding new values to an enum dynamically is not supported")
def __str__(self):
return "{}.{}".format(self.__class__.__name__, self.name)
def __reduce__(self):
return self.__class__, (self.value,)
def __lt__(self, other):
if type(self) != type(other):
return NotImplemented
return self.value < other.value
def __ge__(self, other):
if type(self) != type(other):
return NotImplemented
return self.value >= other.value
|