Skip to content
Permalink
Browse files

[processing] support for expressions in numerical values in modeler

includes cleanup of modeler, to adapt to latest changes in parameters architecture
  • Loading branch information
volaya committed Oct 5, 2016
1 parent fe5d016 commit e08fdaa444f2ffdc138b0eb847210f0449fd97e0
@@ -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
@@ -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
@@ -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():
@@ -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):

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

def getAsScriptCode(self):
@@ -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())
@@ -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()
@@ -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:
@@ -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(
@@ -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:
@@ -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))
@@ -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):

This file was deleted.

0 comments on commit e08fdaa

Please sign in to comment.
You can’t perform that action at this time.