Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[processing] Fix use of data defined parameter values when editing
features in place

Fixes #43758
  • Loading branch information
nyalldawson committed Jul 21, 2021
1 parent 7978634 commit 4363982
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 5 deletions.
8 changes: 8 additions & 0 deletions python/plugins/processing/gui/AlgorithmExecutor.py
Expand Up @@ -108,6 +108,11 @@ def execute_in_place_run(alg, parameters, context=None, feedback=None, raise_exc

active_layer = parameters[in_place_input_parameter_name]

# prepare expression context for feature iteration
alg_context = context.expressionContext()
alg_context.appendScope(active_layer.createExpressionContextScope())
context.setExpressionContext(alg_context)

# Run some checks and prepare the layer for in-place execution by:
# - getting the active layer and checking that it is a vector
# - making the layer editable if it was not already
Expand Down Expand Up @@ -187,6 +192,9 @@ def execute_in_place_run(alg, parameters, context=None, feedback=None, raise_exc
# need a deep copy, because python processFeature implementations may return
# a shallow copy from processFeature
input_feature = QgsFeature(f)

context.expressionContext().setFeature(input_feature)

new_features = alg.processFeature(input_feature, context, feedback)
new_features = QgsVectorLayerUtils.makeFeaturesCompatible(new_features, active_layer)

Expand Down
48 changes: 43 additions & 5 deletions tests/src/python/test_qgsprocessinginplace.py
Expand Up @@ -29,7 +29,8 @@
QgsProject,
QgsProcessingException,
QgsVectorLayer,
QgsFeatureSink
QgsFeatureSink,
QgsProperty
)
from processing.core.Processing import Processing
from processing.core.ProcessingConfig import ProcessingConfig
Expand Down Expand Up @@ -492,7 +493,7 @@ def test_make_features_compatible_geometry(self):
self.assertEqual(len(new_features), 1)
self.assertEqual(new_features[0].geometry().asWkt(), '')

def _alg_tester(self, alg_name, input_layer, parameters, invalid_geometry_policy=QgsFeatureRequest.GeometryNoCheck):
def _alg_tester(self, alg_name, input_layer, parameters, invalid_geometry_policy=QgsFeatureRequest.GeometryNoCheck, retain_selection=False):

alg = self.registry.createAlgorithmById(alg_name)

Expand All @@ -501,9 +502,11 @@ def _alg_tester(self, alg_name, input_layer, parameters, invalid_geometry_policy
parameters['OUTPUT'] = 'memory:'

old_features = [f for f in input_layer.getFeatures()]
input_layer.selectByIds([old_features[0].id()])
# Check selected
self.assertEqual(input_layer.selectedFeatureIds(), [old_features[0].id()], alg_name)

if not retain_selection:
input_layer.selectByIds([old_features[0].id()])
# Check selected
self.assertEqual(input_layer.selectedFeatureIds(), [old_features[0].id()], alg_name)

context = QgsProcessingContext()
context.setInvalidGeometryCheck(invalid_geometry_policy)
Expand Down Expand Up @@ -934,6 +937,41 @@ def test_regenerate_fid(self):
res = QgsVectorLayerUtils.makeFeatureCompatible(f, gpkg_layer, QgsFeatureSink.RegeneratePrimaryKey)
self.assertEqual([ff['fid'] for ff in res], [None])

def test_datadefinedvalue(self):
"""Check that data defined parameters work correctly"""

polygon_layer = self._make_layer('Polygon')
f1 = QgsFeature(polygon_layer.fields())
f1.setAttributes([1])
f1.setGeometry(QgsGeometry.fromWkt('POLYGON((1.2 1.2, 1.2 2.2, 2.2 2.2, 2.2 1.2, 1.2 1.2))'))
f2 = QgsFeature(polygon_layer.fields())
f2.setAttributes([2])
f2.setGeometry(QgsGeometry.fromWkt('POLYGON((1.1 1.1, 1.1 2.1, 2.1 2.1, 2.1 1.1, 1.1 1.1))'))
self.assertTrue(f2.isValid())
self.assertTrue(polygon_layer.startEditing())
self.assertTrue(polygon_layer.addFeatures([f1, f2]))
self.assertEqual(polygon_layer.featureCount(), 2)
polygon_layer.commitChanges()
self.assertEqual(polygon_layer.featureCount(), 2)
QgsProject.instance().addMapLayers([polygon_layer])

polygon_layer.selectAll()
self.assertEqual(polygon_layer.selectedFeatureCount(), 2)

old_features, new_features = self._alg_tester(
'native:densifygeometries',
polygon_layer,
{
'VERTICES': QgsProperty.fromField('int_f'),
}, retain_selection=True
)

geometries = [f.geometry() for f in new_features]
self.assertEqual(geometries[0].asWkt(2), 'Polygon ((1.2 1.2, 1.2 1.7, 1.2 2.2, 1.7 2.2, 2.2 2.2, 2.2 1.7, 2.2 1.2, 1.7 1.2, 1.2 1.2))')
self.assertEqual(geometries[1].asWkt(2), 'Polygon ((1.1 1.1, 1.1 1.43, 1.1 1.77, 1.1 2.1, 1.43 2.1, 1.77 2.1, 2.1 2.1, 2.1 1.77, 2.1 1.43, 2.1 1.1, 1.77 1.1, 1.43 1.1, 1.1 1.1))')
# Check selected
self.assertCountEqual(polygon_layer.selectedFeatureIds(), [1, 2])


if __name__ == '__main__':
unittest.main()

0 comments on commit 4363982

Please sign in to comment.