1
# -*- coding: utf-8 -*-
3
Created on Tue Apr 2 18:31:47 2013
7
from __future__ import (nested_scopes, generators, division, absolute_import,
8
with_statement, print_function, unicode_literals)
11
from grass.pygrass.utils import docstring_property
12
from grass.pygrass.modules.interface.read import GETTYPE, element2dict, DOC
15
def _check_value(param, value):
16
"""Function to check the correctness of a value and
17
return the checked value and the original.
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'
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)
27
elif exc is TypeError:
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):
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))
47
return param.default, param.default
49
# find errors with multiple parmeters
50
if isinstance(value, (list, tuple)):
51
if param.keydescvalues:
52
return (([value, ], value) if isinstance(value, tuple)
55
# everything looks fine, so check each value
57
return [param.type(check_string(val)) for val in value], value
58
except Exception as exc:
59
raiseexcpet(exc, param, param.type, value)
61
msg = 'The Parameter <%s> does not accept multiple inputs'
62
raise TypeError(msg % param.name)
64
if param.keydescvalues:
65
msg = 'The Parameter <%s> require multiple inputs in the form: %s'
66
raise TypeError(msg % (param.name, param.keydescvalues))
68
if param.typedesc == 'all':
71
# check string before trying to convert value to the correct type
73
# the value is a scalar
75
newvalue = param.type(value)
76
except Exception as exc:
77
raiseexcpet(exc, param, type(value), value)
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,
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)
96
# TODO add documentation
97
class Parameter(object):
98
"""The Parameter object store all information about a parameter of a
101
>>> param = Parameter(diz=dict(name='int_number', required='yes',
102
... multiple='no', type='integer',
103
... values=[2, 4, 6, 8]))
108
Traceback (most recent call last):
110
ValueError: The Parameter <int_number>, must be one of the following values: [2, 4, 6, 8]
114
def __init__(self, xparameter=None, diz=None):
116
self._rawvalue = None
119
diz = element2dict(xparameter) if xparameter is not None else diz
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
126
if diz['type'] in GETTYPE:
127
self.type = GETTYPE[diz['type']]
128
self.typedesc = diz['type']
130
raise TypeError('New type: %s, ignored' % diz['type'])
132
self.description = diz.get('description', None)
133
self.keydesc, self.keydescvalues = diz.get('keydesc', (None, None))
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*)",
144
mn, mx = isrange.groups()
145
self.min, self.max = float(mn), float(mx)
147
self.isrange = diz['values'][0]
150
self.values = [self.type(i) for i in diz['values']]
153
self.values = [self.type(i) for i in diz['values']]
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(',')]
164
self.default = self.type(diz['default'])
167
self._value, self._rawvalue = self.default, self.default
168
self.guisection = diz.get('guisection', None)
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
179
def _get_value(self):
182
def _set_value(self, value):
183
self._value, self._rawvalue = _check_value(self, value)
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.")
192
"""Parameter value as insert by user without transformation"""
193
return self._rawvalue
196
"""Return the BASH representation of the parameter. ::
198
>>> param = Parameter(diz=dict(name='int_number', required='yes',
199
... multiple='no', type='integer',
200
... values=[2, 4, 6, 8], default=8))
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])
212
value = str(self.rawvalue)
213
return "%s=%s" % (self.name, value)
215
def get_python(self):
216
"""Return a string with the Python representation of the parameter. ::
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()
226
if self.value is None:
228
return """%s=%r""" % (self.name, self.value)
231
"""Return the BASH representation of the GRASS module parameter."""
232
return self.get_bash()
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")
243
@docstring_property(__doc__)
245
"""Return the docstring of the parameter
247
{name}: {default}{required}{multi}{ptype}
248
{description}{values}"",
252
>>> param = Parameter(diz=dict(name='int_number',
253
... description="Set an number",
255
... multiple='no', type='integer',
256
... values=[2, 4, 6, 8], default=8))
257
>>> print(param.__doc__)
258
int_number: 8, required, integer
263
if hasattr(self, 'values'):
267
vals = ', '.join([repr(val) for val in self.values])
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 '')