Skip to content

Commit f988f6f

Browse files
committed
[processing][needs-docs] Add friendlier API for running algorithms as sub-steps
of main algorithm Using code like: buffered_layer = processing.run(..., context, feedback)['OUTPUT'] ... return {'OUTPUT': buffered_layer} can cause issues if done as a sub-step of a larger processing algorithm. This is because ownership of the generated layer is transferred to the caller (Python) by processing.run. When the algorithm returns, Processing attempts to move ownership of the layer from the context to the caller, resulting in a crash. (This is by design, because processing.run has been optimised for the most common use case, which is one-off execution of algorithms as part of a script, not as part of another processing algorithm. Accordingly by design it returns layers and ownership to the caller, making things easier for callers as they do not then have to resolve the layer reference from the context object and handle ownership themselves) This commit adds a new "is_child_algorithm" argument to processing.run. For algorithms which are executed as sub-steps of a larger algorithm is_child_algorithm should be set to True to avoid any ownership issues with layers. E.g. buffered_layer = processing.run(..., context, feedback, is_child_algorithm=True)['OUTPUT'] ... return {'OUTPUT': buffered_layer} (cherry picked from commit 7f7c7a9)
1 parent 3b814ea commit f988f6f

File tree

1 file changed

+21
-4
lines changed

1 file changed

+21
-4
lines changed

python/plugins/processing/tools/general.py

+21-4
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,28 @@ def algorithmHelp(id):
8989
print('Algorithm "{}" not found.'.format(id))
9090

9191

92-
def run(algOrName, parameters, onFinish=None, feedback=None, context=None):
93-
"""Executes given algorithm and returns its outputs as dictionary
94-
object.
92+
def run(algOrName, parameters, onFinish=None, feedback=None, context=None, is_child_algorithm=False):
9593
"""
96-
return Processing.runAlgorithm(algOrName, parameters, onFinish, feedback, context)
94+
Executes given algorithm and returns its outputs as dictionary object.
95+
96+
:param algOrName: Either an instance of an algorithm, or an algorithm's ID
97+
:param parameters: Algorithm parameters dictionary
98+
:param onFinish: optional function to run after the algorithm has completed
99+
:param feedback: Processing feedback object
100+
:param context: Processing context object
101+
:param is_child_algorithm: Set to True if this algorithm is being run as part of a larger algorithm,
102+
i.e. it is a sub-part of an algorithm which calls other Processing algorithms.
103+
"""
104+
if onFinish or not is_child_algorithm:
105+
return Processing.runAlgorithm(algOrName, parameters, onFinish, feedback, context)
106+
else:
107+
# for child algorithms, we disable to default post-processing step where layer ownership
108+
# is transferred from the context to the caller. In this case, we NEED the ownership to remain
109+
# with the context, so that further steps in the algorithm have guaranteed access to the layer.
110+
def post_process(_alg, _context, _feedback):
111+
return
112+
113+
return Processing.runAlgorithm(algOrName, parameters, onFinish=post_process, feedback=feedback, context=context)
97114

98115

99116
def runAndLoadResults(algOrName, parameters, feedback=None, context=None):

0 commit comments

Comments
 (0)