Skip to content

Commit dfb4cdd

Browse files
committedOct 5, 2016
[processing] moved output value evaluation to output object itself
1 parent 2bb6e4c commit dfb4cdd

File tree

5 files changed

+129
-135
lines changed

5 files changed

+129
-135
lines changed
 

‎python/plugins/processing/algs/qgis/FieldsCalculator.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,6 @@ def processAlgorithm(self, progress):
8989

9090
output = self.getOutputFromName(self.OUTPUT_LAYER)
9191

92-
if output.value == '':
93-
ext = output.getDefaultFileExtension(self)
94-
output.value = system.getTempFilenameInTempFolder(
95-
output.name + '.' + ext)
96-
9792
fields = layer.fields()
9893
if newField:
9994
fields.append(QgsField(fieldName, fieldType, '', width, precision))

‎python/plugins/processing/core/GeoAlgorithm.py

Lines changed: 10 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -197,10 +197,8 @@ def execute(self, progress=SilentProgress(), model=None):
197197
self.model = model
198198
try:
199199
self.setOutputCRS()
200-
self.resolveTemporaryOutputs()
201-
self.resolveDataObjects()
200+
self.resolveOutputs()
202201
self.evaluateParameterValues()
203-
self.checkOutputFileExtensions()
204202
self.runPreExecutionScript(progress)
205203
self.processAlgorithm(progress)
206204
progress.setPercentage(100)
@@ -328,51 +326,24 @@ def getFormatShortNameFromFilename(self, filename):
328326
return name
329327
return 'GTiff'
330328

331-
def checkOutputFileExtensions(self):
332-
"""Checks if the values of outputs are correct and have one of
333-
the supported output extensions.
334-
335-
If not, it adds the first one of the supported extensions, which
336-
is assumed to be the default one.
337-
"""
338-
for out in self.outputs:
339-
if not out.hidden and out.value is not None:
340-
if not os.path.isabs(out.value):
341-
continue
342-
if isinstance(out, OutputRaster):
343-
exts = dataobjects.getSupportedOutputRasterLayerExtensions()
344-
elif isinstance(out, OutputVector):
345-
exts = dataobjects.getSupportedOutputVectorLayerExtensions()
346-
elif isinstance(out, OutputTable):
347-
exts = dataobjects.getSupportedOutputTableExtensions()
348-
elif isinstance(out, OutputHTML):
349-
exts = ['html', 'htm']
350-
else:
351-
continue
352-
idx = out.value.rfind('.')
353-
if idx == -1:
354-
out.value = out.value + '.' + exts[0]
355-
else:
356-
ext = out.value[idx + 1:]
357-
if ext not in exts + ['dbf']:
358-
out.value = out.value + '.' + exts[0]
359-
360-
361329
def evaluateParameterValues(self):
362330
for param in self.parameters:
363331
try:
364332
param.evaluate(self)
365333
except ValueError, e:
334+
traceback.print_exc()
366335
raise GeoAlgorithmExecutionException(str(e))
367336

368-
def resolveTemporaryOutputs(self):
337+
def resolveOutputs(self):
369338
"""Sets temporary outputs (output.value = None) with a
370-
temporary file instead.
339+
temporary file instead. Resolves expressions as well.
371340
"""
372-
for out in self.outputs:
373-
if not out.hidden and out.value is None:
374-
setTempOutput(out, self)
375-
341+
try:
342+
for out in self.outputs:
343+
out.resolveValue(self)
344+
except ValueError, e:
345+
raise GeoAlgorithmExecutionException(str(e))
346+
376347
def setOutputCRS(self):
377348
layers = dataobjects.getAllLayers()
378349
for param in self.parameters:

‎python/plugins/processing/core/outputs.py

Lines changed: 83 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
from builtins import range
2121
from builtins import object
2222

23-
2423
__author__ = 'Victor Olaya'
2524
__date__ = 'August 2012'
2625
__copyright__ = '(C) 2012, Victor Olaya'
@@ -29,15 +28,27 @@
2928

3029
__revision__ = '$Format:%H$'
3130

31+
import os
3232
import sys
3333

3434
from qgis.PyQt.QtCore import QCoreApplication, QSettings
3535

3636
from processing.core.ProcessingConfig import ProcessingConfig
37-
from processing.tools.system import isWindows, getTempFilenameInTempFolder
37+
from processing.tools.system import isWindows, getTempFilenameInTempFolder, getTempDirInTempFolder
3838
from processing.tools.vector import VectorWriter, TableWriter
3939
from processing.tools import dataobjects
4040

41+
from qgis.core import QgsExpressionContext, QgsExpressionContextUtils, QgsExpression, QgsExpressionContextScope
42+
43+
def _expressionContext(alg):
44+
context = QgsExpressionContext()
45+
context.appendScope(QgsExpressionContextUtils.globalScope())
46+
context.appendScope(QgsExpressionContextUtils.projectScope())
47+
processingScope = QgsExpressionContextScope()
48+
for param in alg.parameters:
49+
processingScope.setVariable('%s_value' % param.name, '')
50+
context.appendScope(processingScope)
51+
return context
4152

4253
class Output(object):
4354

@@ -82,6 +93,44 @@ def setValue(self, value):
8293
return True
8394
except:
8495
return False
96+
97+
def _resolveTemporary(self, alg):
98+
ext = self.getDefaultFileExtension()
99+
return getTempFilenameInTempFolder(self.name + '.' + ext)
100+
101+
def _supportedExtensions(self):
102+
return []
103+
104+
def resolveValue(self, alg):
105+
if not self.hidden and not bool(self.value):
106+
self.value = self._resolveTemporary(alg)
107+
else:
108+
exp = QgsExpression(self.value)
109+
if exp.hasParserError():
110+
raise ValueError(self.tr("Error in output expression: ") + exp.parserErrorString())
111+
self.value = exp.evaluate(_expressionContext(alg))
112+
if exp.hasEvalError():
113+
raise ValueError("Error evaluating output expression: " + exp.evalErrorString())
114+
115+
116+
117+
print self.value
118+
if ":" not in self.value:
119+
if not os.path.isabs(self.value):
120+
self.value = os.path.join(ProcessingConfig.getSetting(ProcessingConfig.OUTPUT_FOLDER),
121+
self.value)
122+
supported = self._supportedExtensions()
123+
if supported:
124+
idx = self.value.rfind('.')
125+
if idx == -1:
126+
self.value = self.value + '.' + self.getDefaultFileExtension()
127+
else:
128+
ext = self.value[idx + 1:]
129+
if ext not in supported:
130+
self.value = self.value + '.' + self.getDefaultFileExtension()
131+
132+
def expressionContext(self, alg):
133+
return _expressionContext(alg)
85134

86135
def typeName(self):
87136
return self.__class__.__name__.replace('Output', '').lower()
@@ -93,7 +142,9 @@ def tr(self, string, context=''):
93142

94143

95144
class OutputDirectory(Output):
96-
directory = True
145+
146+
def resolveValue(self, alg):
147+
self.value = getTempDirInTempFolder()
97148

98149

99150
class OutputExtent(Output):
@@ -118,10 +169,7 @@ def setValue(self, value):
118169
class OutputCrs(Output):
119170

120171
def __init__(self, name='', description=''):
121-
self.name = name
122-
self.description = description
123-
self.value = None
124-
self.hidden = True
172+
Output.__init__(self, name, description, True)
125173

126174

127175
class OutputFile(Output):
@@ -136,7 +184,7 @@ def getFileFilter(self, alg):
136184
else:
137185
return self.tr('%s files(*.%s)', 'OutputFile') % (self.ext, self.ext)
138186

139-
def getDefaultFileExtension(self, alg):
187+
def getDefaultFileExtension(self):
140188
return self.ext or 'file'
141189

142190

@@ -145,17 +193,14 @@ class OutputHTML(Output):
145193
def getFileFilter(self, alg):
146194
return self.tr('HTML files(*.html)', 'OutputHTML')
147195

148-
def getDefaultFileExtension(self, alg):
196+
def getDefaultFileExtension(self):
149197
return 'html'
150198

151199

152200
class OutputNumber(Output):
153201

154202
def __init__(self, name='', description=''):
155-
self.name = name
156-
self.description = description
157-
self.value = None
158-
self.hidden = True
203+
Output.__init__(self, name, description, True)
159204

160205

161206
class OutputRaster(Output):
@@ -168,11 +213,8 @@ def getFileFilter(self, alg):
168213
exts[i] = self.tr('%s files (*.%s)', 'OutputVector') % (exts[i].upper(), exts[i].lower())
169214
return ';;'.join(exts)
170215

171-
def getDefaultFileExtension(self, alg):
172-
supported = alg.provider.getSupportedOutputRasterLayerExtensions()
173-
default = ProcessingConfig.getSetting(ProcessingConfig.DEFAULT_OUTPUT_RASTER_LAYER_EXT)
174-
ext = default if default in supported else supported[0]
175-
return ext
216+
def getDefaultFileExtension(self):
217+
return ProcessingConfig.getSetting(ProcessingConfig.DEFAULT_OUTPUT_RASTER_LAYER_EXT)
176218

177219
def getCompatibleFileName(self, alg):
178220
"""
@@ -189,18 +231,17 @@ def getCompatibleFileName(self, alg):
189231
return self.value
190232
else:
191233
if self.compatible is None:
192-
self.compatible = getTempFilenameInTempFolder(
193-
self.name + '.' + self.getDefaultFileExtension(alg))
234+
supported = alg.provider.getSupportedOutputRasterLayerExtensions()
235+
default = ProcessingConfig.getSetting(ProcessingConfig.DEFAULT_OUTPUT_RASTER_LAYER_EXT)
236+
ext = default if default in supported else supported[0]
237+
self.compatible = getTempFilenameInTempFolder(self.name + '.' + ext)
194238
return self.compatible
195239

196240

197241
class OutputString(Output):
198242

199243
def __init__(self, name='', description=''):
200-
self.name = name
201-
self.description = description
202-
self.value = None
203-
self.hidden = True
244+
Output.__init__(self, name, description, True)
204245

205246

206247
class OutputTable(Output):
@@ -209,13 +250,13 @@ class OutputTable(Output):
209250
compatible = None
210251

211252
def getFileFilter(self, alg):
212-
exts = ['csv']
253+
exts = ['dbf']
213254
for i in range(len(exts)):
214255
exts[i] = exts[i].upper() + ' files(*.' + exts[i].lower() + ')'
215256
return ';;'.join(exts)
216257

217-
def getDefaultFileExtension(self, alg):
218-
return alg.provider.getSupportedOutputTableExtensions()[0]
258+
def getDefaultFileExtension(self):
259+
return "dbf"
Code has comments. Press enter to view.
219260

220261
def getCompatibleFileName(self, alg):
221262
"""Returns a filename that is compatible with the algorithm
@@ -233,7 +274,7 @@ def getCompatibleFileName(self, alg):
233274
else:
234275
if self.compatible is None:
235276
self.compatible = getTempFilenameInTempFolder(
236-
self.name + '.' + self.getDefaultFileExtension(alg))
277+
self.name + '.' + alg.provider.getSupportedOutputTableExtensions()[0])
237278
return self.compatible
238279

239280
def getTableWriter(self, fields):
@@ -286,14 +327,13 @@ def getFileFilter(self, alg):
286327
exts[i] = self.tr('%s files (*.%s)', 'OutputVector') % (exts[i].upper(), exts[i].lower())
287328
return ';;'.join(exts)
288329

289-
def getDefaultFileExtension(self, alg):
290-
supported = alg.provider.getSupportedOutputVectorLayerExtensions()
330+
def getDefaultFileExtension(self):
291331
if self.hasGeometry():
292332
default = ProcessingConfig.getSetting(ProcessingConfig.DEFAULT_OUTPUT_VECTOR_LAYER_EXT)
293333
else:
294334
default = 'dbf'
295-
ext = default if default in supported else supported[0]
296-
return ext
335+
return default
336+
297337

298338
def getCompatibleFileName(self, alg):
299339
"""Returns a filename that is compatible with the algorithm
@@ -309,8 +349,10 @@ def getCompatibleFileName(self, alg):
309349
return self.value
310350
else:
311351
if self.compatible is None:
312-
self.compatible = getTempFilenameInTempFolder(
313-
self.name + '.' + self.getDefaultFileExtension(alg))
352+
default = self.getDefaultFileExtension()
353+
supported = alg.provider.getSupportedOutputVectorLayerExtensions()
354+
ext = default if default in supported else supported[0]
355+
self.compatible = getTempFilenameInTempFolder(self.name + '.' + ext)
314356
return self.compatible
315357

316358
def getVectorWriter(self, fields, geomType, crs, options=None):
@@ -345,7 +387,13 @@ def getVectorWriter(self, fields, geomType, crs, options=None):
345387
def dataType(self):
346388
return dataobjects.vectorDataType(self)
347389

348-
390+
def _resolveTemporary(self, alg):
391+
if alg.provider.supportsNonFileBasedOutput():
392+
return "memory:"
393+
else:
394+
ext = self.getDefaultFileExtension()
395+
return getTempFilenameInTempFolder(self.name + '.' + ext)
396+
349397

350398
def getOutputFromString(s):
351399
try:

‎python/plugins/processing/core/parameters.py

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,17 @@ def _expressionContext():
102102
context.appendScope(processingScope)
103103
return context
104104

105+
def _resolveLayers(value):
106+
layers = dataobjects.getAllLayers()
107+
if value:
108+
inputlayers = value.split(';')
109+
for i, inputlayer in enumerate(inputlayers):
110+
for layer in layers:
111+
if layer.name() == inputlayer:
112+
inputlayers[i] = layer.source()
113+
break
114+
return ";".join(inputlayers)
115+
105116
class Parameter:
106117

107118
"""
@@ -312,6 +323,9 @@ def getValueAsCommandLineParameter(self):
312323
s = dataobjects.normalizeLayerSource(str(self.value))
313324
s = '"%s"' % s
314325
return s
326+
327+
def evaluate(self, alg):
328+
self.value = _resolveLayers(self.value)
315329

316330

317331
class ParameterExtent(Parameter):
@@ -771,6 +785,9 @@ def fromScriptCode(self, line):
771785
return ParameterMultipleInput(name, definition,
772786
dataobjects.TYPE_VECTOR_ANY, isOptional)
773787

788+
def evaluate(self, alg):
789+
self.value = _resolveLayers(self.value)
790+
774791

775792
class ParameterNumber(Parameter):
776793

@@ -861,7 +878,7 @@ def _evaluate(self, value):
861878
return result
862879

863880
def evaluate(self, alg):
864-
if isinstance(self.value, basestring):
881+
if isinstance(self.value, basestring) and bool(self.value):
865882
self.value = self._evaluate(self.value)
866883

867884
def _layerVariables(self, element, alg=None):
@@ -1024,7 +1041,6 @@ def getAsScriptCode(self):
10241041
def fromScriptCode(self, line):
10251042
isOptional, name, definition = _splitParameterOptions(line)
10261043
descName = _createDescriptiveName(name)
1027-
print isOptional, name, definition
10281044
if definition.lower().strip().startswith('raster'):
10291045
return ParameterRaster(name, descName, optional=isOptional)
10301046

@@ -1111,7 +1127,7 @@ def __init__(self, name='', description='', default=None, multiline=False,
11111127
self.evaluateExpressions = parseBool(evaluateExpressions)
11121128

11131129
def setValue(self, obj):
1114-
if obj is None:
1130+
if not bool(obj):
11151131
if not self.optional:
11161132
return False
11171133
self.value = None
@@ -1153,13 +1169,14 @@ def fromScriptCode(self, line):
11531169
return ParameterString(name, descName, multiline=True, optional=isOptional)
11541170

11551171
def evaluate(self, alg):
1156-
exp = QgsExpression(self.value)
1157-
if exp.hasParserError():
1158-
raise ValueError(self.tr("Error in parameter expression: ") + exp.parserErrorString())
1159-
result = exp.evaluate(_expressionContext())
1160-
if exp.hasEvalError():
1161-
raise ValueError("Error evaluating parameter expression: " + exp.evalErrorString())
1162-
self.value = result
1172+
if isinstance(self.value, basestring) and bool(self.value) and self.evaluateExpressions:
1173+
exp = QgsExpression(self.value)
1174+
if exp.hasParserError():
1175+
raise ValueError(self.tr("Error in parameter expression: ") + exp.parserErrorString())
1176+
result = exp.evaluate(_expressionContext())
1177+
if exp.hasEvalError():
1178+
raise ValueError("Error evaluating parameter expression: " + exp.evalErrorString())
1179+
self.value = result
11631180

11641181
def expressionContext(self):
11651182
return _expressionContext()

‎python/plugins/processing/gui/OutputSelectionPanel.py

Lines changed: 9 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -83,14 +83,14 @@ def selectOutput(self):
8383

8484
if isinstance(self.output, OutputVector) \
8585
and self.alg.provider.supportsNonFileBasedOutput():
86-
# use memory layers for temporary files if supported
87-
actionSaveToTempFile = QAction(
86+
# use memory layers for temporary layers if supported
87+
actionSaveToTemp = QAction(
8888
self.tr('Create temporary layer'), self.btnSelect)
8989
else:
90-
actionSaveToTempFile = QAction(
90+
actionSaveToTemp = QAction(
9191
self.tr('Save to a temporary file'), self.btnSelect)
92-
actionSaveToTempFile.triggered.connect(self.saveToTemporaryFile)
93-
popupMenu.addAction(actionSaveToTempFile)
92+
actionSaveToTemp.triggered.connect(self.saveToTemporary)
93+
popupMenu.addAction(actionSaveToTemp)
9494

9595
actionSaveToFile = QAction(
9696
self.tr('Save to file...'), self.btnSelect)
@@ -121,22 +121,13 @@ def selectOutput(self):
121121
popupMenu.exec_(QCursor.pos())
122122

123123
def showExpressionsBuilder(self):
124-
dlg = QgsExpressionBuilderDialog(None, self.leText.text(), self, 'generic', self.expressionContext())
124+
dlg = QgsExpressionBuilderDialog(None, self.leText.text(), self, 'generic',
125+
self.output.expressionContext(self.alg))
125126
dlg.setWindowTitle(self.tr('Expression based output'))
126127
if dlg.exec_() == QDialog.Accepted:
127128
self.leText.setText(dlg.expressionText())
128129

129-
def expressionContext(self):
130-
context = QgsExpressionContext()
131-
context.appendScope(QgsExpressionContextUtils.globalScope())
132-
context.appendScope(QgsExpressionContextUtils.projectScope())
133-
processingScope = QgsExpressionContextScope()
134-
for param in self.alg.parameters:
135-
processingScope.setVariable('%s_value' % param.name, '')
136-
context.appendScope(processingScope)
137-
return context
138-
139-
def saveToTemporaryFile(self):
130+
def saveToTemporary(self):
140131
self.leText.setText('')
141132

142133
def saveToPostGIS(self):
@@ -237,32 +228,4 @@ def selectDirectory(self):
237228
self.leText.setText(dirName)
238229

239230
def getValue(self):
240-
fileName = str(self.leText.text())
241-
context = self.expressionContext()
242-
exp = QgsExpression(fileName)
243-
if not exp.hasParserError():
244-
result = exp.evaluate(context)
245-
if not exp.hasEvalError():
246-
fileName = result
247-
if fileName.startswith("[") and fileName.endswith("]"):
248-
fileName = fileName[1:-1]
249-
if fileName.strip() in ['', self.SAVE_TO_TEMP_FILE, self.SAVE_TO_TEMP_LAYER]:
250-
if isinstance(self.output, OutputVector) \
251-
and self.alg.provider.supportsNonFileBasedOutput():
252-
# use memory layers for temporary files if supported
253-
value = 'memory:'
254-
else:
255-
value = None
256-
elif fileName.startswith('memory:'):
257-
value = fileName
258-
elif fileName.startswith('postgis:'):
259-
value = fileName
260-
elif fileName.startswith('spatialite:'):
261-
value = fileName
262-
elif not os.path.isabs(fileName):
263-
value = ProcessingConfig.getSetting(
264-
ProcessingConfig.OUTPUT_FOLDER) + os.sep + fileName
265-
else:
266-
value = fileName
267-
268-
return value
231+
return self.leText.text()

0 commit comments

Comments
 (0)
Please sign in to comment.