Skip to content

Commit

Permalink
[processing] support for expressions in numerical values in modeler
Browse files Browse the repository at this point in the history
includes cleanup of modeler, to adapt to latest changes in parameters architecture
  • Loading branch information
volaya committed Oct 5, 2016
1 parent fe5d016 commit e08fdaa
Show file tree
Hide file tree
Showing 10 changed files with 127 additions and 380 deletions.
1 change: 0 additions & 1 deletion python/plugins/processing/core/Processing.py
Expand Up @@ -54,7 +54,6 @@
from processing.core.alglist import algList

from processing.modeler.ModelerAlgorithmProvider import ModelerAlgorithmProvider
from processing.modeler.ModelerOnlyAlgorithmProvider import ModelerOnlyAlgorithmProvider
from processing.algs.qgis.QGISAlgorithmProvider import QGISAlgorithmProvider
from processing.algs.grass.GrassAlgorithmProvider import GrassAlgorithmProvider
from processing.algs.grass7.Grass7AlgorithmProvider import Grass7AlgorithmProvider
Expand Down
41 changes: 35 additions & 6 deletions python/plugins/processing/core/parameters.py
Expand Up @@ -32,6 +32,7 @@
import os
from inspect import isclass
from copy import deepcopy
import numbers

from qgis.utils import iface
from qgis.PyQt.QtCore import QCoreApplication
Expand All @@ -40,6 +41,7 @@

from processing.tools.vector import resolveFieldIndex, features
from processing.tools import dataobjects
from processing.core.outputs import OutputNumber

def parseBool(s):
if s is None or s == str(None).lower():
Expand Down Expand Up @@ -192,6 +194,9 @@ def wrapper(self, dialog, row=0, col=0):

def evaluate(self, alg):
pass

def evaluateForModeler(self, value, model):
return value

class ParameterBoolean(Parameter):

Expand Down Expand Up @@ -810,6 +815,7 @@ def setValue(self, n):
self.value = float(v)
return True
except:
raise
return False
else:
try:
Expand All @@ -826,6 +832,7 @@ def setValue(self, n):
self.value = value
return True
except:
raise
return False

def getAsScriptCode(self):
Expand All @@ -843,8 +850,8 @@ def fromScriptCode(self, line):
default = definition.strip()[len('number') + 1:] or None
return ParameterNumber(name, descName, default=default, optional=isOptional)

def _evaluate(self):
exp = QgsExpression(self.value)
def _evaluate(self, value):
exp = QgsExpression(value)
if exp.hasParserError():
raise ValueError(self.tr("Error in parameter expression: ") + exp.parserErrorString())
result = exp.evaluate(_expressionContext())
Expand All @@ -853,7 +860,26 @@ def _evaluate(self):
return result

def evaluate(self, alg):
self.value = self._evaluate(self.value)
if isinstance(self.value, basestring):
self.value = self._evaluate(self.value)

def evaluateForModeler(self, value, model):
if isinstance(value, numbers.Number):
return value
variables = {}
for param in model.parameters:
if isinstance(param, ParameterNumber):
variables["@" + param.name] = param.value
for alg in model.algs.values():
for out in alg.algorithm.outputs:
if isinstance(out, OutputNumber):
variables["@%s_%s" % (alg.name, out.name)] = out.value
for k,v in variables.iteritems():
print k,v
value = value.replace(k,unicode(v))

print value
return value

def expressionContext(self):
return _expressionContext()
Expand Down Expand Up @@ -1427,9 +1453,12 @@ def getParameterFromString(s):
isAdvanced = True
tokens = s.split("|")
params = [t if unicode(t) != unicode(None) else None for t in tokens[1:]]
clazz = getattr(sys.modules[__name__], tokens[0])
param = clazz(*params)
param.isAdvanced = isAdvanced
try:
clazz = getattr(sys.modules[__name__], tokens[0])
param = clazz(*params)
param.isAdvanced = isAdvanced
except:
return None
else: # try script syntax
for paramClass in paramClasses:
try:
Expand Down
39 changes: 34 additions & 5 deletions python/plugins/processing/gui/NumberInputPanel.py
Expand Up @@ -35,9 +35,13 @@
from qgis.core import (QgsDataSourceUri,
QgsCredentials,
QgsExpression,
QgsRasterLayer)
QgsRasterLayer,
QgsExpressionContextScope)
from qgis.gui import QgsEncodingFileDialog, QgsExpressionBuilderDialog
from qgis.utils import iface
from processing.core.parameters import ParameterNumber
from processing.core.outputs import OutputNumber
from processing.modeler.ModelerAlgorithm import ValueFromInput, ValueFromOutput, CompoundValue

pluginPath = os.path.split(os.path.dirname(__file__))[0]
WIDGET, BASE = uic.loadUiType(
Expand All @@ -48,18 +52,27 @@ class NumberInputPanel(BASE, WIDGET):

hasChanged = pyqtSignal()

def __init__(self, param):
def __init__(self, param, modelParametersDialog=None):
super(NumberInputPanel, self).__init__(None)
self.setupUi(self)

self.param = param
self.text = param.default

self.modelParametersDialog = modelParametersDialog
if param.default:
self.setValue(param.default)
self.btnSelect.clicked.connect(self.showExpressionsBuilder)
self.leText.textChanged.connect(lambda: self.hasChanged.emit())

def showExpressionsBuilder(self):
context = self.param.expressionContext()
if self.modelParametersDialog is not None:
context.popScope()
values = self.modelParametersDialog.getAvailableValuesOfType(ParameterNumber, OutputNumber)
modelerScope = QgsExpressionContextScope()
for value in values:
name = value.name if isinstance(value, ValueFromInput) else "%s_%s" % (value.alg, value.output)
modelerScope.setVariable(name, 1)
context.appendScope(modelerScope)
dlg = QgsExpressionBuilderDialog(None, self.leText.text(), self, 'generic', context)
dlg.setWindowTitle(self.tr('Expression based input'))
if dlg.exec_() == QDialog.Accepted:
Expand All @@ -69,7 +82,23 @@ def showExpressionsBuilder(self):


def getValue(self):
return self.leText.text()
if self.modelParametersDialog:
value = self.leText.text()
values = []
for param in self.modelParametersDialog.model.parameters:
if isinstance(param, ParameterNumber):
if "@" + param.name in value:
values.append(ValueFromInput(param.name))
for alg in self.modelParametersDialog.model.algs.values():
for out in alg.algorithm.outputs:
if isinstance(out, OutputNumber) and "@%s_%s" % (alg.name, out.name) in value:
values.append(ValueFromOutput(alg.name, out.name))
if values:
return CompoundValue(values, value)
else:
return value
else:
return self.leText.text()

def setValue(self, value):
self.leText.setText(unicode(value))
34 changes: 5 additions & 29 deletions python/plugins/processing/gui/wrappers.py
Expand Up @@ -455,39 +455,15 @@ class NumberWidgetWrapper(WidgetWrapper):

def createWidget(self):
if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
return NumberInputPanel(self.param)
return NumberInputPanel(self.param, None)
else:
widget = QComboBox()
widget.setEditable(True)
files = self.dialog.getAvailableValuesOfType(ParameterNumber, OutputNumber)
for f in files:
widget.addItem(self.dialog.resolveValueDescription(f), f)
return widget
return NumberInputPanel(self.param, self.dialog)

def setValue(self, value):
if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
self.widget.setValue(value)
else:
self.setComboValue(value)

self.widget.setValue(value)

def value(self):
if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
return self.widget.getValue()
else:
def validator(v):
if str(v).strip():
try:
if self.param.isInteger:
int(v)
else:
float(v)
return True
except:
return False
else:
return self.param.optional
return self.comboValue(validator)

return self.widget.getValue()

class RasterWidgetWrapper(WidgetWrapper):

Expand Down
145 changes: 0 additions & 145 deletions python/plugins/processing/modeler/CalculatorModelerAlgorithm.py

This file was deleted.

0 comments on commit e08fdaa

Please sign in to comment.