[GIS] Using parameterAsSink in QGIS processing script

pyqgisqgis-processing

Note I have edited this question to make it more direct and hopefully get a response.

I am attempting to write a series of processing algorithms to automate and extend a workflow in QGIS 3.4. I have been using the processing script template and following a number of examples including.

  1. pyqgis – post-processing of layer output of QgsProcessingAlgorithm
  2. Defining fields and adding features to output layer using QGIS
  3. Python processing script with clip in QGIS 3.2

I also reference the porting_processing.dox by nyalldawson and the workshop by NathanW.

My problem is ( I think) how to properly use parameterAsSink as described by nyalldawson. Unfortunately none of the listed resources, some of which are unanswered, quite answer my question. There seem to be many variations of how to output results from a processing script. I am sure I am missing something very simple but it has me beat. My best guess is I am not properly assigning the results the output sink.

I have tested the code and the file is generated correctly if I send the result to a file it works. What I can't do is get the memory layer to work – the same as if you are usign the inbuild processing scripts

The following code is a modification of the script template attempting something simple to get started. It runs and as above the result is valid – I just can't get it to the result to the QGIS interface. At present I am just implementing the existing processing difference algorithm but I will extend this when I can get it working properly.

# -*- coding: utf-8 -*-

from PyQt5.QtCore import QCoreApplication
from qgis.core import (QgsProcessing,
                       QgsFeatureSink,
                       QgsProcessingException,
                       QgsProcessingAlgorithm,
                       QgsProcessingParameterFeatureSource,
                       QgsProcessingParameterFeatureSink)
import processing

class ceaEz(QgsProcessingAlgorithm):
    INPUT = 'INPUT'
    OVERLAY= "OVERLAY"
    OUTPUT = 'OUTPUT'

    def tr(self, string):

        return QCoreApplication.translate('Processing', string)

    def createInstance(self):

        return type(self)()

    def name(self):

        return self.tr('ceaez')

    def displayName(self):

        return self.tr('CEA minus EZ')

    def group(self):

        return self.tr('Sample plan algorithms')

    def groupId(self):

        return 'sampleplanning'

    def shortHelpString(self):

        return self.tr("Example algorithm short description")

    def initAlgorithm(self, config=None):
        self.addParameter(
            QgsProcessingParameterFeatureSource(
                self.INPUT,
                self.tr('CEA'),
                [QgsProcessing.TypeVectorAnyGeometry]
            )
        )
        self.addParameter(
            QgsProcessingParameterFeatureSource(
                self.OVERLAY,
                self.tr('EZ'),
                [QgsProcessing.TypeVectorAnyGeometry]
            )
        )
        self.addParameter(
            QgsProcessingParameterFeatureSink(
                self.OUTPUT,
                self.tr('OUTPUT'),
                #QgsProcessing.TypeVectorAnyGeometry
            )
        )

    def processAlgorithm(self, parameters, context, feedback):
        diff = processing.runAndLoadResults("native:difference", {
                 'INPUT': parameters['INPUT'],
                 'OVERLAY': parameters['OVERLAY'],
                 'OUTPUT': 'memory:'
        }, context = context, feedback = feedback)['OUTPUT']

        return {self.OUTPUT: diff}

Can anyone show me how to get the correct output?

Best Answer

The output of the 'native:difference' algorithm is a vector layer. FeatureSink is used when you are creating features in your algorithm. To let the user specify the output which will be used in the algorithm, you should use QgsProcessingParameterVectorDestination() along with parameterAsOutputLayer()

def initAlgorithm(self, config=None):
    self.addParameter(
        QgsProcessingParameterFeatureSource(
            self.INPUT,
            self.tr('CEA'),
            [QgsProcessing.TypeVectorAnyGeometry]
        )
    )
    self.addParameter(
        QgsProcessingParameterFeatureSource(
            self.OVERLAY,
            self.tr('EZ'),
            [QgsProcessing.TypeVectorAnyGeometry]
        )
    )
    self.addParameter(
        QgsProcessingParameterVectorDestination(
            self.OUTPUT,
            self.tr('Output layer')
        )
    )

def processAlgorithm(self, parameters, context, feedback):
    output = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)

    diff = processing.runAndLoadResults("native:difference", {
             'INPUT': parameters['INPUT'],
             'OVERLAY': parameters['OVERLAY'],
             'OUTPUT': output
    }, context = context, feedback = feedback)['OUTPUT']

    return {self.OUTPUT: diff}