127e4aa316875b1e5ad7fd85f93707ddf4fdba063Guido van Rossum"""Enumeration metaclass.
227e4aa316875b1e5ad7fd85f93707ddf4fdba063Guido van Rossum
327e4aa316875b1e5ad7fd85f93707ddf4fdba063Guido van RossumXXX This is very much a work in progress.
427e4aa316875b1e5ad7fd85f93707ddf4fdba063Guido van Rossum
527e4aa316875b1e5ad7fd85f93707ddf4fdba063Guido van Rossum"""
6bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
7bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossumimport string
8bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
9bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossumclass EnumMetaClass:
10bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    """Metaclass for enumeration.
11bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
12bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    To define your own enumeration, do something like
13bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
14bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    class Color(Enum):
154117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        red = 1
164117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        green = 2
174117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        blue = 3
18bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
19bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    Now, Color.red, Color.green and Color.blue behave totally
20bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    different: they are enumerated values, not integers.
21bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
22bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    Enumerations cannot be instantiated; however they can be
23bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    subclassed.
24bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
25bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    """
26bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
27bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    def __init__(self, name, bases, dict):
284117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        """Constructor -- create an enumeration.
294117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum
304117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        Called at the end of the class statement.  The arguments are
314117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        the name of the new class, a tuple containing the base
324117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        classes, and a dictionary containing everything that was
334117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        entered in the class' namespace during execution of the class
344117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        statement.  In the above example, it would be {'red': 1,
354117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        'green': 2, 'blue': 3}.
364117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum
374117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        """
384117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        for base in bases:
394117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum            if base.__class__ is not EnumMetaClass:
404117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum                raise TypeError, "Enumeration base class must be enumeration"
414117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        bases = filter(lambda x: x is not Enum, bases)
424117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        self.__name__ = name
434117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        self.__bases__ = bases
444117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        self.__dict = {}
454117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        for key, value in dict.items():
464117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum            self.__dict[key] = EnumInstance(name, key, value)
47bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
48bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    def __getattr__(self, name):
494117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        """Return an enumeration value.
50bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
514117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        For example, Color.red returns the value corresponding to red.
52bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
534117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        XXX Perhaps the values should be created in the constructor?
54bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
554117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        This looks in the class dictionary and if it is not found
564117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        there asks the base classes.
57bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
584117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        The special attribute __members__ returns the list of names
594117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        defined in this class (it does not merge in the names defined
604117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        in base classes).
61bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
624117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        """
634117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        if name == '__members__':
644117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum            return self.__dict.keys()
65bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
664117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        try:
674117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum            return self.__dict[name]
684117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        except KeyError:
694117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum            for base in self.__bases__:
704117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum                try:
714117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum                    return getattr(base, name)
724117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum                except AttributeError:
734117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum                    continue
74bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
754117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        raise AttributeError, name
76bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
77bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    def __repr__(self):
784117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        s = self.__name__
794117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        if self.__bases__:
804117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum            s = s + '(' + string.join(map(lambda x: x.__name__,
814117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum                                          self.__bases__), ", ") + ')'
824117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        if self.__dict:
834117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum            list = []
844117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum            for key, value in self.__dict.items():
854117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum                list.append("%s: %s" % (key, int(value)))
864117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum            s = "%s: {%s}" % (s, string.join(list, ", "))
874117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        return s
88bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
89bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
90bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossumclass EnumInstance:
91bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    """Class to represent an enumeration value.
92bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
93bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    EnumInstance('Color', 'red', 12) prints as 'Color.red' and behaves
94bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    like the integer 12 when compared, but doesn't support arithmetic.
95bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
96bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    XXX Should it record the actual enumeration rather than just its
97bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    name?
98bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
99bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    """
100bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
101bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    def __init__(self, classname, enumname, value):
1024117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        self.__classname = classname
1034117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        self.__enumname = enumname
1044117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        self.__value = value
105bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
106bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    def __int__(self):
1074117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        return self.__value
108bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
109bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    def __repr__(self):
11070a6b49821a3226f55e9716f32d802d06640cb89Walter Dörwald        return "EnumInstance(%r, %r, %r)" % (self.__classname,
11170a6b49821a3226f55e9716f32d802d06640cb89Walter Dörwald                                             self.__enumname,
11270a6b49821a3226f55e9716f32d802d06640cb89Walter Dörwald                                             self.__value)
113bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
114bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    def __str__(self):
1154117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        return "%s.%s" % (self.__classname, self.__enumname)
116bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
117bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    def __cmp__(self, other):
1184117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        return cmp(self.__value, int(other))
119bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
120bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
121bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum# Create the base class for enumerations.
122bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum# It is an empty enumeration.
123bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van RossumEnum = EnumMetaClass("Enum", (), {})
124bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
125bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
126bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossumdef _test():
127bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
128bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    class Color(Enum):
1294117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        red = 1
1304117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        green = 2
1314117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        blue = 3
132bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
133bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    print Color.red
134bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    print dir(Color)
135bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
136bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    print Color.red == Color.red
137bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    print Color.red == Color.blue
138bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    print Color.red == 1
139bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    print Color.red == 2
140bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
141bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    class ExtendedColor(Color):
1424117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        white = 0
1434117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        orange = 4
1444117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        yellow = 5
1454117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        purple = 6
1464117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        black = 7
147bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
148bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    print ExtendedColor.orange
149bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    print ExtendedColor.red
150bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
151bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    print Color.red == ExtendedColor.red
152bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
153bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    class OtherColor(Enum):
1544117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        white = 4
1554117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        blue = 5
156bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
157bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    class MergedColor(Color, OtherColor):
1584117e5428bf1ff3d26d23bd77472265412473ad9Guido van Rossum        pass
159bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
160bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    print MergedColor.red
161bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    print MergedColor.white
162bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
163bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    print Color
164bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    print ExtendedColor
165bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    print OtherColor
166bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    print MergedColor
167bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum
168bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossumif __name__ == '__main__':
169bff110f3f10027cf03457556e42af2d3d87d5e7fGuido van Rossum    _test()
170