Skip to content

Commit

Permalink
Merge pull request #3470 from arnaud-morvan/refactor_fields_context_g…
Browse files Browse the repository at this point in the history
…enerator

[Processing] Fix processing refactor fields algorithm using expression context generators
  • Loading branch information
volaya authored Nov 8, 2016
2 parents 7c4e66b + 78236c0 commit 72fddb8
Show file tree
Hide file tree
Showing 6 changed files with 29 additions and 29 deletions.
2 changes: 1 addition & 1 deletion python/core/composer/qgscomposerobject.sip
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/** \ingroup core
* A base class for objects which belong to a map composition.
*/
class QgsComposerObject : QObject
class QgsComposerObject : QObject, QgsExpressionContextGenerator
{
%TypeHeaderCode
#include <qgscomposerobject.h>
Expand Down
2 changes: 1 addition & 1 deletion python/core/composer/qgscomposition.sip
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* them in a list in ascending z-Order. This list can be changed to lower/raise items one position
* or to bring them to front/back.
* */
class QgsComposition : QGraphicsScene
class QgsComposition : QGraphicsScene, QgsExpressionContextGenerator
{
%TypeHeaderCode
#include <qgscomposition.h>
Expand Down
2 changes: 1 addition & 1 deletion python/core/qgsproject.sip
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
properties.

*/
class QgsProject : QObject
class QgsProject : QObject, QgsExpressionContextGenerator
{
%TypeHeaderCode
#include <qgsproject.h>
Expand Down
2 changes: 1 addition & 1 deletion python/core/qgsvectorlayer.sip
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ struct QgsVectorJoinInfo
*/


class QgsVectorLayer : QgsMapLayer
class QgsVectorLayer : QgsMapLayer, QgsExpressionContextGenerator
{
%TypeHeaderCode
#include "qgsvectorlayer.h"
Expand Down
30 changes: 10 additions & 20 deletions python/plugins/processing/algs/qgis/FieldsMapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,7 @@ def processAlgorithm(self, progress):
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))
exp_context = layer.createExpressionContext()

for field_def in mapping:
fields.append(QgsField(name=field_def['name'],
Expand All @@ -93,27 +90,20 @@ def processAlgorithm(self, progress):
expression.setGeomCalculator(da)
expression.setDistanceUnits(QgsProject.instance().distanceUnits())
expression.setAreaUnits(QgsProject.instance().areaUnits())

expression.prepare(exp_context)
if expression.hasParserError():
raise GeoAlgorithmExecutionException(
self.tr(u'Parser error in expression "{}": {}')
.format(str(field_def['expression']),
str(expression.parserErrorString())))
expression.prepare(exp_context)
if expression.hasEvalError():
raise GeoAlgorithmExecutionException(
self.tr(u'Evaluation error in expression "{}": {}')
.format(str(field_def['expression']),
str(expression.evalErrorString())))
.format(unicode(expression.expression()),
unicode(expression.parserErrorString())))
expressions.append(expression)

writer = output.getVectorWriter(fields,
layer.wkbType(),
layer.crs())

# Create output vector layer with new attributes
error = ''
calculationSuccess = True
error_exp = None
inFeat = QgsFeature()
outFeat = QgsFeature()
features = vector.features(layer)
Expand All @@ -132,8 +122,7 @@ def processAlgorithm(self, progress):
exp_context.lastScope().setVariable("row_number", rownum)
value = expression.evaluate(exp_context)
if expression.hasEvalError():
calculationSuccess = False
error = expression.evalErrorString()
error_exp = expression
break

attrs.append(value)
Expand All @@ -145,7 +134,8 @@ def processAlgorithm(self, progress):

del writer

if not calculationSuccess:
if error_exp is not None:
raise GeoAlgorithmExecutionException(
self.tr('An error occurred while evaluating the calculation'
' string:\n') + error)
self.tr(u'Evaluation error in expression "{}": {}')
.format(unicode(error_exp.expression()),
unicode(error_exp.parserErrorString())))
20 changes: 15 additions & 5 deletions python/plugins/processing/algs/qgis/ui/FieldsMappingPanel.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
from qgis.PyQt.QtWidgets import QComboBox, QHeaderView, QLineEdit, QSpacerItem, QMessageBox, QSpinBox, QStyledItemDelegate
from qgis.PyQt.QtCore import QItemSelectionModel, QAbstractTableModel, QModelIndex, QVariant, Qt, pyqtSlot

from qgis.core import QgsExpression, QgsExpressionContextUtils, QgsApplication, QgsFeature
from qgis.core import QgsExpression, QgsProject, QgsApplication
from qgis.gui import QgsFieldExpressionWidget

from processing.gui.wrappers import WidgetWrapper, DIALOG_STANDARD, DIALOG_MODELER
Expand Down Expand Up @@ -87,21 +87,30 @@ def testAllExpressions(self):
def testExpression(self, row):
self._errors[row] = None
field = self._mapping[row]
exp_context = self.contextGenerator().createExpressionContext()

expression = QgsExpression(field['expression'])
expression.prepare(exp_context)
if expression.hasParserError():
self._errors[row] = expression.parserErrorString()
return

# test evaluation on the first feature
if self._layer is None:
return
context = QgsExpressionContextUtils.createFeatureBasedContext(QgsFeature(), self._layer.fields())
for feature in self._layer.getFeatures():
context.setFeature(feature)
expression.evaluate(context)
exp_context.setFeature(feature)
exp_context.lastScope().setVariable("row_number", 1)
expression.evaluate(exp_context)
if expression.hasEvalError():
self._errors[row] = expression.evalErrorString()
return
break

def contextGenerator(self):
if self._layer:
return self._layer
return QgsProject.instance()

def layer(self):
return self._layer

Expand Down Expand Up @@ -254,6 +263,7 @@ def createEditor(self, parent, option, index):
elif fieldType == QgsExpression:
editor = QgsFieldExpressionWidget(parent)
editor.setLayer(index.model().layer())
editor.registerExpressionContextGenerator(index.model().contextGenerator())
editor.fieldChanged.connect(self.on_expression_fieldChange)

else:
Expand Down

0 comments on commit 72fddb8

Please sign in to comment.