RSS

(root)/update-manager/devel/gsoc09 : /UpdateManager/Util/enum.py (revision 1495)

To get this branch, use:
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