6

Using examples from other posts and the PyQGIS documentation, I have not been able to reproduce adding fields to a layer created by a processing tool. I've added the entire code so anyone can try to reproduce what I have. I have listed the fields after adding the new fields and it shows that it added them, but does not add the QVariant.type, which in turn makes the field not show up after the script has run. Any ideas?

import html, sys
import os, math
from qgis.PyQt.QtCore import QCoreApplication, QVariant
from qgis.core import (QgsProcessing,
                       QgsFeatureSink,
                       QgsProcessingException,
                       QgsProcessingAlgorithm,
                       QgsProcessingParameterFeatureSource,
                       QgsProcessingParameterFile,
                       QgsProcessingParameterFeatureSink,
                       QgsProcessingParameterFolderDestination,
                       QgsProcessingUtils)
from qgis import processing
from qgis.core import (QgsVectorFileWriter,
                       QgsVectorLayer,
                       QgsRasterLayer,
                       QgsDistanceArea,
                       QgsUnitTypes,
                       QgsFeature,
                       QgsField,
                       QgsGeometry,
                       QgsPoint,
                       QgsPointXY,
                       QgsRaster,
                       QgsField,
                       QgsProject,
                       QgsExpression,
                       QgsExpressionContext,
                       QgsExpressionContextScope,
                       QgsCoordinateTransform,
                       QgsCoordinateReferenceSystem,
                       QgsVectorDataProvider)
import numpy as np
import pandas as pd

class Dissolve_Trial(QgsProcessingAlgorithm):
        '''
        '''
    INPUT0 = 'INPUT0'
    INPUT1 = 'INPUT1'
    INPUT2 = 'INPUT2'
    OUTPUT0 = 'OUTPUT0'
    OUTPUT1 = 'OUTPUT1'


    def tr(self, string):
        return QCoreApplication.translate('Processing', string)
    def createInstance(self):
        return Dissolve_Trial()
    def name(self):
        '''
        '''
        return 'dissolve_trial'
    def displayName(self):
        '''
        '''
        return self.tr('dissolve_trial')
    def group(self):
        '''
        '''
        return self.tr('Trial_Scripts')
    def groupId(self):
        '''
        '''
        return 'Trial_Scripts'
    def shortHelpString(self):
        '''
        '''
        return self.tr("xxxx")
    def initAlgorithm(self, config=None):
        '''
        '''

        self.addParameter(
            QgsProcessingParameterFeatureSource(
                self.INPUT0,
                self.tr('Input Layer'),
                [QgsProcessing.TypeVectorAnyGeometry]
            )
        )


        self.addParameter(QgsProcessingParameterFeatureSink(
                    self.OUTPUT0, "HO_Dissolve"))

    def processAlgorithm(self, parameters, context, feedback):
        '''
        '''
        source = self.parameterAsSource(
            parameters,
            self.INPUT0,
            context
        )
        if source is None:
            raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT0))

        (sink, dest_id) = self.parameterAsSink(
            parameters,
            self.OUTPUT0,
            context,
            source.fields(),
            source.wkbType(),
            source.sourceCrs()
        )

        def field_dic(fields, feature, fieldname):
            q = {}
            q['name'] = fieldname
            q['id'] = fields.indexFromName(fieldname)
            q['val'] = feature.attributes()[fields.indexFromName(fieldname)]
            return q

        d_layer = processing.run('qgis:dissolve', {'INPUT': parameters['INPUT0'],
                                                'FIELD': ['Yeah'],
                                                'OUTPUT':parameters['OUTPUT0']})
        n_lay = d_layer['OUTPUT']

        caps = n_lay.dataProvider().capabilities()
        if caps and QgsVectorDataProvider.AddAttributes:
            n_lay.dataProvider().addAttributes([QgsField('No', QVariant.String),
                                                QgsField('Maybe', QVariant.String)])
            n_lay.updateFields()
        else:
            feedback.pushInfo('Couldnt add fields')

        for field in n_lay.fields():
            feedback.pushInfo(str(field))


        for current, feature in enumerate(n_lay.getFeatures()):
            sink.addFeature(feature, QgsFeatureSink.FastInsert)

        return {self.OUTPUT0: dest_id}

1 Answer 1

4

You cannot add the new fields to the new layer created by another processing tool that way, because you copy source layer fields (assume it has 1 field X) to sink. And then, when you try to add features in output layer (n_lay which has X, No, Maybefields) to sink, only the fields (X) which are in both layers (source and n_lay) is added (only X).

Solution: Cut (sink, dest_id) = self.parameterAsSink(....) line and add just above for current, feature in enumerate(n_lay.getFeatures()): as the following:

(sink, dest_id) = self.parameterAsSink(
    parameters,
    self.OUTPUT0,
    context,
    n_lay.fields(), # Change source to n_lay
    n_lay.wkbType(),
    n_lay.sourceCrs()
)

for current, feature in enumerate(n_lay.getFeatures()):
    sink.addFeature(feature, QgsFeatureSink.FastInsert)
1
  • That is beautiful. Thank you! Commented Jun 9, 2020 at 13:57

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.