parameter.py 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. # -*- coding: utf-8 -*-
  2. """
  3. Created on Tue Apr 2 18:31:47 2013
  4. @author: pietro
  5. """
  6. from __future__ import (nested_scopes, generators, division, absolute_import,
  7. with_statement, print_function, unicode_literals)
  8. import re
  9. from grass.pygrass.modules.interface.read import GETTYPE, element2dict, DOC
  10. # TODO add documentation
  11. class Parameter(object):
  12. """The Parameter object store all information about a parameter of module.
  13. It is possible to set parameter of command using this object.
  14. """
  15. def __init__(self, xparameter=None, diz=None):
  16. self._value = None
  17. diz = element2dict(xparameter) if xparameter is not None else diz
  18. if diz is None:
  19. raise TypeError('Xparameter or diz are required')
  20. self.name = diz['name']
  21. self.required = True if diz['required'] == 'yes' else False
  22. self.multiple = True if diz['multiple'] == 'yes' else False
  23. # check the type
  24. if diz['type'] in GETTYPE:
  25. self.type = GETTYPE[diz['type']]
  26. self.typedesc = diz['type']
  27. else:
  28. raise TypeError('New type: %s, ignored' % diz['type'])
  29. self.description = diz.get('description', None)
  30. self.keydesc, self.keydescvalues = diz.get('keydesc', (None, None))
  31. #
  32. # values
  33. #
  34. if 'values' in diz:
  35. try:
  36. # Check for integer ranges: "3-30"
  37. isrange = re.match("(?P<min>-*\d+)-(?P<max>\d+)",
  38. diz['values'][0])
  39. if isrange:
  40. range_min, range_max = isrange.groups()
  41. self.values = range(int(range_min), int(range_max) + 1)
  42. self.isrange = diz['values'][0]
  43. # Check for float ranges: "0.0-1.0"
  44. if not isrange:
  45. isrange = re.match("(?P<min>-*\d+.\d+)-(?P<max>\d+.\d+)",
  46. diz['values'][0])
  47. if isrange:
  48. # We are not able to create range values from
  49. # floating point ranges
  50. self.isrange = diz['values'][0]
  51. # No range was found
  52. if not isrange:
  53. self.values = [self.type(i) for i in diz['values']]
  54. self.isrange = False
  55. except TypeError:
  56. self.values = [self.type(i) for i in diz['values']]
  57. self.isrange = False
  58. #
  59. # default
  60. #
  61. if 'default' in diz:
  62. if self.multiple or self.keydescvalues:
  63. self.default = [self.type(v)
  64. for v in diz['default'].split(',')]
  65. else:
  66. self.default = self.type(diz['default'])
  67. self._value = self.default
  68. else:
  69. self.default = None
  70. self.guisection = diz.get('guisection', None)
  71. #
  72. # gisprompt
  73. #
  74. if 'gisprompt' in diz:
  75. self.typedesc = diz['gisprompt'].get('prompt', '')
  76. self.input = False if diz['gisprompt']['age'] == 'new' else True
  77. else:
  78. self.input = True
  79. def _get_value(self):
  80. return self._value
  81. def _set_value(self, value):
  82. values_error = 'The Parameter <%s>, must be a python list ' \
  83. 'containing one or more of the following values: %r'
  84. if value is None:
  85. self._value = value
  86. elif isinstance(value, list) or isinstance(value, tuple):
  87. if self.multiple or self.keydescvalues:
  88. # check each value
  89. self._value = [self.type(val) for val in value]
  90. else:
  91. str_err = 'The Parameter <%s> does not accept multiple inputs'
  92. raise TypeError(str_err % self.name)
  93. elif self.typedesc == 'all':
  94. self._value = value
  95. elif isinstance(value, self.type):
  96. if hasattr(self, 'values'):
  97. if self.type is float:
  98. if self.values[0] <= value <= self.values[-1]:
  99. self._value = value
  100. else:
  101. err_str = 'The Parameter <%s>, must be: %g<=value<=%g'
  102. raise ValueError(err_str % (self.name, self.values[0],
  103. self.values[-1]))
  104. elif value in self.values:
  105. self._value = value
  106. else:
  107. raise ValueError(values_error % (self.name, self.values))
  108. else:
  109. self._value = value
  110. elif self.type is str and isinstance(value, unicode):
  111. if hasattr(self, 'values'):
  112. if value in self.values:
  113. self._value = str(value)
  114. else:
  115. raise ValueError(values_error % (self.name, self.values))
  116. else:
  117. self._value = str(value)
  118. elif self.type is str and isinstance(value, str):
  119. if hasattr(self, 'values'):
  120. if value in self.values:
  121. self._value = value
  122. else:
  123. raise ValueError(values_error % (self.name, self.values))
  124. else:
  125. self._value = value
  126. else:
  127. str_err = 'The Parameter <%s>, require: %s, get: %s instead'
  128. raise TypeError(str_err % (self.name, self.typedesc, type(value)))
  129. # here the property function is used to transform value in an attribute
  130. # in this case we define which function must be use to get/set the value
  131. value = property(fget=_get_value, fset=_set_value,
  132. doc="Set or obtain value")
  133. def get_bash(self):
  134. """Prova"""
  135. if isinstance(self._value, list) or isinstance(self._value, tuple):
  136. value = ','.join([str(v) for v in self._value])
  137. else:
  138. value = str(self._value)
  139. return """%s=%s""" % (self.name, value)
  140. def get_python(self):
  141. """Prova"""
  142. if not self.value:
  143. return ''
  144. return """%s=%r""" % (self.name, self._value)
  145. def __str__(self):
  146. return self.get_bash()
  147. def __repr__(self):
  148. str_repr = "Parameter <%s> (required:%s, type:%s, multiple:%s)"
  149. return str_repr % (self.name,
  150. "yes" if self.required else "no",
  151. self.type if self.type in (
  152. 'raster', 'vector') else self.typedesc,
  153. "yes" if self.multiple else "no")
  154. # here we use property with a decorator, in this way we mask a method as
  155. # a class attribute
  156. @property
  157. def __doc__(self):
  158. """Return the docstring of the parameter
  159. {name}: {default}{required}{multi}{ptype}
  160. {description}{values}"","""
  161. if hasattr(self, 'values'):
  162. if self.isrange:
  163. vals = self.isrange
  164. else:
  165. vals = ', '.join([repr(val) for val in self.values])
  166. else:
  167. vals = False
  168. if self.keydescvalues:
  169. keydescvals = "\n (%s)" % ', '.join(self.keydescvalues)
  170. return DOC['param'].format(name=self.name,
  171. default=repr(self.default) + ', ' if self.default else '',
  172. required='required, ' if self.required else 'optional, ',
  173. multi='multi' if self.multiple else '',
  174. ptype=self.typedesc, description=self.description,
  175. values='\n Values: {0}'.format(vals) if vals else '',
  176. keydescvalues= keydescvals if self.keydescvalues else '')