Select to view content in your preferred language

Expand ToolValidator object class for versatility in parameter access

222
2
08-29-2024 10:42 AM
Status: Open
StanNielson
Occasional Contributor

When creating/altering a custom geoprocessing tool, managing parameters in the ToolValidator object can be unwieldy, especially with constant use of self.params[...] (or a temporary replacement variable inside an object method) and referring to parameters by their positional index.  As validation grows in complexity, simplicity and explicitness can provide greater readability in syntax.  This can be accomplished in the default ToolValidator class by adding a simple attribute and making the parameters subscriptable with a ToolValidator method.

Through this, parameters can be accessed by Python sequence index/slice (e.g. self[0], self[0:4], self[-1], etc.) or by parameter name as a mapping key (e.g. self['input_features'], self['spatial_ref'], etc.), and these approaches will function just like accessing self.params (e.g. self.params[0].value is the same as self[0].value and self['input_features'].value). Providing this capability allows for more versatility and readability, with simpler syntax via index/slice and explicit, index-independent syntax via key.  The latter can be especially useful if tool parameters need to be reordered (since the key-based approach ignores order) or if explicitly identifying the parameter in the code is desired.

Additionally, this capability would not affect preexisting approaches to validation logic, as it does not change the accessibility of self.params.  The expanded default ToolValidator object class would appear as: 

class ToolValidator:
    
    """class to add custom behavior and properties to the tool and tool
    parameters
    """

    def __init__(self: object):
        # set self.params for use in other function
        self.params = arcpy.GetParameterInfo()
        self.params_map = dict((i.name, i) for i in self.params)
        return

    def initializeParameters(self: object):
        """customizes parameter properties; called when tool is opened"""
        return

    def updateParameters(self: object):
        """modifies parameter values and properties; called whenever a
        parameter is modified, before standard validation
        """
        return

    def updateMessages(self: object):
        """customizes messages for parameters; called after standard
        validation
        """
        return

    def __getitem__(self: object, reference: slice) -> object:
        if isinstance(reference, str): return self.params_map[reference]
        return self.params[reference]

 

I can personally attest to the effectiveness of these additions, allowing for both simpler syntax and the flexibility to revise my tool parameters without using a position index as an intermediary to identifying parameter references when refactoring.

2 Comments
StanNielson

@AlfredBaldenweck: That is definitely a similar idea.  However, this retains original functionality while also allowing the user the remove the .params portion by making the object subscriptable.  This could go even further by assigning the parameters as attributes to the ToolValidator object in its constructor.