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