| 
									
										
										
										
											2002-07-11 21:08:06 +00:00
										 |  |  | """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 = [] | 
					
						
							| 
									
										
										
										
											2007-08-06 21:07:53 +00:00
										 |  |  |         for attr in dict.keys(): | 
					
						
							| 
									
										
										
										
											2002-07-11 21:08:06 +00:00
										 |  |  |             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 | 
					
						
							| 
									
										
										
										
											2007-07-17 20:59:35 +00:00
										 |  |  |         raise AttributeError(name) | 
					
						
							| 
									
										
										
										
											2002-07-11 21:08:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     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) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-27 20:34:09 +00:00
										 |  |  | class Enum(metaclass=EnumMetaclass): | 
					
						
							|  |  |  |     pass | 
					
						
							| 
									
										
										
										
											2002-07-11 21:08:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-27 20:34:09 +00:00
										 |  |  | class FullEnum(metaclass=FullEnumMetaclass): | 
					
						
							|  |  |  |     pass | 
					
						
							| 
									
										
										
										
											2002-07-11 21:08:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def _test(): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class Color(Enum): | 
					
						
							|  |  |  |         red = 1 | 
					
						
							|  |  |  |         green = 2 | 
					
						
							|  |  |  |         blue = 3 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-17 20:59:35 +00:00
										 |  |  |     print(Color.red) | 
					
						
							| 
									
										
										
										
											2002-07-11 21:08:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-17 20:59:35 +00:00
										 |  |  |     print(repr(Color.red)) | 
					
						
							|  |  |  |     print(Color.red == Color.red) | 
					
						
							|  |  |  |     print(Color.red == Color.blue) | 
					
						
							|  |  |  |     print(Color.red == 1) | 
					
						
							|  |  |  |     print(Color.red == 2) | 
					
						
							| 
									
										
										
										
											2002-07-11 21:08:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     class ExtendedColor(Color): | 
					
						
							|  |  |  |         white = 0 | 
					
						
							|  |  |  |         orange = 4 | 
					
						
							|  |  |  |         yellow = 5 | 
					
						
							|  |  |  |         purple = 6 | 
					
						
							|  |  |  |         black = 7 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-17 20:59:35 +00:00
										 |  |  |     print(ExtendedColor.orange) | 
					
						
							|  |  |  |     print(ExtendedColor.red) | 
					
						
							| 
									
										
										
										
											2002-07-11 21:08:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-17 20:59:35 +00:00
										 |  |  |     print(Color.red == ExtendedColor.red) | 
					
						
							| 
									
										
										
										
											2002-07-11 21:08:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     class OtherColor(Enum): | 
					
						
							|  |  |  |         white = 4 | 
					
						
							|  |  |  |         blue = 5 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class MergedColor(Color, OtherColor): | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-17 20:59:35 +00:00
										 |  |  |     print(MergedColor.red) | 
					
						
							|  |  |  |     print(MergedColor.white) | 
					
						
							| 
									
										
										
										
											2002-07-11 21:08:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-17 20:59:35 +00:00
										 |  |  |     print(Color) | 
					
						
							|  |  |  |     print(ExtendedColor) | 
					
						
							|  |  |  |     print(OtherColor) | 
					
						
							|  |  |  |     print(MergedColor) | 
					
						
							| 
									
										
										
										
											2002-07-11 21:08:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def _test2(): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class Color(FullEnum): | 
					
						
							|  |  |  |         red = 1 | 
					
						
							|  |  |  |         green = 2 | 
					
						
							|  |  |  |         blue = 3 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-17 20:59:35 +00:00
										 |  |  |     print(Color.red) | 
					
						
							| 
									
										
										
										
											2002-07-11 21:08:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-17 20:59:35 +00:00
										 |  |  |     print(repr(Color.red)) | 
					
						
							|  |  |  |     print(Color.red == Color.red) | 
					
						
							|  |  |  |     print(Color.red == Color.blue) | 
					
						
							|  |  |  |     print(Color.red == 1) | 
					
						
							|  |  |  |     print(Color.red == 2) | 
					
						
							| 
									
										
										
										
											2002-07-11 21:08:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     class ExtendedColor(Color): | 
					
						
							|  |  |  |         white = 0 | 
					
						
							|  |  |  |         orange = 4 | 
					
						
							|  |  |  |         yellow = 5 | 
					
						
							|  |  |  |         purple = 6 | 
					
						
							|  |  |  |         black = 7 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-17 20:59:35 +00:00
										 |  |  |     print(ExtendedColor.orange) | 
					
						
							|  |  |  |     print(ExtendedColor.red) | 
					
						
							| 
									
										
										
										
											2002-07-11 21:08:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-17 20:59:35 +00:00
										 |  |  |     print(Color.red == ExtendedColor.red) | 
					
						
							| 
									
										
										
										
											2002-07-11 21:08:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     class OtherColor(FullEnum): | 
					
						
							|  |  |  |         white = 4 | 
					
						
							|  |  |  |         blue = 5 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class MergedColor(Color, OtherColor): | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-17 20:59:35 +00:00
										 |  |  |     print(MergedColor.red) | 
					
						
							|  |  |  |     print(MergedColor.white) | 
					
						
							| 
									
										
										
										
											2002-07-11 21:08:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-17 20:59:35 +00:00
										 |  |  |     print(Color) | 
					
						
							|  |  |  |     print(ExtendedColor) | 
					
						
							|  |  |  |     print(OtherColor) | 
					
						
							|  |  |  |     print(MergedColor) | 
					
						
							| 
									
										
										
										
											2002-07-11 21:08:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | if __name__ == '__main__': | 
					
						
							|  |  |  |     _test() | 
					
						
							|  |  |  |     _test2() |