1 # -*- coding: utf-8 -*-
4 # Part of enum, a package providing enumerated types for Python.
6 # Copyright © 2007–2009 Ben Finney <ben+python@benfinney.id.au>
7 # This is free software; you may copy, modify and/or distribute this work
8 # under the terms of the GNU General Public License, version 2 or later
9 # or, at your option, the terms of the Python license.
11 """ Robust enumerated type support in Python.
13 This package provides a module for robust enumerations in Python.
15 An enumeration object is created with a sequence of string arguments
16 to the Enum() constructor::
18 >>> from enum import Enum
19 >>> Colours = Enum('red', 'blue', 'green')
20 >>> Weekdays = Enum('mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun')
22 The return value is an immutable sequence object with a value for each
23 of the string arguments. Each value is also available as an attribute
24 named from the corresponding string argument::
26 >>> pizza_night = Weekdays[4]
27 >>> shirt_colour = Colours.green
29 The values are constants that can be compared only with values from
30 the same enumeration; comparison with other values will invoke
31 Python's fallback comparisons::
33 >>> pizza_night == Weekdays.fri
35 >>> shirt_colour > Colours.red
37 >>> shirt_colour == "green"
40 Each value from an enumeration exports its sequence index
41 as an integer, and can be coerced to a simple string matching the
42 original arguments used to create the enumeration::
46 >>> shirt_colour.index
51 __author_name__
= "Ben Finney"
52 __author_email__
= "ben+python@benfinney.id.au"
53 __author__
= "%(__author_name__)s <%(__author_email__)s>" % vars()
55 _copyright_year_begin
= "2007"
56 __date__
= "2009-08-26"
57 _copyright_year_latest
= __date__
.split('-')[0]
58 _copyright_year_range
= _copyright_year_begin
59 if _copyright_year_latest
> _copyright_year_begin
:
60 _copyright_year_range
+= "–%(_copyright_year_latest)s" % vars()
62 "Copyright © %(_copyright_year_range)s"
63 " %(__author_name__)s") % vars()
64 __license__
= "Choice of GPL or Python license"
66 __url__
= "http://pypi.python.org/pypi/enum/"
70 class EnumException(Exception):
71 """ Base class for all exceptions in this module. """
73 def __init__(self
, *args
, **kwargs
):
74 if self
.__class
__ is EnumException
:
75 class_name
= self
.__class
__.__name
__
76 raise NotImplementedError(
77 "%(class_name)s is an abstract base class" % vars())
78 super(EnumException
, self
).__init
__(*args
, **kwargs
)
81 class EnumEmptyError(AssertionError, EnumException
):
82 """ Raised when attempting to create an empty enumeration. """
85 return "Enumerations cannot be empty"
88 class EnumBadKeyError(TypeError, EnumException
):
89 """ Raised when creating an Enum with non-string keys. """
91 def __init__(self
, key
):
95 return "Enumeration keys must be strings: %(key)r" % vars(self
)
98 class EnumImmutableError(TypeError, EnumException
):
99 """ Raised when attempting to modify an Enum. """
101 def __init__(self
, *args
):
105 return "Enumeration does not allow modification"
108 def _comparator(func
):
109 """ Decorator for EnumValue rich comparison methods. """
110 def comparator_wrapper(self
, other
):
112 assert self
.enumtype
== other
.enumtype
113 result
= func(self
.index
, other
.index
)
114 except (AssertionError, AttributeError):
115 result
= NotImplemented
118 comparator_wrapper
.__name
__ = func
.__name
__
119 comparator_wrapper
.__doc
__ = getattr(float, func
.__name
__).__doc
__
120 return comparator_wrapper
122 class EnumValue(object):
123 """ A specific value of an enumerated type. """
125 def __init__(self
, enumtype
, index
, key
):
126 """ Set up a new instance. """
127 self
._enumtype
= enumtype
133 return self
._enumtype
147 return "EnumValue(%(_enumtype)r, %(_index)r, %(_key)r)" % vars(self
)
150 return hash(self
._index
)
153 def __eq__(self
, other
):
154 return (self
== other
)
157 def __ne__(self
, other
):
158 return (self
!= other
)
161 def __lt__(self
, other
):
162 return (self
< other
)
165 def __le__(self
, other
):
166 return (self
<= other
)
169 def __gt__(self
, other
):
170 return (self
> other
)
173 def __ge__(self
, other
):
174 return (self
>= other
)
178 """ Enumerated type. """
180 def __init__(self
, *keys
, **kwargs
):
181 """ Create an enumeration instance. """
183 value_type
= kwargs
.get('value_type', EnumValue
)
186 raise EnumEmptyError()
189 values
= [None] * len(keys
)
191 for i
, key
in enumerate(keys
):
192 value
= value_type(self
, i
, key
)
195 super(Enum
, self
).__setattr
__(key
, value
)
197 raise EnumBadKeyError(key
)
199 self
.__dict
__['_keys'] = keys
200 self
.__dict
__['_values'] = values
202 def __setattr__(self
, name
, value
):
203 raise EnumImmutableError(name
)
205 def __delattr__(self
, name
):
206 raise EnumImmutableError(name
)
209 return len(self
._values
)
211 def __getitem__(self
, index
):
212 return self
._values
[index
]
214 def __setitem__(self
, index
, value
):
215 raise EnumImmutableError(index
)
217 def __delitem__(self
, index
):
218 raise EnumImmutableError(index
)
221 return iter(self
._values
)
223 def __contains__(self
, value
):
225 if isinstance(value
, basestring
):
226 is_member
= (value
in self
._keys
)
228 is_member
= (value
in self
._values
)
234 # time-stamp-format: "%:y-%02m-%02d"
235 # time-stamp-start: "__date__ = \""
236 # time-stamp-end: "\"$"
237 # time-stamp-line-limit: 200
239 # vim: filetype=python fileencoding=utf-8 :