Skip to content

Commit

Permalink
Move expression context generation out of parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Jun 5, 2017
1 parent 416770b commit 28f7a8b
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 72 deletions.
9 changes: 0 additions & 9 deletions python/plugins/processing/core/GeoAlgorithm.py
Expand Up @@ -120,7 +120,6 @@ def execute(self, parameters, context=None, feedback=None, model=None):
try:
self.setOutputCRS()
self.resolveOutputs()
self.evaluateParameterValues()
self.runPreExecutionScript(feedback)
self.processAlgorithm(parameters, context, feedback)
feedback.setProgress(100)
Expand Down Expand Up @@ -229,14 +228,6 @@ def getFormatShortNameFromFilename(self, filename):
return name
return 'GTiff'

def evaluateParameterValues(self):
for param in self.parameters:
try:
param.evaluate(self)
except ValueError as e:
traceback.print_exc()
raise GeoAlgorithmExecutionException(str(e))

def resolveOutputs(self):
"""Sets temporary outputs (output.value = None) with a
temporary file instead. Resolves expressions as well.
Expand Down
62 changes: 3 additions & 59 deletions python/plugins/processing/core/parameters.py
Expand Up @@ -37,10 +37,10 @@
import numbers

from qgis.core import QgsProcessingUtils
from qgis.utils import iface

from qgis.PyQt.QtCore import QCoreApplication
from qgis.core import (QgsRasterLayer, QgsVectorLayer, QgsMapLayer, QgsCoordinateReferenceSystem,
QgsExpressionContext, QgsExpressionContextUtils, QgsExpression, QgsExpressionContextScope,
QgsExpression,
QgsProject,
QgsRectangle,
QgsVectorFileWriter,
Expand Down Expand Up @@ -72,25 +72,6 @@ def _createDescriptiveName(s):
return s.replace('_', ' ')


def _expressionContext():
context = QgsExpressionContext()
context.appendScope(QgsExpressionContextUtils.globalScope())
context.appendScope(QgsExpressionContextUtils.projectScope(QgsProject.instance()))

if iface.mapCanvas():
context.appendScope(QgsExpressionContextUtils.mapSettingsScope(iface.mapCanvas().mapSettings()))

processingScope = QgsExpressionContextScope()

extent = iface.mapCanvas().fullExtent()
processingScope.setVariable('fullextent_minx', extent.xMinimum())
processingScope.setVariable('fullextent_miny', extent.yMinimum())
processingScope.setVariable('fullextent_maxx', extent.xMaximum())
processingScope.setVariable('fullextent_maxy', extent.yMaximum())
context.appendScope(processingScope)
return context


class Parameter(object):

"""
Expand Down Expand Up @@ -139,9 +120,6 @@ def tr(self, string, context=''):
context = 'Parameter'
return QCoreApplication.translate(context, string)

def evaluate(self, alg):
pass


class ParameterBoolean(Parameter):

Expand Down Expand Up @@ -726,8 +704,7 @@ def setValue(self, n):

if isinstance(n, str):
try:
v = self._evaluate(n)
self.value = float(v)
self.value = float(n)
if self.isInteger:
self.value = int(math.floor(self.value))
return True
Expand Down Expand Up @@ -772,22 +749,6 @@ def fromScriptCode(self, line):
default = None
return ParameterNumber(name, descName, default=default, optional=isOptional)

def _evaluate(self, value):
exp = QgsExpression(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())
if self.isInteger:
return math.floor(result)
else:
return result

def evaluate(self, alg):
if isinstance(self.value, str) and bool(self.value):
self.value = self._evaluate(self.value)

def _layerVariables(self, element, alg=None):
variables = {}
context = dataobjects.createContext()
Expand Down Expand Up @@ -827,9 +788,6 @@ def evaluateForModeler(self, value, model):

return value

def expressionContext(self):
return _expressionContext()

def getValueAsCommandLineParameter(self):
if self.value is None:
return str(None)
Expand Down Expand Up @@ -1070,7 +1028,6 @@ def __init__(self, name='', description='', default=None, multiline=False,
optional=False, evaluateExpressions=False, metadata={}):
Parameter.__init__(self, name, description, default, optional, metadata)
self.multiline = parseBool(multiline)
self.evaluateExpressions = parseBool(evaluateExpressions)

def setValue(self, obj):
if not bool(obj):
Expand Down Expand Up @@ -1118,19 +1075,6 @@ def fromScriptCode(self, line):
else:
return ParameterString(name, descName, multiline=True, optional=isOptional)

def evaluate(self, alg):
if isinstance(self.value, str) 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()


class ParameterExpression(Parameter):

Expand Down
7 changes: 5 additions & 2 deletions python/plugins/processing/gui/NumberInputPanel.py
Expand Up @@ -39,6 +39,7 @@
from processing.core.parameters import ParameterNumber, ParameterVector, ParameterRaster
from processing.core.outputs import OutputNumber, OutputVector, OutputRaster
from processing.modeler.ModelerAlgorithm import ValueFromInput, ValueFromOutput, CompoundValue
from processing.tools.dataobjects import createExpressionContext

pluginPath = os.path.split(os.path.dirname(__file__))[0]
NUMBER_WIDGET, NUMBER_BASE = uic.loadUiType(
Expand All @@ -48,6 +49,7 @@


class ModellerNumberInputPanel(BASE, WIDGET):

"""
Number input panel for use inside the modeller - this input panel
is based off the base input panel and includes a text based line input
Expand All @@ -70,7 +72,7 @@ def __init__(self, param, modelParametersDialog):
self.leText.textChanged.connect(lambda: self.hasChanged.emit())

def showExpressionsBuilder(self):
context = self.param.expressionContext()
context = createExpressionContext()
dlg = QgsExpressionBuilderDialog(None, str(self.leText.text()), self, 'generic', context)

context.popScope()
Expand Down Expand Up @@ -138,6 +140,7 @@ def setValue(self, value):


class NumberInputPanel(NUMBER_BASE, NUMBER_WIDGET):

"""
Number input panel for use outside the modeller - this input panel
contains a user friendly spin box for entering values. It also
Expand Down Expand Up @@ -195,7 +198,7 @@ def __init__(self, param):
self.spnValue.valueChanged.connect(lambda: self.hasChanged.emit())

def showExpressionsBuilder(self):
context = self.param.expressionContext()
context = createExpressionContext()
dlg = QgsExpressionBuilderDialog(None, str(self.spnValue.value()), self, 'generic', context)

dlg.setWindowTitle(self.tr('Expression based input'))
Expand Down
2 changes: 1 addition & 1 deletion python/plugins/processing/gui/wrappers.py
Expand Up @@ -230,7 +230,7 @@ def wrapWithExpressionButton(self, basewidget):
return widget

def showExpressionsBuilder(self):
context = self.param.expressionContext()
context = dataobjects.createExpressionContext()
value = self.value()
if not isinstance(value, str):
value = ''
Expand Down
25 changes: 24 additions & 1 deletion python/plugins/processing/tools/dataobjects.py
Expand Up @@ -40,9 +40,13 @@
QgsSettings,
QgsProcessingUtils,
QgsProcessingContext,
QgsFeatureRequest)
QgsFeatureRequest,
QgsExpressionContext,
QgsExpressionContextUtils,
QgsExpressionContextScope)
from qgis.gui import QgsSublayersDialog
from qgis.PyQt.QtCore import QCoreApplication
from qgis.utils import iface

from processing.core.ProcessingConfig import ProcessingConfig
from processing.algs.gdal.GdalUtils import GdalUtils
Expand Down Expand Up @@ -91,6 +95,25 @@ def raise_error(f):
return context


def createExpressionContext():
context = QgsExpressionContext()
context.appendScope(QgsExpressionContextUtils.globalScope())
context.appendScope(QgsExpressionContextUtils.projectScope(QgsProject.instance()))

if iface.mapCanvas():
context.appendScope(QgsExpressionContextUtils.mapSettingsScope(iface.mapCanvas().mapSettings()))

processingScope = QgsExpressionContextScope()

extent = iface.mapCanvas().fullExtent()
processingScope.setVariable('fullextent_minx', extent.xMinimum())
processingScope.setVariable('fullextent_miny', extent.yMinimum())
processingScope.setVariable('fullextent_maxx', extent.xMaximum())
processingScope.setVariable('fullextent_maxy', extent.yMaximum())
context.appendScope(processingScope)
return context


def getSupportedOutputRasterLayerExtensions():
allexts = []
for exts in list(GdalUtils.getSupportedRasters().values()):
Expand Down

0 comments on commit 28f7a8b

Please sign in to comment.