In GP-tools written in C# (ArcObjects) we can listen for the Cancel-event and react on that. I wonder if there is anything similar in Python GP-tools applying arcpy. I googled that issue and the only thing I found was the Cancel-method on the Result-Object (so that you can ask the state of the result of a GP-tool, i.e. if it was canceled). I'm aware that you can cancel GP-tools running in the background in the Result Window, but this Cancel-event is catched by the system and therefore the developer or the GP-tool cannot react on that. Thank You in advance!

  • This is an interesting question. I have been trying to find a way in python to accomplish this. I have been trying to run a background arcpy task (join or what not) in another thread in a while loop with the condition being a global true/false and flipping the value a few seconds in. The only thing I have been able to do is freeze ArcMap. Do you think arcpy modules can handle being run in a separate thread than the main? It seems like most of the ones I have tried are blocking and don't allow anything until done. – Branco Mar 11 '15 at 12:36

This isn't an answer, but an elaboration on the question. I've published an asynchronous gp service using the code shown below. If the user cancels, the result object returned does indicate that. However, the loop runs for the full number of seconds. I would like to break out of the loop if user has canceled.

def execute(self, parameters, messages):
    secondstosleep  = int(parameters[0].valueAsText)
    output = parameters[1].valueAsText

    if secondstosleep < 0:
        messages.addErrorMessage("{0} : less than zero.".format(secondstosleep))
        raise arcpy.ExecuteError
    messages.addMessage("starting to sleep for {0} seconds".format(secondstosleep))
    slept = 0
    for t in xrange(0,secondstosleep):
        # would like to break if user has canceled
        # check for cancel here and break
        slept = slept + 1
    messages.addMessage("slept for {0} seconds".format(slept))

If you use arcmap 10.4 and up, you can set arcpy.env.autoCancelling = False to do the clean up work yourself. Example from official website.

import arcpy
arcpy.env.autoCancelling = False

def my_function(tables, output):
    temp_tables = []
        for table in tables:
            temp_tables.append(arcpy.CopyRows_management(table, '#')[0])
            # If isCancelled is True this means that the cancel button
            # has been pressed
            if arcpy.env.isCancelled:
               raise RuntimeError('Tool has been cancelled')
            arcpy.Merge_management(tables, output)
     except RuntimeError as err:
        # If tool is cancelled or finishes successfully, clean up intermediate data
        if temp_tables:
            for temp_table in temp_tables:

The only way I can think of is the use of Progressor in Arcpy. Using Progressor once the user press the cancel button the loop breaks. Then you can check the result object to see whether it is canceled by the user. Here is a sample code:

def execute(self, parameters, messages):
    import time
                        "Step progressor: Counting from 0 to {0}".format(n),
                        0, n, p)
    for i in range(n):
        if (i % p) == 0:
            ##            # would like to break if user has canceled
            arcpy.SetProgressorLabel("Iteration: {0}".format(i))

    arcpy.SetProgressorLabel("Iteration: {0}".format(i + 1))
    arcpy.SetProgressorPosition(i + 1)
  • Thanks Farid, but this needs to work when running as a geoprocessor service. I don't think the progressor works in that context, does it? – Kirk Kuykendall Mar 16 '15 at 16:58
  • No it doesn't. Although the OP doesn't ask about gp services. – Farid Cheraghi Dec 7 '15 at 10:48

Your Answer

