~ubuntu-branches/ubuntu/vivid/grass/vivid-proposed

« back to all changes in this revision

Viewing changes to lib/python/pygrass/modules/interface/parameter.py

  • Committer: Package Import Robot
  • Author(s): Bas Couwenberg
  • Date: 2015-02-20 23:12:08 UTC
  • mfrom: (8.2.6 experimental)
  • Revision ID: package-import@ubuntu.com-20150220231208-1u6qvqm84v430b10
Tags: 7.0.0-1~exp1
* New upstream release.
* Update python-ctypes-ternary.patch to use if/else instead of and/or.
* Drop check4dev patch, rely on upstream check.
* Add build dependency on libpq-dev to grass-dev for libpq-fe.h.
* Drop patches applied upstream, refresh remaining patches.
* Update symlinks for images switched from jpg to png.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
"""
 
3
Created on Tue Apr  2 18:31:47 2013
 
4
 
 
5
@author: pietro
 
6
"""
 
7
from __future__ import (nested_scopes, generators, division, absolute_import,
 
8
                        with_statement, print_function, unicode_literals)
 
9
import re
 
10
 
 
11
from grass.pygrass.utils import docstring_property
 
12
from grass.pygrass.modules.interface.read import GETTYPE, element2dict, DOC
 
13
 
 
14
 
 
15
def _check_value(param, value):
 
16
    """Function to check the correctness of a value and
 
17
    return the checked value and the original.
 
18
    """
 
19
    must_val = 'The Parameter <%s>, must be one of the following values: %r'
 
20
    req = 'The Parameter <%s>, require: %s, get: %s instead: %r\n%s'
 
21
 
 
22
    def raiseexcpet(exc, param, ptype, value):
 
23
        """Function to modifa the error message"""
 
24
        msg = req % (param.name, param.typedesc, ptype, value, exc.message)
 
25
        if exc is ValueError:
 
26
            raise ValueError(msg)
 
27
        elif exc is TypeError:
 
28
            raise TypeError(msg)
 
29
        else:
 
30
            exc.message = msg
 
31
            raise exc
 
32
 
 
33
    def check_string(value):
 
34
        """Function to check that a string parameter is already a string"""
 
35
        string = (str, unicode)
 
36
        if param.type in string:
 
37
            if type(value) in (int, float):
 
38
                value = str(value)
 
39
            if type(value) not in string:
 
40
                msg = ("The Parameter <%s> require a string,"
 
41
                       " %s instead is provided: %r")
 
42
                raise ValueError(msg % (param.name, type(value), value))
 
43
        return value
 
44
 
 
45
    # return None if None
 
46
    if value is None:
 
47
        return param.default, param.default
 
48
 
 
49
    # find errors with multiple parmeters
 
50
    if isinstance(value, (list, tuple)):
 
51
        if param.keydescvalues:
 
52
            return (([value, ], value) if isinstance(value, tuple)
 
53
                    else (value, value))
 
54
        if param.multiple:
 
55
            # everything looks fine, so check each value
 
56
            try:
 
57
                return [param.type(check_string(val)) for val in value], value
 
58
            except Exception as exc:
 
59
                raiseexcpet(exc, param, param.type, value)
 
60
        else:
 
61
            msg = 'The Parameter <%s> does not accept multiple inputs'
 
62
            raise TypeError(msg % param.name)
 
63
 
 
64
    if param.keydescvalues:
 
65
        msg = 'The Parameter <%s> require multiple inputs in the form: %s'
 
66
        raise TypeError(msg % (param.name, param.keydescvalues))
 
67
 
 
68
    if param.typedesc == 'all':
 
69
        return value, value
 
70
 
 
71
    # check string before trying to convert value to the correct type
 
72
    check_string(value)
 
73
    # the value is a scalar
 
74
    try:
 
75
        newvalue = param.type(value)
 
76
    except Exception as exc:
 
77
        raiseexcpet(exc, param, type(value), value)
 
78
 
 
79
    # check values
 
80
    if hasattr(param, 'values'):
 
81
        if param.type in (float, int):
 
82
            # check for value in range
 
83
            if ((param.min is not None and newvalue < param.min) or
 
84
                    (param.max is not None and newvalue > param.max)):
 
85
                err_str = ('The Parameter <%s>, must be between: '
 
86
                           '%g<=value<=%g, %r is outside.')
 
87
                raise ValueError(err_str % (param.name, param.min,
 
88
                                            param.max, newvalue))
 
89
        # check if value is in the list of valid values
 
90
        if param.values is not None and newvalue not in param.values:
 
91
            raise ValueError(must_val % (param.name, param.values))
 
92
    return (([newvalue, ] if (param.multiple or param.keydescvalues)
 
93
             else newvalue), value)
 
94
 
 
95
 
 
96
# TODO add documentation
 
97
class Parameter(object):
 
98
    """The Parameter object store all information about a parameter of a
 
99
    GRASS GIS module. ::
 
100
 
 
101
        >>> param = Parameter(diz=dict(name='int_number', required='yes',
 
102
        ...                            multiple='no', type='integer',
 
103
        ...                            values=[2, 4, 6, 8]))
 
104
        >>> param.value = 2
 
105
        >>> param.value
 
106
        2
 
107
        >>> param.value = 3
 
108
        Traceback (most recent call last):
 
109
           ...
 
110
        ValueError: The Parameter <int_number>, must be one of the following values: [2, 4, 6, 8]
 
111
 
 
112
    ...
 
113
    """
 
114
    def __init__(self, xparameter=None, diz=None):
 
115
        self._value = None
 
116
        self._rawvalue = None
 
117
        self.min = None
 
118
        self.max = None
 
119
        diz = element2dict(xparameter) if xparameter is not None else diz
 
120
        if diz is None:
 
121
            raise TypeError('Xparameter or diz are required')
 
122
        self.name = diz['name']
 
123
        self.required = True if diz['required'] == 'yes' else False
 
124
        self.multiple = True if diz['multiple'] == 'yes' else False
 
125
        # check the type
 
126
        if diz['type'] in GETTYPE:
 
127
            self.type = GETTYPE[diz['type']]
 
128
            self.typedesc = diz['type']
 
129
        else:
 
130
            raise TypeError('New type: %s, ignored' % diz['type'])
 
131
 
 
132
        self.description = diz.get('description', None)
 
133
        self.keydesc, self.keydescvalues = diz.get('keydesc', (None, None))
 
134
 
 
135
        #
 
136
        # values
 
137
        #
 
138
        if 'values' in diz:
 
139
            try:
 
140
                # Check for integer ranges: "3-30" or float ranges: "0.0-1.0"
 
141
                isrange = re.match("(?P<min>-*\d+.*\d*)-(?P<max>\d+.*\d*)",
 
142
                                   diz['values'][0])
 
143
                if isrange:
 
144
                    mn, mx = isrange.groups()
 
145
                    self.min, self.max = float(mn), float(mx)
 
146
                    self.values = None
 
147
                    self.isrange = diz['values'][0]
 
148
                # No range was found
 
149
                else:
 
150
                    self.values = [self.type(i) for i in diz['values']]
 
151
                    self.isrange = False
 
152
            except TypeError:
 
153
                self.values = [self.type(i) for i in diz['values']]
 
154
                self.isrange = False
 
155
 
 
156
        #
 
157
        # default
 
158
        #
 
159
        if 'default' in diz and diz['default']:
 
160
            if self.multiple or self.keydescvalues:
 
161
                self.default = [self.type(v)
 
162
                                for v in diz['default'].split(',')]
 
163
            else:
 
164
                self.default = self.type(diz['default'])
 
165
        else:
 
166
            self.default = None
 
167
        self._value, self._rawvalue = self.default, self.default
 
168
        self.guisection = diz.get('guisection', None)
 
169
 
 
170
        #
 
171
        # gisprompt
 
172
        #
 
173
        if 'gisprompt' in diz and diz['gisprompt']:
 
174
            self.typedesc = diz['gisprompt'].get('prompt', '')
 
175
            self.input = False if diz['gisprompt']['age'] == 'new' else True
 
176
        else:
 
177
            self.input = True
 
178
 
 
179
    def _get_value(self):
 
180
        return self._value
 
181
 
 
182
    def _set_value(self, value):
 
183
        self._value, self._rawvalue = _check_value(self, value)
 
184
 
 
185
    # here the property function is used to transform value in an attribute
 
186
    # in this case we define which function must be use to get/set the value
 
187
    value = property(fget=_get_value, fset=_set_value,
 
188
                     doc="Parameter value transformed and validated.")
 
189
 
 
190
    @property
 
191
    def rawvalue(self):
 
192
        """Parameter value as insert by user without transformation"""
 
193
        return self._rawvalue
 
194
 
 
195
    def get_bash(self):
 
196
        """Return the BASH representation of the parameter. ::
 
197
 
 
198
            >>> param = Parameter(diz=dict(name='int_number', required='yes',
 
199
            ...                            multiple='no', type='integer',
 
200
            ...                            values=[2, 4, 6, 8], default=8))
 
201
            >>> param.get_bash()
 
202
            u'int_number=8'
 
203
 
 
204
        ..
 
205
        """
 
206
        sep = ','
 
207
        if isinstance(self.rawvalue, (list, tuple)):
 
208
            value = sep.join([sep.join([str(v) for v in val])
 
209
                              if isinstance(val, tuple) else str(val)
 
210
                              for val in self.rawvalue])
 
211
        else:
 
212
            value = str(self.rawvalue)
 
213
        return "%s=%s" % (self.name, value)
 
214
 
 
215
    def get_python(self):
 
216
        """Return a string with the Python representation of the parameter. ::
 
217
 
 
218
            >>> param = Parameter(diz=dict(name='int_number', required='yes',
 
219
            ...                            multiple='no', type='integer',
 
220
            ...                            values=[2, 4, 6, 8], default=8))
 
221
            >>> param.get_python()
 
222
            u'int_number=8'
 
223
 
 
224
        ..
 
225
        """
 
226
        if self.value is None:
 
227
            return ''
 
228
        return """%s=%r""" % (self.name, self.value)
 
229
 
 
230
    def __str__(self):
 
231
        """Return the BASH representation of the GRASS module parameter."""
 
232
        return self.get_bash()
 
233
 
 
234
    def __repr__(self):
 
235
        """Return the python representation of the GRASS module parameter."""
 
236
        str_repr = "Parameter <%s> (required:%s, type:%s, multiple:%s)"
 
237
        mtype = ('raster', 'vector')  # map type
 
238
        return str_repr % (self.name,
 
239
                           "yes" if self.required else "no",
 
240
                           self.type if self.type in mtype else self.typedesc,
 
241
                           "yes" if self.multiple else "no")
 
242
 
 
243
    @docstring_property(__doc__)
 
244
    def __doc__(self):
 
245
        """Return the docstring of the parameter
 
246
 
 
247
        {name}: {default}{required}{multi}{ptype}
 
248
            {description}{values}"",
 
249
 
 
250
        ::
 
251
 
 
252
            >>> param = Parameter(diz=dict(name='int_number',
 
253
            ...                            description="Set an number",
 
254
            ...                            required='yes',
 
255
            ...                            multiple='no', type='integer',
 
256
            ...                            values=[2, 4, 6, 8], default=8))
 
257
            >>> print(param.__doc__)
 
258
            int_number: 8, required, integer
 
259
                Set an number
 
260
                Values: 2, 4, 6, 8
 
261
        ..
 
262
        """
 
263
        if hasattr(self, 'values'):
 
264
            if self.isrange:
 
265
                vals = self.isrange
 
266
            else:
 
267
                vals = ', '.join([repr(val) for val in self.values])
 
268
        else:
 
269
            vals = False
 
270
        if self.keydescvalues:
 
271
            keydescvals = "\n    (%s)" % ', '.join(self.keydescvalues)
 
272
        return DOC['param'].format(name=self.name,
 
273
                default=repr(self.default) + ', ' if self.default else '',
 
274
                required='required, ' if self.required else 'optional, ',
 
275
                multi='multi' if self.multiple else '',
 
276
                ptype=self.typedesc, description=self.description,
 
277
                values='\n    Values: {0}'.format(vals)  if vals else '',
 
278
                keydescvalues= keydescvals if self.keydescvalues else '')