Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[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)
  • Loading branch information
nyalldawson committed Feb 1, 2019
1 parent 3b814ea commit f988f6f
Showing 1 changed file with 21 additions and 4 deletions.
25 changes: 21 additions & 4 deletions python/plugins/processing/tools/general.py
Expand Up @@ -89,11 +89,28 @@ def algorithmHelp(id):
print('Algorithm "{}" not found.'.format(id))


def run(algOrName, parameters, onFinish=None, feedback=None, context=None):
"""Executes given algorithm and returns its outputs as dictionary
object.
def run(algOrName, parameters, onFinish=None, feedback=None, context=None, is_child_algorithm=False):
"""
return Processing.runAlgorithm(algOrName, parameters, onFinish, feedback, context)
Executes given algorithm and returns its outputs as dictionary object.
:param algOrName: Either an instance of an algorithm, or an algorithm's ID
:param parameters: Algorithm parameters dictionary
:param onFinish: optional function to run after the algorithm has completed
:param feedback: Processing feedback object
:param context: Processing context object
:param is_child_algorithm: Set to True if this algorithm is being run as part of a larger algorithm,
i.e. it is a sub-part of an algorithm which calls other Processing algorithms.
"""
if onFinish or not is_child_algorithm:
return Processing.runAlgorithm(algOrName, parameters, onFinish, feedback, context)
else:
# for child algorithms, we disable to default post-processing step where layer ownership
# is transferred from the context to the caller. In this case, we NEED the ownership to remain
# with the context, so that further steps in the algorithm have guaranteed access to the layer.
def post_process(_alg, _context, _feedback):
return

return Processing.runAlgorithm(algOrName, parameters, onFinish=post_process, feedback=feedback, context=context)


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

0 comments on commit f988f6f

Please sign in to comment.