2

I would like to create a QgsVectorLayer using memory in a python script that will run in a processing model. Using the doc provided here https://docs.qgis.org/3.28/en/docs/user_manual/processing/scripts.html I created the following script. However, the output layer is not loaded in QGIS and not even saved in a file.

from qgis import processing
from qgis.processing import alg
from qgis.core import *
from qgis.PyQt.QtCore import QVariant

@alg(name='test', label="test", group='examplescripts', group_label='Example scripts')
@alg.input(type=alg.VECTOR_LAYER_DEST, name='OUTPUT',
           label='output')
def test(instance, parameters, context, feedback, inputs):
    """
    Description of the algorithm.
    (If there is no comment here, you will get an error)
    """

    vl = QgsVectorLayer("Point", "test", "memory")
    pr = vl.dataProvider()
    pr.addAttributes([QgsField("name", QVariant.String),
                      QgsField("age",  QVariant.Int),
                      QgsField("size", QVariant.Double)])
    vl.updateFields() 

    f = QgsFeature()
    f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10,10)))
    f.setAttributes(["Ada L.", 2, 0.3])
    pr.addFeature(f)
    vl.updateExtents() 

    return {'OUTPUT': vl}

Tried other return options, but no success

return {'OUTPUT': vl.id()}
return vl

Checking the docs there is QgsFeatureSink class, like in this code https://gist.github.com/ghtmtt/cd6ee99f69ce87298f9eb3466129306f. However, I'm not sure how to reach to this object using the function parameters.

2 Answers 2

0

Your variable vl is a layer in memory. You haven't actually saved it to the output directory yet - return {'OUTPUT': vl} is ultimately a console return, something completely separate from your pre-defined OUTPUT variable.

One option, and likely the most widely accepted, is to use QgsVectorFileWriter like in this question/reply.
Another would be, if you use any processing.run() algorithms; they tend to have the actual saving of the file implemented meaning you can pass the file output path on to those.
I have personally never worked with QgsFeatureSink before. I know it should have some of the functionality you are looking for, but someone else would have to explain how that works exactly.

0

I found an easy solution using a SINK as the layer output parameter.
The sink behaves somewhat as a vector layer and you just add features to it:

from qgis import processing
from qgis.processing import alg
from qgis.core import *
from qgis.PyQt.QtCore import QVariant

@alg(name='test', label="test", group='examplescripts', group_label='Example scripts')
@alg.input(type=alg.SINK, name="OUTPUT", label="output")
def test(instance, parameters, context, feedback, inputs):
    
    fields = QgsFields()
    fields.append(QgsField("name", QVariant.String))
    fields.append(QgsField("age",  QVariant.Int))
    fields.append(QgsField("size", QVariant.Double))
    
    #here is the sink, from the parameters, 
    sink, outputId = instance.parameterAsSink(parameters, 
                                              'OUTPUT', 
                                               context, 
                                               fields, 
                                               QgsWkbTypes.Point)#,
                                               #inputLayer.sourceCrs())
    #in the line above, you need one last parameter which is the crs
    #if not passed, the result layer will not have a coordinate system

    #create features
    f = QgsFeature()
    f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10,10)))
    f.setAttributes(["Ada L.", 2, 0.3])

    #add feature(s) to the sink
    sink.addFeature(f)

    return {'OUTPUT': outputId} #return the sink id

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.