diff options
Diffstat (limited to 'Mailman/enum.py')
| -rw-r--r-- | Mailman/enum.py | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/Mailman/enum.py b/Mailman/enum.py new file mode 100644 index 000000000..fc05ff5b1 --- /dev/null +++ b/Mailman/enum.py @@ -0,0 +1,132 @@ +# Copyright (C) 2004-2007 by the Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA. + +"""Enumeration meta class. + +To define your own enumeration, do something like: + +>>> class Colors(Enum): +... red = 1 +... green = 2 +... blue = 3 + +Enum subclasses cannot be instantiated, but you can convert them to integers +and from integers. Returned enumeration attributes are singletons and can be +compared by identity only. +""" + +COMMASPACE = ', ' + +# Based on example by Jeremy Hylton +# Modified and extended by Barry Warsaw + + + +class EnumMetaclass(type): + def __init__(cls, name, bases, dict): + # cls == the class being defined + # name == the name of the class + # bases == the class's bases + # dict == the class attributes + super(EnumMetaclass, cls).__init__(name, bases, dict) + # Store EnumValues here for easy access. + cls._enums = {} + # Figure out the set of enum values on the base classes, to ensure + # that we don't get any duplicate values (which would screw up + # conversion from integer). + for basecls in cls.__mro__: + if hasattr(basecls, '_enums'): + cls._enums.update(basecls._enums) + # For each class attribute, create an EnumValue and store that back on + # the class instead of the int. Skip Python reserved names. Also add + # a mapping from the integer to the instance so we can return the same + # object on conversion. + for attr in dict: + if not (attr.startswith('__') and attr.endswith('__')): + intval = dict[attr] + enumval = EnumValue(name, intval, attr) + if intval in cls._enums: + raise TypeError('Multiple enum values: %s' % enumval) + # Store as an attribute on the class, and save the attr name + setattr(cls, attr, enumval) + cls._enums[intval] = attr + + def __getattr__(cls, name): + if name == '__members__': + return cls._enums.values() + raise AttributeError(name) + + def __repr__(cls): + enums = ['%s: %d' % (cls._enums[k], k) for k in sorted(cls._enums)] + return '<%s {%s}>' % (cls.__name__, COMMASPACE.join(enums)) + + def __iter__(cls): + for i in sorted(self._enums): + yield self._enums[i] + + def __getitem__(cls, i): + # i can be an integer or a string + attr = cls._enums.get(i) + if attr is None: + # It wasn't an integer -- try attribute name + try: + return getattr(cls, i) + except (AttributeError, TypeError): + raise ValueError(i) + return getattr(cls, attr) + + # Support both MyEnum[i] and MyEnum(i) + __call__ = __getitem__ + + + +class EnumValue(object): + """Class to represent an enumeration value. + + EnumValue('Color', 'red', 12) prints as 'Color.red' and can be converted + to the integer 12. + """ + def __init__(self, classname, value, enumname): + self._classname = classname + self._value = value + self._enumname = enumname + + def __repr__(self): + return 'EnumValue(%s, %s, %d)' % ( + self._classname, self._enumname, self._value) + + def __str__(self): + return self._enumname + + def __int__(self): + return self._value + + # Support only comparison by identity. Yes, really raise + # NotImplementedError instead of returning NotImplemented. + def __eq__(self, other): + raise NotImplementedError + + __ne__ = __eq__ + __lt__ = __eq__ + __gt__ = __eq__ + __le__ = __eq__ + __ge__ = __eq__ + + + +class Enum: + __metaclass__ = EnumMetaclass |
