123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319 |
- """
- Created on Tue Apr 2 18:31:47 2013
- @author: pietro
- """
- from __future__ import (
- nested_scopes,
- generators,
- division,
- absolute_import,
- with_statement,
- print_function,
- unicode_literals,
- )
- import re
- from grass.pygrass.modules.interface.docstring import docstring_property
- from grass.pygrass.modules.interface.read import GETTYPE, element2dict, DOC
- def _check_value(param, value):
- """Function to check the correctness of a value and
- return the checked value and the original.
- """
- must_val = "The Parameter <%s>, must be one of the following values: %r"
- req = "The Parameter <%s>, require: %s, get: %s instead: %r\n%s"
- string = (type(b""), type(""))
- def raiseexcpet(exc, param, ptype, value):
- """Function to modifa the error message"""
- msg = req % (param.name, param.typedesc, ptype, value, str(exc))
- if isinstance(exc, ValueError):
- raise ValueError(msg)
- elif isinstance(exc, TypeError):
- raise TypeError(msg)
- else:
- exc.message = msg
- raise exc
- def check_string(value):
- """Function to check that a string parameter is already a string"""
- if param.type in string:
- if type(value) in (int, float):
- value = str(value)
- if type(value) not in string:
- msg = (
- "The Parameter <%s> require a string," " %s instead is provided: %r"
- )
- raise ValueError(msg % (param.name, type(value), value))
- return value
- # return None if None
- if value is None:
- return param.default, param.default
- # find errors with multiple parmeters
- if isinstance(value, (list, tuple)):
- if param.keydescvalues:
- return (
- (
- [
- value,
- ],
- value,
- )
- if isinstance(value, tuple)
- else (value, value)
- )
- if param.multiple:
- # everything looks fine, so check each value
- try:
- return [param.type(check_string(val)) for val in value], value
- except Exception as exc:
- raiseexcpet(exc, param, param.type, value)
- else:
- msg = "The Parameter <%s> does not accept multiple inputs"
- raise TypeError(msg % param.name)
- if param.keydescvalues:
- msg = "The Parameter <%s> require multiple inputs in the form: %s"
- raise TypeError(msg % (param.name, param.keydescvalues))
- if param.typedesc == "all":
- return value, value
- # check string before trying to convert value to the correct type
- check_string(value)
- # the value is a scalar
- try:
- newvalue = param.type(value)
- except Exception as exc:
- raiseexcpet(exc, param, type(value), value)
- # check values
- if hasattr(param, "values"):
- if param.type in (float, int):
- # check for value in range
- if (param.min is not None and newvalue < param.min) or (
- param.max is not None and newvalue > param.max
- ):
- err_str = (
- "The Parameter <%s>, must be between: "
- "%g<=value<=%g, %r is outside."
- )
- raise ValueError(err_str % (param.name, param.min, param.max, newvalue))
- # check if value is in the list of valid values
- if param.values is not None and newvalue not in param.values:
- raise ValueError(must_val % (param.name, param.values))
- return (
- (
- [
- newvalue,
- ]
- if (param.multiple or param.keydescvalues)
- else newvalue
- ),
- value,
- )
- # TODO add documentation
- class Parameter(object):
- """The Parameter object store all information about a parameter of a
- GRASS GIS module. ::
- >>> param = Parameter(diz=dict(name='int_number', required='yes',
- ... multiple='no', type='integer',
- ... values=[2, 4, 6, 8]))
- >>> param.value = 2
- >>> param.value
- 2
- >>> param.value = 3
- Traceback (most recent call last):
- ...
- ValueError: The Parameter <int_number>, must be one of the following values: [2, 4, 6, 8]
- ...
- """
- def __init__(self, xparameter=None, diz=None):
- self._value = None
- self._rawvalue = None
- self.min = None
- self.max = None
- diz = element2dict(xparameter) if xparameter is not None else diz
- if diz is None:
- raise TypeError("Xparameter or diz are required")
- self.name = diz["name"]
- self.required = True if diz["required"] == "yes" else False
- self.multiple = True if diz["multiple"] == "yes" else False
- # check the type
- if diz["type"] in GETTYPE:
- self.type = GETTYPE[diz["type"]]
- self.typedesc = diz["type"]
- else:
- raise TypeError("New type: %s, ignored" % diz["type"])
- self.description = diz.get("description", None)
- self.keydesc, self.keydescvalues = diz.get("keydesc", (None, None))
- #
- # values
- #
- if "values" in diz:
- try:
- # Check for integer ranges: "3-30" or float ranges: "0.0-1.0"
- isrange = re.match(
- "(?P<min>-*\d+.*\d*)*-(?P<max>\d+.*\d*)*", diz["values"][0]
- )
- if isrange:
- mn, mx = isrange.groups()
- self.min = None if mn is None else float(mn)
- self.max = None if mx is None else float(mx)
- self.values = None
- self.isrange = diz["values"][0]
- # No range was found
- else:
- self.values = [self.type(i) for i in diz["values"]]
- self.isrange = False
- except TypeError:
- self.values = [self.type(i) for i in diz["values"]]
- self.isrange = False
- #
- # default
- #
- if "default" in diz and diz["default"]:
- if self.multiple or self.keydescvalues:
- self.default = [self.type(v) for v in diz["default"].split(",")]
- else:
- self.default = self.type(diz["default"])
- else:
- self.default = None
- self._value, self._rawvalue = self.default, self.default
- self.guisection = diz.get("guisection", None)
- #
- # gisprompt
- #
- if "gisprompt" in diz and diz["gisprompt"]:
- self.typedesc = diz["gisprompt"].get("prompt", "")
- self.input = False if diz["gisprompt"]["age"] == "new" else True
- else:
- self.input = True
- def _get_value(self):
- return self._value
- def _set_value(self, value):
- self._value, self._rawvalue = _check_value(self, value)
- # here the property function is used to transform value in an attribute
- # in this case we define which function must be use to get/set the value
- value = property(
- fget=_get_value,
- fset=_set_value,
- doc="Parameter value transformed and validated.",
- )
- @property
- def rawvalue(self):
- """Parameter value as insert by user without transformation"""
- return self._rawvalue
- def get_bash(self):
- """Return the BASH representation of the parameter. ::
- >>> param = Parameter(diz=dict(name='int_number', required='yes',
- ... multiple='no', type='integer',
- ... values=[2, 4, 6, 8], default=8))
- >>> param.get_bash()
- 'int_number=8'
- ..
- """
- sep = ","
- if isinstance(self.rawvalue, (list, tuple)):
- value = sep.join(
- [
- sep.join([str(v) for v in val])
- if isinstance(val, tuple)
- else str(val)
- for val in self.rawvalue
- ]
- )
- else:
- value = str(self.rawvalue)
- return "%s=%s" % (self.name, value)
- def get_python(self):
- """Return a string with the Python representation of the parameter. ::
- >>> param = Parameter(diz=dict(name='int_number', required='yes',
- ... multiple='no', type='integer',
- ... values=[2, 4, 6, 8], default=8))
- >>> param.get_python()
- 'int_number=8'
- ..
- """
- if self.value is None:
- return ""
- return """%s=%r""" % (self.name, self.value)
- def __str__(self):
- """Return the BASH representation of the GRASS module parameter."""
- return self.get_bash()
- def __repr__(self):
- """Return the python representation of the GRASS module parameter."""
- str_repr = "Parameter <%s> (required:%s, type:%s, multiple:%s)"
- mtype = ("raster", "vector") # map type
- return str_repr % (
- self.name,
- "yes" if self.required else "no",
- self.type if self.type in mtype else self.typedesc,
- "yes" if self.multiple else "no",
- )
- @docstring_property(__doc__)
- def __doc__(self):
- """Return the docstring of the parameter
- {name}: {default}{required}{multi}{ptype}
- {description}{values}"",
- ::
- >>> param = Parameter(diz=dict(name='int_number',
- ... description="Set an number",
- ... required='yes',
- ... multiple='no', type='integer',
- ... values=[2, 4, 6, 8], default=8))
- >>> print(param.__doc__)
- int_number: 8, required, integer
- Set an number
- Values: 2, 4, 6, 8
- ..
- """
- if hasattr(self, "values"):
- if self.isrange:
- vals = self.isrange
- else:
- vals = ", ".join([repr(val) for val in self.values])
- else:
- vals = False
- if self.keydescvalues:
- keydescvals = "\n (%s)" % ", ".join(self.keydescvalues)
- return DOC["param"].format(
- name=self.name,
- default=repr(self.default) + ", " if self.default else "",
- required="required, " if self.required else "optional, ",
- multi="multi" if self.multiple else "",
- ptype=self.typedesc,
- description=self.description,
- values="\n Values: {0}".format(vals) if vals else "",
- keydescvalues=keydescvals if self.keydescvalues else "",
- )
|