parameter.py 6.8 KB

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