<div dir="ltr"><div>Hi,</div><div><br></div><div>  <span class="gmail-HwtZe" lang="en"><span class="gmail-jCAhz gmail-ChMk0b"><span class="gmail-ryNqvb">I'm probably not the right user to answer, because I don't master the processing framework, but I get the impression that the problem is in its multithreaded nature.<br>  </span></span></span><span class="gmail-HwtZe" lang="en"><span class="gmail-jCAhz gmail-ChMk0b"><span class="gmail-ryNqvb">I think it's likely that you'll access result['OUTPUT'] before it is returned. </span></span></span><span class="gmail-HwtZe" lang="en"><span class="gmail-jCAhz gmail-ChMk0b"><span class="gmail-ryNqvb">I'm also interested in this type of cases, so a response from a more experienced user would be welcome.<br><br>  </span></span></span><span class="gmail-HwtZe" lang="en"><span class="gmail-jCAhz gmail-ChMk0b"><span class="gmail-ryNqvb">In the meantime, you can try something like:<br></span></span></span></div><div><span style="font-family:monospace"><br></span></div><div><span style="font-family:monospace">import threading</span></div><div><span style="font-family:monospace"><br></span></div><div><span style="font-family:monospace">lock = threading.Lock()</span></div><div><span style="font-family:monospace">result = {}<br></span></div><div><span style="font-family:monospace"><br></span></div><div><span style="font-family:monospace">with lock:</span></div><div><span style="font-family:monospace">  try:<br></span></div><div><span class="gmail-HwtZe" lang="en" style="font-family:monospace"><span class="gmail-jCAhz gmail-ChMk0b"><span class="gmail-ryNqvb"></span></span></span></div><div><span style="font-family:monospace">    result = processing.run("qgis:shortestpathpointtolayer",
parameters, context=context, feedback=feedback, is_child_algorithm=True)</span></div><div><span style="font-family:monospace">  except Exception as e:</span></div><div><span style="font-family:monospace">    raise e  # Handle it properly                </span></div><div><span style="font-family:monospace"><br></span></div><div><span style="font-family:monospace">shortest_path = QgsProcessingContext.takeResultLayer(context, result['OUTPUT'])</span></div><div><br></div><div><br></div><div>Regards,</div><div>Gabriel</div><br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">El vie, 11 oct 2024 a la(s) 6:01 a.m., Morten Storm via QGIS-User (<a href="mailto:qgis-user@lists.osgeo.org">qgis-user@lists.osgeo.org</a>) escribió:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Hi all,<br>
<br>
I have written a processing script for QGIS 3.x, which itself calls a native<br>
processing function (qgis:shortestpathpointtolayer) in a for loop.<br>
<br>
---------<br>
from qgis.PyQt.QtCore import QCoreApplication<br>
from qgis.core import (QgsProcessing,<br>
                       QgsFeatureRequest,<br>
                       QgsExpression,<br>
                       QgsProcessingContext,<br>
                       QgsProcessingException,<br>
                       QgsProcessingAlgorithm,<br>
                       QgsProcessingParameterVectorLayer,<br>
                       QgsProcessingFeatureSourceDefinition)<br>
from qgis import processing<br>
<br>
<br>
class findDownstreamPathAlgorithm(QgsProcessingAlgorithm):<br>
    """<br>
    This is an algorithm that calculates downstream paths on<br>
    a simplified network.<br>
<br>
    """<br>
<br>
    INPUT_NETWORK = 'INPUT_NETWORK'<br>
    INPUT_VALVES = 'INPUT_VALVES'<br>
<br>
    def tr(self, string):<br>
        return QCoreApplication.translate('Processing', string)<br>
<br>
    def createInstance(self):<br>
        return findDownstreamPathAlgorithm()<br>
<br>
    def name(self):<br>
        return 'iterateclusters'<br>
<br>
    def displayName(self):<br>
        return <a href="http://self.tr" rel="noreferrer" target="_blank">self.tr</a>('Iterate clusters')<br>
<br>
    def group(self):<br>
        return <a href="http://self.tr" rel="noreferrer" target="_blank">self.tr</a>('Thvilum')<br>
<br>
    def groupId(self):<br>
        return 'lukkelister'<br>
<br>
    def shortHelpString(self):<br>
        return <a href="http://self.tr" rel="noreferrer" target="_blank">self.tr</a>("Iterate clusters in a simplified network")<br>
<br>
    def initAlgorithm(self, config=None):<br>
<br>
        self.addParameter(<br>
            QgsProcessingParameterVectorLayer(<br>
                self.INPUT_NETWORK,<br>
                <a href="http://self.tr" rel="noreferrer" target="_blank">self.tr</a>('Netværkslag'),<br>
                [QgsProcessing.SourceType.TypeVectorLine]<br>
            )<br>
        )<br>
<br>
        self.addParameter(<br>
            QgsProcessingParameterVectorLayer(<br>
                self.INPUT_VALVES,<br>
                <a href="http://self.tr" rel="noreferrer" target="_blank">self.tr</a>('Ventillag'),<br>
                [QgsProcessing.SourceType.TypeVectorPoint]<br>
            )<br>
        )<br>
<br>
    def processAlgorithm(self, parameters, context, feedback):<br>
<br>
        # Retrieve the feature sources<br>
        network = self.parameterAsVectorLayer(<br>
            parameters,<br>
            self.INPUT_NETWORK,<br>
            context<br>
        )<br>
<br>
        valves = self.parameterAsVectorLayer(<br>
            parameters,<br>
            self.INPUT_VALVES,<br>
            context<br>
        )<br>
<br>
        if network is None:<br>
            raise QgsProcessingException(self.invalidSourceError(parameters,<br>
self.INPUT_NETWORK))<br>
<br>
        if valves is None:<br>
            raise QgsProcessingException(self.invalidSourceError(parameters,<br>
self.INPUT_VALVES))<br>
<br>
        # Store inlets from valves layer in separate scractch layer<br>
        inlets =<br>
valves.materialize(QgsFeatureRequest(QgsExpression("situation =<br>
'IsInlet'")))<br>
<br>
        # Collect clusters to evaluate<br>
        clusterList = []<br>
        for feat in network.getFeatures():<br>
            clusterList.append(feat["cluster"])<br>
<br>
        # Remove duplicates and sort list<br>
        clusterList = sorted(set(clusterList))<br>
        if len(clusterList) > 0:<br>
            total = 100.0 / len(clusterList)<br>
        else:<br>
            total = 0<br>
<br>
        isCanceled = False<br>
        for current, cluster in enumerate(clusterList):<br>
            # Update the progress bar<br>
            feedback.setProgress(int(current * total))<br>
<br>
            valves.selectByExpression("cluster = {} and situation =<br>
'Flow'".format(cluster))<br>
            for feat in valves.selectedFeatures():<br>
                # Stop the algorithm if cancel button has been clicked<br>
                if feedback.isCanceled():<br>
                    isCanceled = True<br>
                    break<br>
<br>
                vertex_id = feat["vertexId"]<br>
                valve_geom = feat.geometry()<br>
                network.selectByExpression("cluster != {}".format(cluster))<br>
<br>
                parameters = {<br>
                    'DEFAULT_DIRECTION' : 2,<br>
                    'DEFAULT_SPEED' : 50,<br>
                    'DIRECTION_FIELD' : '',<br>
                    'END_POINTS' : inlets,<br>
                    'INPUT' : QgsProcessingFeatureSourceDefinition(<br>
<a href="http://network.id" rel="noreferrer" target="_blank">network.id</a>(), selectedFeaturesOnly=True),<br>
                    'OUTPUT' : 'TEMPORARY_OUTPUT',<br>
                    #'OUTPUT_NON_ROUTABLE' : 'TEMPORARY_OUTPUT',<br>
                    'SPEED_FIELD' : '',<br>
                    'START_POINT' : valve_geom,<br>
                    'STRATEGY' : 0,<br>
                    'TOLERANCE' : 0,<br>
                    'VALUE_BACKWARD' : '',<br>
                    'VALUE_BOTH' : '',<br>
                    'VALUE_FORWARD' : ''<br>
                    }<br>
<br>
                result = processing.run("qgis:shortestpathpointtolayer",<br>
parameters, context=context, feedback=feedback, is_child_algorithm=True)<br>
                shortest_path =<br>
QgsProcessingContext.takeResultLayer(context, result['OUTPUT'])<br>
<br>
                # Do something with the path<br>
<br>
                del shortest_path<br>
<br>
            if isCanceled:<br>
                break<br>
<br>
<br>
        return {self.INPUT_NETWORK: network}<br>
---------<br>
<br>
When running this script on QGIS 3.28.4 it runs a couple of iterations and<br>
then raises an exception (access violation) with the following description:<br>
<br>
**Python Stack Trace**<br>
```<br>
Windows fatal exception: access violation<br>
<br>
Thread 0x00005d8c (most recent call first):<br>
  File<br>
"C:\PROGRA~1/QGIS32~2.4/apps/qgis-ltr/./python/plugins\processing\gui\Algori<br>
thmExecutor.py", line 72 in execute<br>
    results, ok = alg.run(parameters, context, feedback, {}, False)<br>
  File<br>
"C:\PROGRA~1/QGIS32~2.4/apps/qgis-ltr/./python/plugins\processing\core\Proce<br>
ssing.py", line 187 in runAlgorithm<br>
    ret, results = execute(alg, parameters, context, feedback,<br>
catch_exceptions=False)<br>
  File<br>
"C:\PROGRA~1/QGIS32~2.4/apps/qgis-ltr/./python/plugins\processing\tools\gene<br>
ral.py", line 116 in run<br>
    return Processing.runAlgorithm(algOrName, parameters,<br>
onFinish=post_process, feedback=feedback, context=context)<br>
  File<br>
"C:\Users\morte\AppData\Roaming\QGIS\QGIS3\profiles\default\processing\scrip<br>
ts\iterateClusters.py", line 156 in processAlgorithm<br>
    result = processing.run("qgis:shortestpathpointtolayer", parameters,<br>
context=context, feedback=feedback, is_child_algorithm=True)<br>
<br>
Current thread 0x000075e0 (most recent call first):<br>
  File<br>
"C:\PROGRA~1/QGIS32~2.4/apps/qgis-ltr/./python/plugins\processing\Processing<br>
Plugin.py", line 394 in executeAlgorithm<br>
    dlg.exec_()<br>
  File<br>
"C:\PROGRA~1/QGIS32~2.4/apps/qgis-ltr/./python/plugins\processing\gui\Proces<br>
singToolbox.py", line 234 in executeAlgorithm<br>
    self.executeWithGui.emit(<a href="http://alg.id" rel="noreferrer" target="_blank">alg.id</a>(), self, self.in_place_mode, False)<br>
```<br>
<br>
On QGIS 3.38.3 the process also runs for a couple of iteration and then just<br>
freezes the whole application.<br>
<br>
Running a simple (=non processing) version of this script from the Python<br>
console works beautifully on both QGIS versions!<br>
<br>
What am I missing in my processing script?<br>
<br>
<br>
<br>
Best regards,<br>
Morten<br>
<br>
--<br>
Morten Storm<br>
Styrke 10 ApS<br>
<br>
House of Innovation | Jernbanegade 27 | 6000 Kolding | Denmark<br>
<br>
www: <a href="https://styrke10.dk" rel="noreferrer" target="_blank">https://styrke10.dk</a><br>
mobile: +45 51 51 09 29<br>
<br>
<br>
_______________________________________________<br>
QGIS-User mailing list<br>
<a href="mailto:QGIS-User@lists.osgeo.org" target="_blank">QGIS-User@lists.osgeo.org</a><br>
List info: <a href="https://lists.osgeo.org/mailman/listinfo/qgis-user" rel="noreferrer" target="_blank">https://lists.osgeo.org/mailman/listinfo/qgis-user</a><br>
Unsubscribe: <a href="https://lists.osgeo.org/mailman/listinfo/qgis-user" rel="noreferrer" target="_blank">https://lists.osgeo.org/mailman/listinfo/qgis-user</a><br>
</blockquote></div>