[processing] moved output value evaluation to output object itself

This commit is contained in:
volaya 2016-09-14 09:49:04 +02:00
parent 2bb6e4c19f
commit dfb4cdd34b
5 changed files with 129 additions and 135 deletions

View File

@ -89,11 +89,6 @@ class FieldsCalculator(GeoAlgorithm):
output = self.getOutputFromName(self.OUTPUT_LAYER)
if output.value == '':
ext = output.getDefaultFileExtension(self)
output.value = system.getTempFilenameInTempFolder(
output.name + '.' + ext)
fields = layer.fields()
if newField:
fields.append(QgsField(fieldName, fieldType, '', width, precision))

View File

@ -197,10 +197,8 @@ class GeoAlgorithm(object):
self.model = model
try:
self.setOutputCRS()
self.resolveTemporaryOutputs()
self.resolveDataObjects()
self.resolveOutputs()
self.evaluateParameterValues()
self.checkOutputFileExtensions()
self.runPreExecutionScript(progress)
self.processAlgorithm(progress)
progress.setPercentage(100)
@ -328,51 +326,24 @@ class GeoAlgorithm(object):
return name
return 'GTiff'
def checkOutputFileExtensions(self):
"""Checks if the values of outputs are correct and have one of
the supported output extensions.
If not, it adds the first one of the supported extensions, which
is assumed to be the default one.
"""
for out in self.outputs:
if not out.hidden and out.value is not None:
if not os.path.isabs(out.value):
continue
if isinstance(out, OutputRaster):
exts = dataobjects.getSupportedOutputRasterLayerExtensions()
elif isinstance(out, OutputVector):
exts = dataobjects.getSupportedOutputVectorLayerExtensions()
elif isinstance(out, OutputTable):
exts = dataobjects.getSupportedOutputTableExtensions()
elif isinstance(out, OutputHTML):
exts = ['html', 'htm']
else:
continue
idx = out.value.rfind('.')
if idx == -1:
out.value = out.value + '.' + exts[0]
else:
ext = out.value[idx + 1:]
if ext not in exts + ['dbf']:
out.value = out.value + '.' + exts[0]
def evaluateParameterValues(self):
for param in self.parameters:
try:
param.evaluate(self)
except ValueError, e:
traceback.print_exc()
raise GeoAlgorithmExecutionException(str(e))
def resolveTemporaryOutputs(self):
def resolveOutputs(self):
"""Sets temporary outputs (output.value = None) with a
temporary file instead.
temporary file instead. Resolves expressions as well.
"""
for out in self.outputs:
if not out.hidden and out.value is None:
setTempOutput(out, self)
try:
for out in self.outputs:
out.resolveValue(self)
except ValueError, e:
raise GeoAlgorithmExecutionException(str(e))
def setOutputCRS(self):
layers = dataobjects.getAllLayers()
for param in self.parameters:

View File

@ -20,7 +20,6 @@ from builtins import str
from builtins import range
from builtins import object
__author__ = 'Victor Olaya'
__date__ = 'August 2012'
__copyright__ = '(C) 2012, Victor Olaya'
@ -29,15 +28,27 @@ __copyright__ = '(C) 2012, Victor Olaya'
__revision__ = '$Format:%H$'
import os
import sys
from qgis.PyQt.QtCore import QCoreApplication, QSettings
from processing.core.ProcessingConfig import ProcessingConfig
from processing.tools.system import isWindows, getTempFilenameInTempFolder
from processing.tools.system import isWindows, getTempFilenameInTempFolder, getTempDirInTempFolder
from processing.tools.vector import VectorWriter, TableWriter
from processing.tools import dataobjects
from qgis.core import QgsExpressionContext, QgsExpressionContextUtils, QgsExpression, QgsExpressionContextScope
def _expressionContext(alg):
context = QgsExpressionContext()
context.appendScope(QgsExpressionContextUtils.globalScope())
context.appendScope(QgsExpressionContextUtils.projectScope())
processingScope = QgsExpressionContextScope()
for param in alg.parameters:
processingScope.setVariable('%s_value' % param.name, '')
context.appendScope(processingScope)
return context
class Output(object):
@ -82,6 +93,44 @@ class Output(object):
return True
except:
return False
def _resolveTemporary(self, alg):
ext = self.getDefaultFileExtension()
return getTempFilenameInTempFolder(self.name + '.' + ext)
def _supportedExtensions(self):
return []
def resolveValue(self, alg):
if not self.hidden and not bool(self.value):
self.value = self._resolveTemporary(alg)
else:
exp = QgsExpression(self.value)
if exp.hasParserError():
raise ValueError(self.tr("Error in output expression: ") + exp.parserErrorString())
self.value = exp.evaluate(_expressionContext(alg))
if exp.hasEvalError():
raise ValueError("Error evaluating output expression: " + exp.evalErrorString())
print self.value
if ":" not in self.value:
if not os.path.isabs(self.value):
self.value = os.path.join(ProcessingConfig.getSetting(ProcessingConfig.OUTPUT_FOLDER),
self.value)
supported = self._supportedExtensions()
if supported:
idx = self.value.rfind('.')
if idx == -1:
self.value = self.value + '.' + self.getDefaultFileExtension()
else:
ext = self.value[idx + 1:]
if ext not in supported:
self.value = self.value + '.' + self.getDefaultFileExtension()
def expressionContext(self, alg):
return _expressionContext(alg)
def typeName(self):
return self.__class__.__name__.replace('Output', '').lower()
@ -93,7 +142,9 @@ class Output(object):
class OutputDirectory(Output):
directory = True
def resolveValue(self, alg):
self.value = getTempDirInTempFolder()
class OutputExtent(Output):
@ -118,10 +169,7 @@ class OutputExtent(Output):
class OutputCrs(Output):
def __init__(self, name='', description=''):
self.name = name
self.description = description
self.value = None
self.hidden = True
Output.__init__(self, name, description, True)
class OutputFile(Output):
@ -136,7 +184,7 @@ class OutputFile(Output):
else:
return self.tr('%s files(*.%s)', 'OutputFile') % (self.ext, self.ext)
def getDefaultFileExtension(self, alg):
def getDefaultFileExtension(self):
return self.ext or 'file'
@ -145,17 +193,14 @@ class OutputHTML(Output):
def getFileFilter(self, alg):
return self.tr('HTML files(*.html)', 'OutputHTML')
def getDefaultFileExtension(self, alg):
def getDefaultFileExtension(self):
return 'html'
class OutputNumber(Output):
def __init__(self, name='', description=''):
self.name = name
self.description = description
self.value = None
self.hidden = True
Output.__init__(self, name, description, True)
class OutputRaster(Output):
@ -168,11 +213,8 @@ class OutputRaster(Output):
exts[i] = self.tr('%s files (*.%s)', 'OutputVector') % (exts[i].upper(), exts[i].lower())
return ';;'.join(exts)
def getDefaultFileExtension(self, alg):
supported = alg.provider.getSupportedOutputRasterLayerExtensions()
default = ProcessingConfig.getSetting(ProcessingConfig.DEFAULT_OUTPUT_RASTER_LAYER_EXT)
ext = default if default in supported else supported[0]
return ext
def getDefaultFileExtension(self):
return ProcessingConfig.getSetting(ProcessingConfig.DEFAULT_OUTPUT_RASTER_LAYER_EXT)
def getCompatibleFileName(self, alg):
"""
@ -189,18 +231,17 @@ class OutputRaster(Output):
return self.value
else:
if self.compatible is None:
self.compatible = getTempFilenameInTempFolder(
self.name + '.' + self.getDefaultFileExtension(alg))
supported = alg.provider.getSupportedOutputRasterLayerExtensions()
default = ProcessingConfig.getSetting(ProcessingConfig.DEFAULT_OUTPUT_RASTER_LAYER_EXT)
ext = default if default in supported else supported[0]
self.compatible = getTempFilenameInTempFolder(self.name + '.' + ext)
return self.compatible
class OutputString(Output):
def __init__(self, name='', description=''):
self.name = name
self.description = description
self.value = None
self.hidden = True
Output.__init__(self, name, description, True)
class OutputTable(Output):
@ -209,13 +250,13 @@ class OutputTable(Output):
compatible = None
def getFileFilter(self, alg):
exts = ['csv']
exts = ['dbf']
for i in range(len(exts)):
exts[i] = exts[i].upper() + ' files(*.' + exts[i].lower() + ')'
return ';;'.join(exts)
def getDefaultFileExtension(self, alg):
return alg.provider.getSupportedOutputTableExtensions()[0]
def getDefaultFileExtension(self):
return "dbf"
def getCompatibleFileName(self, alg):
"""Returns a filename that is compatible with the algorithm
@ -233,7 +274,7 @@ class OutputTable(Output):
else:
if self.compatible is None:
self.compatible = getTempFilenameInTempFolder(
self.name + '.' + self.getDefaultFileExtension(alg))
self.name + '.' + alg.provider.getSupportedOutputTableExtensions()[0])
return self.compatible
def getTableWriter(self, fields):
@ -286,14 +327,13 @@ class OutputVector(Output):
exts[i] = self.tr('%s files (*.%s)', 'OutputVector') % (exts[i].upper(), exts[i].lower())
return ';;'.join(exts)
def getDefaultFileExtension(self, alg):
supported = alg.provider.getSupportedOutputVectorLayerExtensions()
def getDefaultFileExtension(self):
if self.hasGeometry():
default = ProcessingConfig.getSetting(ProcessingConfig.DEFAULT_OUTPUT_VECTOR_LAYER_EXT)
else:
default = 'dbf'
ext = default if default in supported else supported[0]
return ext
return default
def getCompatibleFileName(self, alg):
"""Returns a filename that is compatible with the algorithm
@ -309,8 +349,10 @@ class OutputVector(Output):
return self.value
else:
if self.compatible is None:
self.compatible = getTempFilenameInTempFolder(
self.name + '.' + self.getDefaultFileExtension(alg))
default = self.getDefaultFileExtension()
supported = alg.provider.getSupportedOutputVectorLayerExtensions()
ext = default if default in supported else supported[0]
self.compatible = getTempFilenameInTempFolder(self.name + '.' + ext)
return self.compatible
def getVectorWriter(self, fields, geomType, crs, options=None):
@ -345,7 +387,13 @@ class OutputVector(Output):
def dataType(self):
return dataobjects.vectorDataType(self)
def _resolveTemporary(self, alg):
if alg.provider.supportsNonFileBasedOutput():
return "memory:"
else:
ext = self.getDefaultFileExtension()
return getTempFilenameInTempFolder(self.name + '.' + ext)
def getOutputFromString(s):
try:

View File

@ -102,6 +102,17 @@ def _expressionContext():
context.appendScope(processingScope)
return context
def _resolveLayers(value):
layers = dataobjects.getAllLayers()
if value:
inputlayers = value.split(';')
for i, inputlayer in enumerate(inputlayers):
for layer in layers:
if layer.name() == inputlayer:
inputlayers[i] = layer.source()
break
return ";".join(inputlayers)
class Parameter:
"""
@ -312,6 +323,9 @@ class ParameterDataObject(Parameter):
s = dataobjects.normalizeLayerSource(str(self.value))
s = '"%s"' % s
return s
def evaluate(self, alg):
self.value = _resolveLayers(self.value)
class ParameterExtent(Parameter):
@ -771,6 +785,9 @@ class ParameterMultipleInput(ParameterDataObject):
return ParameterMultipleInput(name, definition,
dataobjects.TYPE_VECTOR_ANY, isOptional)
def evaluate(self, alg):
self.value = _resolveLayers(self.value)
class ParameterNumber(Parameter):
@ -861,7 +878,7 @@ class ParameterNumber(Parameter):
return result
def evaluate(self, alg):
if isinstance(self.value, basestring):
if isinstance(self.value, basestring) and bool(self.value):
self.value = self._evaluate(self.value)
def _layerVariables(self, element, alg=None):
@ -1024,7 +1041,6 @@ class ParameterRaster(ParameterDataObject):
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)
@ -1111,7 +1127,7 @@ class ParameterString(Parameter):
self.evaluateExpressions = parseBool(evaluateExpressions)
def setValue(self, obj):
if obj is None:
if not bool(obj):
if not self.optional:
return False
self.value = None
@ -1153,13 +1169,14 @@ class ParameterString(Parameter):
return ParameterString(name, descName, multiline=True, optional=isOptional)
def evaluate(self, alg):
exp = QgsExpression(self.value)
if exp.hasParserError():
raise ValueError(self.tr("Error in parameter expression: ") + exp.parserErrorString())
result = exp.evaluate(_expressionContext())
if exp.hasEvalError():
raise ValueError("Error evaluating parameter expression: " + exp.evalErrorString())
self.value = result
if isinstance(self.value, basestring) and bool(self.value) and self.evaluateExpressions:
exp = QgsExpression(self.value)
if exp.hasParserError():
raise ValueError(self.tr("Error in parameter expression: ") + exp.parserErrorString())
result = exp.evaluate(_expressionContext())
if exp.hasEvalError():
raise ValueError("Error evaluating parameter expression: " + exp.evalErrorString())
self.value = result
def expressionContext(self):
return _expressionContext()

View File

@ -83,14 +83,14 @@ class OutputSelectionPanel(BASE, WIDGET):
if isinstance(self.output, OutputVector) \
and self.alg.provider.supportsNonFileBasedOutput():
# use memory layers for temporary files if supported
actionSaveToTempFile = QAction(
# use memory layers for temporary layers if supported
actionSaveToTemp = QAction(
self.tr('Create temporary layer'), self.btnSelect)
else:
actionSaveToTempFile = QAction(
actionSaveToTemp = QAction(
self.tr('Save to a temporary file'), self.btnSelect)
actionSaveToTempFile.triggered.connect(self.saveToTemporaryFile)
popupMenu.addAction(actionSaveToTempFile)
actionSaveToTemp.triggered.connect(self.saveToTemporary)
popupMenu.addAction(actionSaveToTemp)
actionSaveToFile = QAction(
self.tr('Save to file...'), self.btnSelect)
@ -121,22 +121,13 @@ class OutputSelectionPanel(BASE, WIDGET):
popupMenu.exec_(QCursor.pos())
def showExpressionsBuilder(self):
dlg = QgsExpressionBuilderDialog(None, self.leText.text(), self, 'generic', self.expressionContext())
dlg = QgsExpressionBuilderDialog(None, self.leText.text(), self, 'generic',
self.output.expressionContext(self.alg))
dlg.setWindowTitle(self.tr('Expression based output'))
if dlg.exec_() == QDialog.Accepted:
self.leText.setText(dlg.expressionText())
def expressionContext(self):
context = QgsExpressionContext()
context.appendScope(QgsExpressionContextUtils.globalScope())
context.appendScope(QgsExpressionContextUtils.projectScope())
processingScope = QgsExpressionContextScope()
for param in self.alg.parameters:
processingScope.setVariable('%s_value' % param.name, '')
context.appendScope(processingScope)
return context
def saveToTemporaryFile(self):
def saveToTemporary(self):
self.leText.setText('')
def saveToPostGIS(self):
@ -237,32 +228,4 @@ class OutputSelectionPanel(BASE, WIDGET):
self.leText.setText(dirName)
def getValue(self):
fileName = str(self.leText.text())
context = self.expressionContext()
exp = QgsExpression(fileName)
if not exp.hasParserError():
result = exp.evaluate(context)
if not exp.hasEvalError():
fileName = result
if fileName.startswith("[") and fileName.endswith("]"):
fileName = fileName[1:-1]
if fileName.strip() in ['', self.SAVE_TO_TEMP_FILE, self.SAVE_TO_TEMP_LAYER]:
if isinstance(self.output, OutputVector) \
and self.alg.provider.supportsNonFileBasedOutput():
# use memory layers for temporary files if supported
value = 'memory:'
else:
value = None
elif fileName.startswith('memory:'):
value = fileName
elif fileName.startswith('postgis:'):
value = fileName
elif fileName.startswith('spatialite:'):
value = fileName
elif not os.path.isabs(fileName):
value = ProcessingConfig.getSetting(
ProcessingConfig.OUTPUT_FOLDER) + os.sep + fileName
else:
value = fileName
return value
return self.leText.text()