I'm currently acquainting myself with the parameter and parameter validation methods of the tool class and I can't quite figure out what's required to get error/warning messages to properly populate and how updateParameters and updateMessages differ for setErrorMessage/setWarningMessage. Either I get no message, the message doesn't update on value change, or its the wrong one. What is the correct code to make sure that a parameter is properly validated after it changes and then displays the proper message (if any)?
For a simple example, I just want to validate that a given parameter is in a list of strings:
project_ids = ['123', '456', '789']
class tool:
def __init__(self):
"""Define the tool (tool name is the name of the class)."""
self.label = 'test tool'
self.description = "test"
def getParameterInfo(self) -> list:
"""Define the tool parameters."""
project_id = arcpy.Parameter(name="project ID",
displayName="project ID",
datatype="GPString",
parameterType="Required", # Required|Optional|Derived
direction="Input", # Input|Output
)
return [project_id]
def isLicensed(self):
"""Set whether the tool is licensed to execute."""
return True
def updateParameters(self, parameters):
"""Modify the values and properties of parameters before internal
validation is performed. This method is called whenever a parameter
has been changed."""
if parameters[0].altered:
if parameters[0].value is None:
parameters[0].setErrorMessage("No Project Specified")
elif parameters[0].valueAsText not in project_ids:
parameters[0].setErrorMessage('Unrecognized project ID')
return
def updateMessages(self, parameters):
"""Modify the messages created by internal validation for each tool
parameter. This method is called after internal validation."""
# The only time I got messages to show up was when I put the code block from updateParameters here
return
@staticmethod
def execute(self, parameters, messages=None):
"""The source code of the tool."""
project_id = parameters[0]
test_function(project_id)
return
def postExecute(self, parameters):
"""This method takes place after outputs are processed and
added to the display."""
return
This is what I do and it seems to work. Maybe you're just missing clearMessage()
def updateParameters(self, parameters):
"""Modify the values and properties of parameters before internal
validation is performed. This method is called whenever a parameter
has been changed."""
project_id = parameters[0].valueAsText
valid_project_ids = ['123', '456', '789']
error_msg = f'Unrecognized project ID; please enter one of the following: {valid_project_ids}'
if project_id:
if project_id not in valid_project_ids:
project_id.setErrorMessage(error_msg)
else:
project_id.clearMessage()
else:
project_id.setErrorMessage(error_msg)
return
TLDR:
Longer message with how I got to that conclusion:
So, I think your biggest problem in this specific case is that you're using updateParameters() for messaging instead of updateMessages().
project_ids = ['123', '456', '789']
def updateMessages(self, parameters):
"""Modify the messages created by internal validation for each tool
parameter. This method is called after internal validation."""
if parameters[0].value:
if parameters[0].valueAsText not in project_ids:
parameters[0].setErrorMessage('Unrecognized project ID')
else:
parameters[0].setWarningMessage(parameters[0].valueAsText)
# I can't get a default message to show up
#else:
# parameters[0].setErrorMessage("No Project Specified")
return
The other issue, and one I couldn't initially solve to my satisfaction, is that you're trying to set a default message to show before anything happens.
I played around a bit, and it seemed to only be a problem if you use setErrorMessage(); setWarningMessage() works just fine as a default. However, setWarningMessage() will override the required bit of the parameter, allowing you to run the tool without giving it a value.
project_ids = ['123', '456', '789']
def updateMessages(self, parameters):
"""Modify the messages created by internal validation for each tool
parameter. This method is called after internal validation."""
if parameters[0].value:
if parameters[0].valueAsText not in project_ids:
parameters[0].setErrorMessage('Unrecognized project ID')
# else:
# parameters[0].setWarningMessage(parameters[0].valueAsText)
else:
parameters[0].setWarningMessage("No Project Specified")
return
So, I got to thinking and experimenting, and I think the true issue is actually not in updateParameters() or updateMessages(), but in getParameterInfo().
If you set your parameter to "Optional", rather than "Required", the issue of setting an error message disappears.
project_ids = ['123', '456', '789']
def getParameterInfo(self) -> list:
"""Define the tool parameters."""
project_id = arcpy.Parameter(name="projectID",
displayName="project ID",
datatype="GPString",
parameterType="Optional",
direction="Input",
)
params = [project_id]
return params
def updateMessages(self, parameters):
"""Modify the messages created by internal validation for each tool
parameter. This method is called after internal validation."""
if parameters[0].value:
if parameters[0].valueAsText not in project_ids:
parameters[0].setErrorMessage('Unrecognized project ID')
# else:
# parameters[0].setWarningMessage(parameters[0].valueAsText)
else:
# Both of these worked for me.
# The former is to conditionally set an optional parameter
# to "required", the latter just sets an error message.
# One or both is fine.
##parameters[0].setIDMessage('ERROR', 735)
parameters[0].setErrorMessage("No Project Specified")
return