mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
[processing] moved output value evaluation to output object itself
This commit is contained in:
parent
2bb6e4c19f
commit
dfb4cdd34b
@ -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))
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
Loading…
x
Reference in New Issue
Block a user