[processing] moved script syntax from script algorithm class to parameters classes

This commit is contained in:
volaya 2016-09-05 12:59:21 +02:00
parent a69b358aa7
commit 8cc9a50a52
2 changed files with 206 additions and 144 deletions

View File

@ -30,6 +30,7 @@ __revision__ = '$Format:%H$'
import sys
import os
import inspect
from qgis.PyQt.QtCore import QCoreApplication
from qgis.core import QgsRasterLayer, QgsVectorLayer
@ -37,19 +38,23 @@ from processing.tools.vector import resolveFieldIndex, features
from processing.tools.system import isWindows
from processing.tools import dataobjects
def getParameterFromString(s):
tokens = s.split("|")
params = [t if str(t) != str(None) else None for t in tokens[1:]]
clazz = getattr(sys.modules[__name__], tokens[0])
return clazz(*params)
def parseBool(s):
if s is None or s == str(None).lower():
return None
return str(s).lower() == str(True).lower()
def _splitParameterOptions(line):
tokens = line.split('=', 1)
if tokens[1].lower().strip().startswith('optional'):
isOptional = True
definition = tokens[1].strip()[len('optional') + 1:]
else:
isOptional = False
definition = tokens[1]
return isOptional, tokens[0], definition
def _createDescriptiveName(s):
return s.replace('_', ' ')
class Parameter(object):
@ -128,8 +133,7 @@ class Parameter(object):
if context == '':
context = 'Parameter'
return QCoreApplication.translate(context, string)
class ParameterBoolean(Parameter):
default_metadata = {
@ -158,6 +162,20 @@ class ParameterBoolean(Parameter):
param_type += 'optional '
param_type += 'boolean '
return '##' + self.name + '=' + param_type + str(self.default)
@classmethod
def fromScriptCode(self, line):
isOptional, name, definition = _splitParameterOptions(line)
if definition.startswith("boolean"):
descName = _createDescriptiveName(name)
default = definition.strip()[len('boolean') + 1:]
if default:
param = ParameterBoolean(name, descName, default)
else:
param = ParameterBoolean(name, descName)
param.optional = isOptional
return param
class ParameterCrs(Parameter):
@ -194,6 +212,16 @@ class ParameterCrs(Parameter):
param_type += 'crs '
return '##' + self.name + '=' + param_type + str(self.default)
@classmethod
def fromScriptCode(self, line):
isOptional, name, definition = _splitParameterOptions(line)
if definition.startswith("crs"):
descName = _createDescriptiveName(name)
default = definition.strip()[len('crs') + 1:]
if default:
return ParameterCrs(name, descName, default, isOptional)
else:
return ParameterCrs(name, descName, None, isOptional)
class ParameterDataObject(Parameter):
@ -243,6 +271,14 @@ class ParameterExtent(Parameter):
param_type += 'optional '
param_type += 'extent'
return '##' + self.name + '=' + param_type
@classmethod
def fromScriptCode(self, line):
isOptional, name, definition = _splitParameterOptions(line)
if definition.startswith("extent"):
descName = _createDescriptiveName(name)
default = definition.strip()[len('extent') + 1:] or None
return ParameterExtent(name, descName, default, isOptional)
class ParameterPoint(Parameter):
@ -279,6 +315,14 @@ class ParameterPoint(Parameter):
param_type += 'point'
return '##' + self.name + '=' + param_type
@classmethod
def fromScriptCode(self, line):
isOptional, name, definition = _splitParameterOptions(line)
if definition.startswith("point"):
descName = _createDescriptiveName(name)
default = definition.strip()[len('point') + 1:] or None
return ParameterPoint(name, descName, default, isOptional)
class ParameterFile(Parameter):
@ -318,6 +362,13 @@ class ParameterFile(Parameter):
param_type += 'file'
return '##' + self.name + '=' + param_type
@classmethod
def fromScriptCode(self, line):
isOptional, name, definition = _splitParameterOptions(line)
if definition.startswith("file") or definition.startswith("folder"):
descName = _createDescriptiveName(name)
return ParameterFile(name, descName, definition.startswith("folder"), isOptional)
class ParameterFixedTable(Parameter):
@ -356,6 +407,14 @@ class ParameterFixedTable(Parameter):
tablestring = tablestring[:-1]
return tablestring
@classmethod
def fromScriptCode(self, line):
isOptional, name, definition = _splitParameterOptions(line)
if definition.startswith("point"):
descName = _createDescriptiveName(name)
default = definition.strip()[len('point') + 1:] or None
return ParameterPoint(name, descName, default, isOptional)
class ParameterMultipleInput(ParameterDataObject):
@ -542,6 +601,17 @@ class ParameterMultipleInput(ParameterDataObject):
param_type += 'multiple vector'
return '##' + self.name + '=' + param_type
@classmethod
def fromScriptCode(self, line):
isOptional, name, definition = _splitParameterOptions(line)
descName = _createDescriptiveName(name)
if definition.lower().strip() == 'multiple raster':
return ParameterMultipleInput(name, descName,
dataobjects.TYPE_RASTER, isOptional)
elif definition.lower().strip() == 'multiple vector':
return ParameterMultipleInput(name, definition,
dataobjects.TYPE_VECTOR_ANY, isOptional)
class ParameterNumber(Parameter):
@ -599,6 +669,13 @@ class ParameterNumber(Parameter):
param_type += 'number'
return '##' + self.name + '=' + param_type + str(self.default)
@classmethod
def fromScriptCode(self, line):
isOptional, name, definition = _splitParameterOptions(line)
descName = _createDescriptiveName(name)
if definition.lower().strip().startswith('number'):
default = definition.strip()[len('number') + 1:] or None
return ParameterNumber(name, descName, default=default, optional=isOptional)
class ParameterRange(Parameter):
@ -701,6 +778,13 @@ class ParameterRaster(ParameterDataObject):
param_type += 'raster'
return '##' + self.name + '=' + param_type
@classmethod
def fromScriptCode(self, line):
isOptional, name, definition = _splitParameterOptions(line)
descName = _createDescriptiveName(name)
print isOptional, name, definition
if definition.lower().strip().startswith('raster'):
return ParameterRaster(name, descName, optional=isOptional)
class ParameterSelection(Parameter):
@ -744,7 +828,18 @@ class ParameterSelection(Parameter):
except:
return False
@classmethod
def fromScriptCode(self, line):
isOptional, name, definition = _splitParameterOptions(line)
descName = _createDescriptiveName(name)
if definition.lower().strip().startswith('selectionfromfile'):
options = definition.strip()[len('selectionfromfile '):].split(';')
return ParameterSelection(name, descName, options, isSource=True, optional=isOptional)
elif definition.lower().strip().startswith('selection'):
options = definition.strip()[len('selection '):].split(';')
return ParameterSelection(name, descName, options, optional=isOptional)
class ParameterString(Parameter):
NEWLINE = '\n'
@ -781,6 +876,22 @@ class ParameterString(Parameter):
param_type += 'string'
return '##' + self.name + '=' + param_type + self.default
@classmethod
def fromScriptCode(self, line):
isOptional, name, definition = _splitParameterOptions(line)
descName = _createDescriptiveName(name)
if definition.lower().strip().startswith('string'):
default = definition.strip()[len('string') + 1:]
if default:
return ParameterString(name, descName, default, optional=isOptional)
else:
return ParameterString(name, descName, optional=isOptional)
elif definition.lower().strip().startswith('longstring'):
default = definition.strip()[len('longstring') + 1:]
if default:
return ParameterString(name, descName, default, multiline=True, optional=isOptional)
else:
return ParameterString(name, descName, multiline=True, optional=isOptional)
class ParameterTable(ParameterDataObject):
@ -853,6 +964,13 @@ class ParameterTable(ParameterDataObject):
param_type += 'table'
return '##' + self.name + '=' + param_type
@classmethod
def fromScriptCode(self, line):
isOptional, name, definition = _splitParameterOptions(line)
descName = _createDescriptiveName(name)
if definition.lower().strip().startswith('table'):
return ParameterTable(name, descName, isOptional)
class ParameterTableField(Parameter):
@ -908,6 +1026,24 @@ class ParameterTableField(Parameter):
return '##' + self.name + '=' + param_type + self.parent
@classmethod
def fromScriptCode(self, line):
isOptional, name, definition = _splitParameterOptions(line)
descName = _createDescriptiveName(name)
if definition.lower().strip().startswith('field'):
if definition.lower().strip().startswith('field number'):
parent = definition.strip()[len('field number') + 1:]
datatype = ParameterTableField.DATA_TYPE_NUMBER
elif definition.lower().strip().startswith('field string'):
parent = definition.strip()[len('field string') + 1:]
datatype = ParameterTableField.DATA_TYPE_STRING
else:
parent = definition.strip()[len('field') + 1:]
datatype = ParameterTableField.DATA_TYPE_ANY
return ParameterTableField(name, descName, parent, datatype, isOptional)
class ParameterTableMultipleField(Parameter):
"""A parameter representing several table fields.
@ -974,6 +1110,23 @@ class ParameterTableMultipleField(Parameter):
param_type += 'multiple field '
return '##' + self.name + '=' + param_type + self.parent
@classmethod
def fromScriptCode(self, line):
isOptional, name, definition = _splitParameterOptions(line)
if definition.lower().strip().startswith('multiple field'):
descName = _createDescriptiveName(name)
if definition.lower().strip().startswith('multiple field number'):
field = definition.strip()[len('multiple field number') + 1:]
datatype = ParameterTableMultipleField.DATA_TYPE_NUMBER
elif definition.lower().strip().startswith('multiple field string'):
field = definition.strip()[len('multiple field string') + 1:]
datatype = ParameterTableMultipleField.DATA_TYPE_STRING
else:
field = definition.strip()[len('multiple field') + 1:]
datatype = ParameterTableMultipleField.DATA_TYPE_ANY
return ParameterTableMultipleField(name, descName, field, datatype, isOptional)
class ParameterVector(ParameterDataObject):
@ -1050,6 +1203,22 @@ class ParameterVector(ParameterDataObject):
param_type += 'vector'
return '##' + self.name + '=' + param_type
@classmethod
def fromScriptCode(self, line):
isOptional, name, definition = _splitParameterOptions(line)
descName = _createDescriptiveName(name)
if definition.lower().strip() == 'vector':
return ParameterVector(name, descName,
[dataobjects.TYPE_VECTOR_ANY], isOptional)
elif definition.lower().strip() == 'vector point':
return ParameterVector(name, descName,
[dataobjects.TYPE_VECTOR_POINT], isOptional)
elif definition.lower().strip() == 'vector line':
return ParameterVector(name, descName,
[dataobjects.TYPE_VECTOR_LINE], isOptional)
elif definition.lower().strip() == 'vector polygon':
return ParameterVector(name, descName,
[dataobjects.TYPE_VECTOR_POLYGON], isOptional)
class ParameterGeometryPredicate(Parameter):
@ -1089,3 +1258,23 @@ class ParameterGeometryPredicate(Parameter):
else:
self.value = value
return True
paramClasses = [c for c in sys.modules[__name__].__dict__.values() if inspect.isclass(c) and issubclass(c, Parameter)]
def getParameterFromString(s):
print s
#Try the parameter definitions used in description files
if '|' in s:
tokens = s.split("|")
params = [t if unicode(t) != unicode(None) else None for t in tokens[1:]]
clazz = getattr(sys.modules[__name__], tokens[0])
return clazz(*params)
else: #try script syntax
for paramClass in paramClasses:
try:
param = paramClass.fromScriptCode(s)
if param is not None:
return param
except AttributeError:
pass

View File

@ -146,12 +146,6 @@ class ScriptAlgorithm(GeoAlgorithm):
out = None
line = line.replace('#', '')
# If the line is in the format of the text description files for
# normal algorithms, then process it using parameter and output
# factories
if '|' in line:
self.processDescriptionParameterLine(line)
return
if line == "nomodeler":
self.showInModeler = False
return
@ -170,15 +164,8 @@ class ScriptAlgorithm(GeoAlgorithm):
if tokens[1].lower().strip().startswith('output'):
outToken = tokens[1].strip()[len('output') + 1:]
out = self.processOutputParameterToken(outToken)
elif tokens[1].lower().strip().startswith('optional'):
optToken = tokens[1].strip()[len('optional') + 1:]
param = self.processInputParameterToken(optToken, tokens[0])
if param:
param.optional = True
else:
param = self.processInputParameterToken(tokens[1], tokens[0])
param = getParameterFromString(line)
if param is not None:
self.addParameter(param)
@ -191,125 +178,11 @@ class ScriptAlgorithm(GeoAlgorithm):
self.tr('Could not load script: %s.\n'
'Problem with line "%s"', 'ScriptAlgorithm') % (self.descriptionFile or '', line))
def processInputParameterToken(self, token, name):
param = None
descName = self.createDescriptiveName(name)
if token.lower().strip() == 'raster':
param = ParameterRaster(name, descName, False)
elif token.lower().strip() == 'vector':
param = ParameterVector(name, descName,
[dataobjects.TYPE_VECTOR_ANY])
elif token.lower().strip() == 'vector point':
param = ParameterVector(name, descName,
[dataobjects.TYPE_VECTOR_POINT])
elif token.lower().strip() == 'vector line':
param = ParameterVector(name, descName,
[dataobjects.TYPE_VECTOR_LINE])
elif token.lower().strip() == 'vector polygon':
param = ParameterVector(name, descName,
[dataobjects.TYPE_VECTOR_POLYGON])
elif token.lower().strip() == 'table':
param = ParameterTable(name, descName, False)
elif token.lower().strip() == 'multiple raster':
param = ParameterMultipleInput(name, descName,
dataobjects.TYPE_RASTER)
param.optional = False
elif token.lower().strip() == 'multiple vector':
param = ParameterMultipleInput(name, descName,
dataobjects.TYPE_VECTOR_ANY)
param.optional = False
elif token.lower().strip().startswith('selectionfromfile'):
options = token.strip()[len('selectionfromfile '):].split(';')
param = ParameterSelection(name, descName, options, isSource=True)
elif token.lower().strip().startswith('selection'):
options = token.strip()[len('selection '):].split(';')
param = ParameterSelection(name, descName, options)
elif token.lower().strip().startswith('boolean'):
default = token.strip()[len('boolean') + 1:]
if default:
param = ParameterBoolean(name, descName, default)
else:
param = ParameterBoolean(name, descName)
elif token.lower().strip() == 'extent':
param = ParameterExtent(name, descName)
elif token.lower().strip() == 'point':
param = ParameterPoint(name, descName)
elif token.lower().strip() == 'file':
param = ParameterFile(name, descName, False)
elif token.lower().strip() == 'folder':
param = ParameterFile(name, descName, True)
elif token.lower().strip().startswith('number'):
default = token.strip()[len('number') + 1:]
if default:
param = ParameterNumber(name, descName, default=default)
else:
param = ParameterNumber(name, descName)
elif token.lower().strip().startswith('field'):
if token.lower().strip().startswith('field number'):
field = token.strip()[len('field number') + 1:]
datatype = ParameterTableField.DATA_TYPE_NUMBER
elif token.lower().strip().startswith('field string'):
field = token.strip()[len('field string') + 1:]
datatype = ParameterTableField.DATA_TYPE_STRING
else:
field = token.strip()[len('field') + 1:]
datatype = ParameterTableField.DATA_TYPE_ANY
found = False
for p in self.parameters:
if p.name == field:
found = True
break
if found:
param = ParameterTableField(
name=name,
description=descName,
parent=field,
datatype=datatype
)
elif token.lower().strip().startswith('multiple field'):
if token.lower().strip().startswith('multiple field number'):
field = token.strip()[len('multiple field number') + 1:]
datatype = ParameterTableMultipleField.DATA_TYPE_NUMBER
elif token.lower().strip().startswith('multiple field string'):
field = token.strip()[len('multiple field string') + 1:]
datatype = ParameterTableMultipleField.DATA_TYPE_STRING
else:
field = token.strip()[len('multiple field') + 1:]
datatype = ParameterTableMultipleField.DATA_TYPE_ANY
found = False
for p in self.parameters:
if p.name == field:
found = True
break
if found:
param = ParameterTableMultipleField(
name=name,
description=descName,
parent=field,
datatype=datatype
)
elif token.lower().strip().startswith('string'):
default = token.strip()[len('string') + 1:]
if default:
param = ParameterString(name, descName, default)
else:
param = ParameterString(name, descName)
elif token.lower().strip().startswith('longstring'):
default = token.strip()[len('longstring') + 1:]
if default:
param = ParameterString(name, descName, default, multiline=True)
else:
param = ParameterString(name, descName, multiline=True)
elif token.lower().strip().startswith('crs'):
default = token.strip()[len('crs') + 1:]
if default:
param = ParameterCrs(name, descName, default)
else:
param = ParameterCrs(name, descName)
return param
def processInputParameterLine(self, line):
for paramClass in paramClasses:
param = paramClass.fromScriptCode(line)
if param is not None:
return param
def processOutputParameterToken(self, token):
out = None