1

Is there a way to retain Warning or Error messages for parameters between tool validation calls?

In my example below, I want to check the input feature class for something, and add a warning message. For efficiency, I only want to perform these checks and update the messages IF that parameter has changed. But then if I change a different parameter (like unchecking the box in my example), it removes all existing messages.

I have several checks to perform and it takes a few seconds, so I don't want to run these checks every time a subsequent, unrelated parameter is updated. It would be much faster if there was a way to see:

Is there already a warning message here? If so, keep it.

The .hasWarning() property doesn't tell me what the message itself is.

class msgtest(object):
    def __init__(self):
        self.label = "Message test"
        self.description = "Message Test"
        self.canRunInBackground = False

    def getParameterInfo(self):
        
        in_fc = arcpy.Parameter(
            displayName="Input feature class",
            name="in_fc",
            datatype="GPFeatureLayer",
            parameterType="Required",
            direction="Input")
       
        checkbox = arcpy.Parameter(
            displayName="Checkbox",
            name="checkbox",
            datatype="GPBoolean",
            parameterType="Required",
            direction="Input")
        checkbox.value = True   
        
        parameters = [in_fc,checkbox]
        return parameters
        
    def updateMessages(self, parameters):
        # Example - Throw warning message if less than 100 features 
        
        # this option only runs when the input FC has been updated. Messages will disappear if a different parameter is changed.
        if (parameters[0].altered and not parameters[0].hasBeenValidated):
            if int(arcpy.GetCount_management(parameters[0].value).getOutput(0)) < 100:
                parameters[0].setWarningMessage('Fewer than 100 items')
        
        # this option runs every time. Message will always appear correctly but is very inefficient
        #if parameters[0].value:
        #    if int(arcpy.GetCount_management(parameters[0].value).getOutput(0)) < 100:
        #        parameters[0].setWarningMessage('Fewer than 100 items')
        
        return

    def execute(self, parameters, messages):

        return

1 Answer 1

2

The issue is with how to track changes when internal validation is run. Think about your logic; you select a layer and it checks if there are less than 100 features, but it only does that if the parameter has been altered AND it has not been validated. You then click on your checkbox and this fires the internal validation. Has your parameter 0 suddenly changed and not been validated, the answer to that is NO because you are interacting with parameter 1, so the message clears. This seems to be behaviour baked into the ESRI logic.

So you need to track that parameter 0 has not been altered. You can do that by tracking a Boolean flag you create or by storing information in a dictionary, see your amended code:

import arcpy

dictCount = dict()

class Toolbox(object):
    def __init__(self):
        """Define the toolbox (the name of the toolbox is the name of the
        .pyt file)."""
        self.label = "Toolbox"
        self.alias = ""

        # List of tool classes associated with this toolbox
        self.tools = [msgtest]

class msgtest(object):
    global dictCount

    def __init__(self):
        self.label = "Message test"
        self.description = "Message Test"
        self.canRunInBackground = False

    def getParameterInfo(self):

        in_fc = arcpy.Parameter(
            displayName="Input feature class",
            name="in_fc",
            datatype="GPFeatureLayer",
            parameterType="Required",
            direction="Input")

        checkbox = arcpy.Parameter(
            displayName="Checkbox",
            name="checkbox",
            datatype="GPBoolean",
            parameterType="Required",
            direction="Input")
        checkbox.value = True

        parameters = [in_fc,checkbox]
        return parameters

    def updateMessages(self, parameters):
        if parameters[0].altered:
            if dictCount.has_key(parameters[0].valueAsText):
                if dictCount[parameters[0].valueAsText] == "<100":
                    parameters[0].setWarningMessage('Fewer than 100 items')
                else:
                    parameters[0].clearMessage()

            else:
                if int(arcpy.GetCount_management(parameters[0].value).getOutput(0)) < 100:
                    parameters[0].setWarningMessage('Fewer than 100 items')
                    dictCount[parameters[0].valueAsText] = "<100"
                else:
                    dictCount[parameters[0].valueAsText] = ">100"
                    parameters[0].clearMessage()
        return

    def isLicensed(self):
        """Set whether tool is licensed to execute."""
        return True

    def execute(self, parameters, messages):
        return

This code is designed to run using Python 2.7 because of the has_key() method on the dictionary.

2
  • Thanks hornbydd. This seems to be behaving about the same as my commented out version that simply checks every time "if parameters[0].value:" So we're retaining the message correctly, but still having to run the check for 100 items each time any other parameter is changed. In my real script, this process takes a while, the equivalent of adding a time.sleep(3). What I'm really after is a way to just keep the warning message without having to wait 3 seconds every time a box gets checked
    – Brennan
    Jun 8, 2022 at 12:08
  • @Brennan, well spotted! You were correct it still went into the section of the code to do the count which you wanted to avoid. Upon reading the help file on what the property altered actually recorded I realised my original method using the boolean was failing to capture the fact that it had been read. I have rewritten the code to use a dictionary to track the layers and record if the count is <>100. Try this.
    – Hornbydd
    Jun 8, 2022 at 15:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.