qgis / QGIS

QGIS is a free, open source, cross platform (lin/win/mac) geographical information system (GIS)
https://qgis.org
GNU General Public License v2.0
10.42k stars 2.98k forks source link

Calling setLegendSymbolItem in processing alg cause crash #58884

Open roya0045 opened 3 days ago

roya0045 commented 3 days ago

What is the bug or the crash?

When trying to update a symbol of a given layer from a Processing Script, calling the function setLegendSymbolItem on the renderer or a clone of the renderer. I always get a hard crash. When disabling this function from my processing function, everything runs fine.

Steps to reproduce the issue

Use the following script


from qgis.PyQt.QtCore import QCoreApplication
from qgis.PyQt.QtXml import QDomDocument
from qgis.core import (QgsProcessing,
                       QgsExpressionContext,QgsExpression,QgsColorUtils,QgsExpressionContextUtils,
                       QgsFeatureSink,
                       QgsProcessingException,
                       QgsProcessingAlgorithm,
                       QgsProcessingParameterVectorLayer,QgsProcessingParameterFileDestination,
                       QgsProcessingParameterExpression)
from qgis import processing

class SymbolUpdaterProcessingAlgorithm(QgsProcessingAlgorithm):

    INPUT = 'INPUT'
    COLOREXP = 'COLOREXP'
    STYLEF='STYLEF'

    def tr(self, string):
        return QCoreApplication.translate('Processing', string)

    def createInstance(self):
        return SymbolUpdaterProcessingAlgorithm()

    def displayName(self):
        return self.tr('Symbol Color Updated')

    def group(self):

        return self.tr('Symbology')

    def groupId(self):

        return 'symbology'

    def shortHelpString(self):

        return self.tr("Updates the main symbol color to the majority color")

    def initAlgorithm(self, config=None):

        self.addParameter(
            QgsProcessingParameterVectorLayer(
                self.INPUT,
                self.tr('Input layer'),
                [QgsProcessing.SourceType.TypeVectorAnyGeometry]
            )
        )

        self.addParameter(
            QgsProcessingParameterExpression(
                self.COLOREXP,
                self.tr('Color Expression'),
                parentLayerParameterName=self.INPUT,defaultValue='color_rgb( 120,120,120)'
            )
        )
        self.addParameter( QgsProcessingParameterFileDestination(self.STYLEF,self.tr('Updated style file(unused)')))

    def processAlgorithm(self, parameters, context, feedback):

        vlayer = self.parameterAsVectorLayer(
            parameters,
            self.INPUT,
            context)

        if vlayer is None:
            raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))

        colorExp = self.parameterAsExpression(parameters,self.COLOREXP,context)
        outputFile = self.parameterAsFileOutput(parameters, self.STYLEF, context)
        baseExp = 'majority({},filter:={})'

        currentRenderer = vlayer.renderer().clone()

        lnodes = currentRenderer.legendSymbolItems()
        expConxt = QgsExpressionContext( QgsExpressionContextUtils.globalProjectLayerScopes( vlayer ) )
        for lnode in lnodes:
            lkey = lnode.ruleKey() 
            nodesymb = lnode.symbol()
            keyStrExp = currentRenderer.legendKeyToExpression(lkey,None)[0]
            feedback.pushInfo(keyStrExp)
            keyExp = QgsExpression( baseExp.format(colorExp,keyStrExp ) )
            colorExpVal = keyExp.evaluate( expConxt )
            if colorExpVal is None:
                continue
            feedback.pushInfo(colorExpVal)
            qcolr = QgsColorUtils.colorFromString(colorExpVal)
            nodesymb.setColor( qcolr )
            feedback.pushInfo(lkey)
            currentRenderer.setLegendSymbolItem(lkey,nodesymb)

        vlayer.setRenderer(currentRenderer)
        vlayer.triggerRepaint() 
        return {self.STYLEF: outputFile}

Versions

Tested in Win 10 with 3.37 & 3.35, no recent change seem to affect that area of code.

Supported QGIS version

New profile

Additional context

No response

roya0045 commented 3 days ago

Ok I found the issue, this is caused by the delete call in the function.

The fix is to create a clone of the symbology.

Imo the fix would be to at least add the documentation to prevent this kind of error, it's not clear that the provided QgsSymbol should not be an existant symbol. The example of using clone() would be better as making this happen in python isn't clear.