| """Enumeration metaclass.""" | 
 |  | 
 | class EnumMetaclass(type): | 
 |     """Metaclass for enumeration. | 
 |  | 
 |     To define your own enumeration, do something like | 
 |  | 
 |     class Color(Enum): | 
 |         red = 1 | 
 |         green = 2 | 
 |         blue = 3 | 
 |  | 
 |     Now, Color.red, Color.green and Color.blue behave totally | 
 |     different: they are enumerated values, not integers. | 
 |  | 
 |     Enumerations cannot be instantiated; however they can be | 
 |     subclassed. | 
 |     """ | 
 |  | 
 |     def __init__(cls, name, bases, dict): | 
 |         super(EnumMetaclass, cls).__init__(name, bases, dict) | 
 |         cls._members = [] | 
 |         for attr in dict.keys(): | 
 |             if not (attr.startswith('__') and attr.endswith('__')): | 
 |                 enumval = EnumInstance(name, attr, dict[attr]) | 
 |                 setattr(cls, attr, enumval) | 
 |                 cls._members.append(attr) | 
 |  | 
 |     def __getattr__(cls, name): | 
 |         if name == "__members__": | 
 |             return cls._members | 
 |         raise AttributeError(name) | 
 |  | 
 |     def __repr__(cls): | 
 |         s1 = s2 = "" | 
 |         enumbases = [base.__name__ for base in cls.__bases__ | 
 |                      if isinstance(base, EnumMetaclass) and not base is Enum] | 
 |         if enumbases: | 
 |             s1 = "(%s)" % ", ".join(enumbases) | 
 |         enumvalues = ["%s: %d" % (val, getattr(cls, val)) | 
 |                       for val in cls._members] | 
 |         if enumvalues: | 
 |             s2 = ": {%s}" % ", ".join(enumvalues) | 
 |         return "%s%s%s" % (cls.__name__, s1, s2) | 
 |  | 
 | class FullEnumMetaclass(EnumMetaclass): | 
 |     """Metaclass for full enumerations. | 
 |  | 
 |     A full enumeration displays all the values defined in base classes. | 
 |     """ | 
 |  | 
 |     def __init__(cls, name, bases, dict): | 
 |         super(FullEnumMetaclass, cls).__init__(name, bases, dict) | 
 |         for obj in cls.__mro__: | 
 |             if isinstance(obj, EnumMetaclass): | 
 |                 for attr in obj._members: | 
 |                     # XXX inefficient | 
 |                     if not attr in cls._members: | 
 |                         cls._members.append(attr) | 
 |  | 
 | class EnumInstance(int): | 
 |     """Class to represent an enumeration value. | 
 |  | 
 |     EnumInstance('Color', 'red', 12) prints as 'Color.red' and behaves | 
 |     like the integer 12 when compared, but doesn't support arithmetic. | 
 |  | 
 |     XXX Should it record the actual enumeration rather than just its | 
 |     name? | 
 |     """ | 
 |  | 
 |     def __new__(cls, classname, enumname, value): | 
 |         return int.__new__(cls, value) | 
 |  | 
 |     def __init__(self, classname, enumname, value): | 
 |         self.__classname = classname | 
 |         self.__enumname = enumname | 
 |  | 
 |     def __repr__(self): | 
 |         return "EnumInstance(%s, %s, %d)" % (self.__classname, self.__enumname, | 
 |                                              self) | 
 |  | 
 |     def __str__(self): | 
 |         return "%s.%s" % (self.__classname, self.__enumname) | 
 |  | 
 | class Enum(metaclass=EnumMetaclass): | 
 |     pass | 
 |  | 
 | class FullEnum(metaclass=FullEnumMetaclass): | 
 |     pass | 
 |  | 
 | def _test(): | 
 |  | 
 |     class Color(Enum): | 
 |         red = 1 | 
 |         green = 2 | 
 |         blue = 3 | 
 |  | 
 |     print(Color.red) | 
 |  | 
 |     print(repr(Color.red)) | 
 |     print(Color.red == Color.red) | 
 |     print(Color.red == Color.blue) | 
 |     print(Color.red == 1) | 
 |     print(Color.red == 2) | 
 |  | 
 |     class ExtendedColor(Color): | 
 |         white = 0 | 
 |         orange = 4 | 
 |         yellow = 5 | 
 |         purple = 6 | 
 |         black = 7 | 
 |  | 
 |     print(ExtendedColor.orange) | 
 |     print(ExtendedColor.red) | 
 |  | 
 |     print(Color.red == ExtendedColor.red) | 
 |  | 
 |     class OtherColor(Enum): | 
 |         white = 4 | 
 |         blue = 5 | 
 |  | 
 |     class MergedColor(Color, OtherColor): | 
 |         pass | 
 |  | 
 |     print(MergedColor.red) | 
 |     print(MergedColor.white) | 
 |  | 
 |     print(Color) | 
 |     print(ExtendedColor) | 
 |     print(OtherColor) | 
 |     print(MergedColor) | 
 |  | 
 | def _test2(): | 
 |  | 
 |     class Color(FullEnum): | 
 |         red = 1 | 
 |         green = 2 | 
 |         blue = 3 | 
 |  | 
 |     print(Color.red) | 
 |  | 
 |     print(repr(Color.red)) | 
 |     print(Color.red == Color.red) | 
 |     print(Color.red == Color.blue) | 
 |     print(Color.red == 1) | 
 |     print(Color.red == 2) | 
 |  | 
 |     class ExtendedColor(Color): | 
 |         white = 0 | 
 |         orange = 4 | 
 |         yellow = 5 | 
 |         purple = 6 | 
 |         black = 7 | 
 |  | 
 |     print(ExtendedColor.orange) | 
 |     print(ExtendedColor.red) | 
 |  | 
 |     print(Color.red == ExtendedColor.red) | 
 |  | 
 |     class OtherColor(FullEnum): | 
 |         white = 4 | 
 |         blue = 5 | 
 |  | 
 |     class MergedColor(Color, OtherColor): | 
 |         pass | 
 |  | 
 |     print(MergedColor.red) | 
 |     print(MergedColor.white) | 
 |  | 
 |     print(Color) | 
 |     print(ExtendedColor) | 
 |     print(OtherColor) | 
 |     print(MergedColor) | 
 |  | 
 | if __name__ == '__main__': | 
 |     _test() | 
 |     _test2() |