<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>