Skip to content
Permalink
Browse files
[processing] Fixes for field calculator and field mapper
- respect project distance, area and ellipsoid settings
- ensure expression variables are correctly evaluated
  • Loading branch information
nyalldawson committed Feb 28, 2016
1 parent b223593 commit d32c41a60ed28abe3d8a93971810ee4f9735e055
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 8 deletions.
@@ -26,7 +26,7 @@
__revision__ = '$Format:%H$'

from PyQt4.QtCore import QVariant
from qgis.core import QgsExpression, QgsFeature, QgsField, QgsDistanceArea, QgsProject, GEO_NONE
from qgis.core import QgsExpression, QgsExpressionContext, QgsExpressionContextUtils, QgsFeature, QgsField, QgsDistanceArea, QgsProject, GEO_NONE
from qgis.utils import iface
from processing.core.GeoAlgorithm import GeoAlgorithm
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
@@ -111,8 +111,15 @@ def processAlgorithm(self, progress):
da.setEllipsoid(QgsProject.instance().readEntry(
'Measure', '/Ellipsoid', GEO_NONE)[0])
exp.setGeomCalculator(da)
exp.setDistanceUnits(QgsProject.instance().distanceUnits())
exp.setAreaUnits(QgsProject.instance().areaUnits())

if not exp.prepare(layer.pendingFields()):
exp_context = QgsExpressionContext()
exp_context.appendScope(QgsExpressionContextUtils.globalScope())
exp_context.appendScope(QgsExpressionContextUtils.projectScope())
exp_context.appendScope(QgsExpressionContextUtils.layerScope(layer))

if not exp.prepare(exp_context):
raise GeoAlgorithmExecutionException(
self.tr('Evaluation error: %s' % exp.evalErrorString()))

@@ -129,8 +136,9 @@ def processAlgorithm(self, progress):
rownum = 1
for current, f in enumerate(features):
rownum = current + 1
exp.setCurrentRowNumber(rownum)
value = exp.evaluate(f)
exp_context.setFeature(f)
exp_context.lastScope().setVariable("row_number", rownum)
value = exp.evaluate(exp_context)
if exp.hasEvalError():
calculationSuccess = False
error = exp.evalErrorString()
@@ -26,7 +26,8 @@
__revision__ = '$Format:%H$'


from qgis.core import QgsField, QgsExpression, QgsFeature
from qgis.core import QgsField, QgsExpression, QgsExpressionContext, QgsExpressionContextUtils, QgsDistanceArea, QgsProject, QgsFeature, GEO_NONE
from qgis.utils import iface
from processing.core.GeoAlgorithm import GeoAlgorithm
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
from processing.core.parameters import ParameterVector
@@ -68,19 +69,36 @@ def processAlgorithm(self, progress):
provider = layer.dataProvider()
fields = []
expressions = []

da = QgsDistanceArea()
da.setSourceCrs(layer.crs().srsid())
da.setEllipsoidalMode(
iface.mapCanvas().mapSettings().hasCrsTransformEnabled())
da.setEllipsoid(QgsProject.instance().readEntry(
'Measure', '/Ellipsoid', GEO_NONE)[0])

exp_context = QgsExpressionContext()
exp_context.appendScope(QgsExpressionContextUtils.globalScope())
exp_context.appendScope(QgsExpressionContextUtils.projectScope())
exp_context.appendScope(QgsExpressionContextUtils.layerScope(layer))

for field_def in mapping:
fields.append(QgsField(name=field_def['name'],
type=field_def['type'],
len=field_def['length'],
prec=field_def['precision']))

expression = QgsExpression(field_def['expression'])
expression.setGeomCalculator(da)
expression.setDistanceUnits(QgsProject.instance().distanceUnits())
expression.setAreaUnits(QgsProject.instance().areaUnits())

if expression.hasParserError():
raise GeoAlgorithmExecutionException(
self.tr(u'Parser error in expression "{}": {}')
.format(unicode(field_def['expression']),
unicode(expression.parserErrorString())))
expression.prepare(provider.fields())
expression.prepare(exp_context)
if expression.hasEvalError():
raise GeoAlgorithmExecutionException(
self.tr(u'Evaluation error in expression "{}": {}')
@@ -108,8 +126,9 @@ def processAlgorithm(self, progress):
for i in xrange(0, len(mapping)):
field_def = mapping[i]
expression = expressions[i]
expression.setCurrentRowNumber(rownum)
value = expression.evaluate(inFeat)
exp_context.setFeature(inFeat)
exp_context.lastScope().setVariable("row_number", rownum)
value = expression.evaluate(exp_context)
if expression.hasEvalError():
calculationSuccess = False
error = expression.evalErrorString()
@@ -31,6 +31,7 @@
from PyQt4 import uic
from PyQt4.QtCore import Qt, QSettings
from PyQt4.QtGui import QDialog, QFileDialog, QApplication, QCursor, QMessageBox
from qgis.core import QgsExpressionContext, QgsExpressionContextUtils
from qgis.gui import QgsEncodingFileDialog

from processing.core.ProcessingConfig import ProcessingConfig
@@ -95,6 +96,14 @@ def updateLayer(self):
self.builder.setLayer(self.layer)
self.builder.loadFieldNames()

exp_context = QgsExpressionContext()
exp_context.appendScope(QgsExpressionContextUtils.globalScope())
exp_context.appendScope(QgsExpressionContextUtils.projectScope())
exp_context.appendScope(QgsExpressionContextUtils.layerScope(self.layer))
exp_context.lastScope().setVariable("row_number", 1)
exp_context.setHighlightedVariables(["row_number"])
self.builder.setExpressionContext(exp_context)

self.populateFields()

def setupSpinboxes(self, index):

2 comments on commit d32c41a

@nyalldawson
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alexbruy what's the correct way to backport processing fixes to 2.14? just push it to the 2.14 branch?

@alexbruy
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, just puch them to the 2.14 branch and they will be included in the next point release

Please sign in to comment.