0

I want to create a simple qgis processing algorithm, where input layer is copied, there are some basic operations done on attributes and the resulting layer is returned. However, I encounter following error:

The following layers were not correctly generated. • Selected_features_10143967_2a0f_4057_8aea_cb8c49a1766f You can check the 'Log Messages Panel' in QGIS main window to find more information about the execution of the algorithm.

The Log Messages Panel is empty. Here is the code:

from qgis import processing
from qgis.processing import alg
from qgis.core import QgsProject, QgsField, edit
from PyQt5.QtCore import QVariant
@alg(name='somename', label='somelabel',
 group='somegroup', group_label='somegroup')
# 'INPUT' is the recommended name for the main input parameter
@alg.input(type=alg.SOURCE, name='INPUT', label='in')
# 'OUTPUT' is the recommended name for the main output parameter
@alg.input(type=alg.VECTOR_LAYER_DEST, name='OUTPUT',
 label='out')
def somename(instance, parameters, context, feedback, inputs):
 """
 Does stuff
 """
 input = instance.parameterAsVectorLayer(parameters, 'INPUT', context)
 input.selectAll()
 output = processing.run("native:saveselectedfeatures", {'INPUT': input, 'OUTPUT': parameters['OUTPUT']},
 context=context,
 feedback=feedback)['OUTPUT']
 input.removeSelection()
 layer_provider = output.dataProvider()
 layer_provider.addAttributes([QgsField("somefield", QVariant.String, len=1)])
 output.updateFields()
 with edit(output):
 for feature in output.getFeatures():
 if not feature['someotherfield']:
 feature['somefield'] = '0'
 
 output.updateFeature(feature)
 return {'OUTPUT': output}

What am I doing wrong? What is the proper way to return the result after editing?

asked Dec 20, 2021 at 17:32

1 Answer 1

1

The error is not about how you are returning the results, but that problems in your code are preventing the output layer from being correctly generated. Your main problem is that your output variable holds a layer id string, not an actual layer.

I would suggest a slightly different approach. Rather than running Save Selected Features as a child algorithm to copy your input layer, use feature source and feature sink parameters, add a field to the sink then copy your input features to the sink setting the input geometry, input attributes and appending the new attribute value if the input feature satisfies the condition.

The following should work (tested in QGIS 3.20):

from qgis.processing import alg
from qgis.core import (QgsField,
 QgsFeatureSink,
 QgsFeature)
from PyQt5.QtCore import QVariant
@alg(name='somename', label='somelabel',
 group='somegroup', group_label='somegroup')
# 'INPUT' is the recommended name for the main input parameter
@alg.input(type=alg.SOURCE, name='INPUT', label='in')
# 'OUTPUT' is the recommended name for the main output parameter
@alg.input(type=alg.SINK, name='OUTPUT',
 label='out')
def somename(instance, parameters, context, feedback, inputs):
 """
 Does stuff
 """
 # Declare source from input parameter
 source = instance.parameterAsSource(parameters, 'INPUT', context)
 # Copy source fields
 flds = source.fields()
 # Add new field
 flds.append(QgsField("somefield", QVariant.String, len=1))
 # Create feature sink from output parameter with extra field (geom type & crs same as source)
 (sink, dest_id) = instance.parameterAsSink(parameters, 'OUTPUT', context,
 flds, source.wkbType(), source.sourceCrs())
 # Loop through source features
 for in_feat in source.getFeatures():
 # Create output feature
 out_feat = QgsFeature()
 # Set geometry from source
 out_feat.setGeometry(in_feat.geometry())
 # Copy source attributes
 atts = in_feat.attributes()
 # If input feature satisfies condition add new value to attributes
 # Are you checking for an empty string here?
 if not in_feat['someotherfield']:
 atts.append(0)
 # Set modified attributes to output feature
 out_feat.setAttributes(atts)
 # Add output feature to feature sink
 sink.addFeature(out_feat, QgsFeatureSink.FastInsert)
 
 # Return output layer id
 return {'OUTPUT': dest_id}
answered Dec 20, 2021 at 23:45
2
  • It's a pity that you can't edit resulting layer directly. Nevertheless, it works. BTW you can do out_feat.setFields(flds) to refer to attributes by names. Commented Jan 5, 2022 at 15:53
  • @Kubson, sorry I don't really know what you mean when you say "it's a pity you can't edit resulting layer directly". The approach in my answer is quite common in QGIS processing algorithms. If you really want to stick with your original approach you could probably get a QgsVectorLayer object like: layer = QgsProcessingUtils.mapLayerFromString(output, context). I didn't try it myself in this case because I honestly don't see the advantage of doing it that way. Commented Jan 5, 2022 at 23:00

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.