1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
|
# UpdateManager/Util/enum.py
#
# Copyright (c) 2009 Canonical
# 2009 Stephan Peijnik
#
# Author: Stephan Peijnik <debian@sp.or.at>
#
# 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.
""" Implementation of autodoc-aware Enum for Python """
class Enum(object):
""" Simple autodoc-aware C-like enumeration.
All enumeration names must be upper case and may not contain spaces, see
below for examples.
>>> ReturnCodes = Enum('SUCCESS', ERROR='A non-fatal error occured',
FATAL='A fatal error occured')
>>> ReturnCodes.SUCCESS
0
.. note:: When using values with docstring the values are ordered
alphabetically by their name. This is caused by how the dict type
works.
"""
_enum_name = ':class:`Enum<UpdateManager.Util.enum.Enum>`'
_allowed_characters = None
def __init__(self, *names, **names_with_doc):
"""
Creates an enumeration and updates the docstring of the generated
object.
:param *names: A list of enumeration names without a docstring.
:param **names_with_doc: A dictionary of enumeration names and their
docstrings. The key forms the name, whilst the value represents
the docstring.
All enumeration names must be upper case and may not contain spaces.
Example::
ReturnCodes = Enum('SUCCESS', ERROR='A non-fatal error occured',
FATAL='A fatal error occured')
NegativeCodes = Enum('UI_ERROR', negative=True,
BACKEND_ERROR='Backend error')
"""
self.__doc__ = '''%s:
''' % (self._enum_name)
for i in range(0, len(names)):
value = self._nodoc_id_to_value(i)
self._name_sanity_check(names[i])
self.__dict__[names[i]] = value
self.__doc__ += '''**%s** = *%d*
''' % (names[i], value)
i = self._doc_first_value(len(names))
for name in names_with_doc.keys():
self._name_sanity_check(name)
self.__dict__[name] = i
docstring = names_with_doc[name]
if type(docstring) != str:
raise TypeError('Values of kwargs must be (doc-)strings.')
self.__doc__ += '''**%s** = *%d*
%s
''' % (name, i, names_with_doc[name])
i = self._doc_next_value(i)
self.__doc__ += '\n'
@classmethod
def _nodoc_id_to_value(cls, identity):
""" Map ids of names without a docstring to a value
:param id: Name id
"""
return identity
@classmethod
def _doc_next_value(cls, value):
""" Gets the next value """
return value+1
@classmethod
def _doc_first_value(cls, nodoc_max_value):
""" Gets the first value """
return nodoc_max_value
def _name_sanity_check(self, name):
""" Checks an enum name for sanity.
Names may only consist of uppercase, characters and are limited
to the values A-Z, 0-9 and _ (underscore).
"""
if getattr(self, '_allowed_characters', None):
allowed_characters = self._allowed_characters
else:
allowed_characters = '_'
# Build the allowed character list.
for i in range(ord('A'), ord('Z')+1):
allowed_characters += chr(i)
for i in range(ord('0'), ord('9')+1):
allowed_characters += chr(i)
for i in range(0, len(name)):
char = name[i]
if char not in allowed_characters:
e_msg = 'Enumeration names may only consist of '+\
'uppercase letters, numbers and underscores:\n'
e_msg += '%s\n' % (name)
j = 0
while (j < i):
e_msg += ' '
j += 1
e_msg += '^'
raise TypeError(e_msg)
def __getattr__(self, name):
""" Custom attribute resolution """
if name in self.__dict__:
return self.__dict__['name']
raise AttributeError(name)
def __setattr__(self, name, value):
""" Only the __doc__ attribute may be set """
if name != '__doc__':
raise TypeError('Cannot set values of %s objects.' \
% (self.__class__.__name__))
else:
self.__dict__['__doc__'] = value
def __delattr__(self, name):
""" No attributes may be deleted """
raise TypeError('Cannot delete values of %s objects.' \
% (self.__class__.__name__))
class NegativeEnum(Enum):
"""
Simple autodoc-aware C-like negative enumeration.
The difference to :class:`Enum` is that values are assigned starting at
*-1* downwards.
>>> NegativeCodes = Enum('UI_ERROR', negative=True,
BACKEND_ERROR='Backend error')
>>> NegativeCodes.UI_ERROR
-1
"""
_enum_name = ':class:`NegativeEnum<UpdateManager.Util.enum.NegativeEnum>`'
@classmethod
def _nodoc_id_to_value(cls, identity):
""" Map ids of names without a docstring to a value
:param id: Name id
"""
return -(identity+1)
@classmethod
def _doc_next_value(cls, value):
""" Gets next value """
return value-1
@classmethod
def _doc_first_value(cls, nodoc_max_value):
""" Gets first value """
return (nodoc_max_value*-1)-1
|