Customizing tool behavior in a Python toolbox

Validation is everything that happens before a tool's OK button is pushed. When creating your own custom tools, validation allows you to customize how parameters respond and interact to values and each other. Validation is performed with a block of Python code that is used to control tool behavior.

To learn more about validation, see Understanding validation in script tools.

In a Python toolbox, every tool parameter has an associated Parameter object with properties and methods that are useful in tool validation. In a Python toolbox, parameters are defined in the getParameterInfo method of the tool class. The behavior of those parameters, and how they interact with each other and inputs, is validated according to the updateParameters method of the tool class.

Accessing the tool parameters

Parameter objects form the foundation of how parameters are defined and interact in a Python toolbox. The standard practice is to create the list of parameters in the tool class' getParameterInfo method, as shown in the code below.

def getParameterInfo(self):
    #Define parameter definitions

    # First parameter
    param0 = arcpy.Parameter(
        displayName="Input Features",
        name="in_features",
        datatype="GPFeatureLayer",
        parameterType="Required",
        direction="Input")

    return [param0]

For more about defining parameters in a Python toolbox, see Defining parameters in a Python toolbox.

Parameter object

Methods

Method nameUsage description

setErrorMessage(message:string)

Marks the parameter as having an error (a red X) with the supplied message. Tools do not execute if any of the parameters have an error.

setWarningMessage(message:string)

Marks the parameter as having a warning (a yellow triangle) with the supplied message. Unlike errors, tools do execute with warning messages.

setIDMessage(messageType: string, messageID: string, {AddArgument1}, {AddArgument2})

Allows you to set a system message. The arguments are the same as the AddIDMessage function.

clearMessage()

Clears out any message text and sets the status to informative (no error or warning).

hasError()

Returns true if the parameter contains an error.

hasWarning()

Returns true if the parameter contains a warning.

isInputValueDerived()

Returns true if the tool is being validated inside a Model and the input value is the output of another tool in the model.

Parameter object methods

Properties

Property nameRead/WriteValue(s)Description

name

Read-only

String

The parameter name.

direction

Read-only

String: "Input", "Output"

Input/Output direction of the parameter.

datatype

Read-only

String

For a list of parameter data types, see Defining parameter data types in a Python toolbox.

parameterType

Read-only

String: "Required", "Optional", "Derived"

The parameter type.

parameterDependencies

Read/write

Python list

A list of indexes of each dependent parameter.

value

Read/write

Value object

The value of the parameter.

defaultEnvironmentName

Read-only

String

The default environment setting.

enabled

Read/write

Boolean

False if the parameter is unavailable.

altered

Read-only

Boolean

True if the user has modified the value.

hasBeenValidated

Read-only

Boolean

True if the internal validation routine has checked the parameter.

category

Read/write

String

The category of the parameter.

schema

Read-only

Schema object

The schema of the output dataset.

filter

Read-only

Filter object

The filter to apply to values in the parameter.

symbology

Read/write

String

The path to a layer file (.lyrx) used for drawing the output.

message

Read-only

String

The message to be displayed to the user. See setErrorMessage and setWarningMessage above.

Parameter object properties

Although many Parameter object properties are read/write, most of these properties can only be set or modified when you initially create or modify the object. Several properties, including name, displayName, datatype, direction, and parameterType, establish the characteristics of a tool and cannot be modified during validation methods (such as updateMessages and updateParameters).

parameterDependencies

You typically set parameter dependencies for use by the Schema object. There are two cases where the dependencies may already be set in the getParameterInfo method of the tool.

  • For an output dataset parameter whose type is Derived, the dependency is the index of the parameter from which to derive the output.
  • For certain input data types, the dependency is the index of the parameter containing the information used by the control, as shown in the table below.

Input data typeDependent data typeDescription

Field or SQL Expression

Table

The table containing the fields.

INFO Item or INFO Expression

INFO Table

The INFO table containing the items.

Coverage Feature Class

Coverage

The coverage containing features.

Area Units or Linear Units

GeoDataset

A geographic dataset used to determine the default units.

Coordinate System

Workspace

A workspace used to determine the default coordinate system.

Network Analyst Hierarchy Settings

Network Dataset

The network dataset containing hierarchy information.

Geostatistical Value Table

Geostatistical Layer

The analysis layer containing tables.

Network Travel Mode

Network Data Source, Network Dataset, Network Dataset Layer

List of travel modes.

Obtained from data types

Dependencies are typically set in the getParameterInfo method:

def getParameterInfo(self):
    #Define parameter definitions

    # First parameter
    param0 = arcpy.Parameter(
        displayName="Input Features",
        name="in_features",
        datatype="GPFeatureLayer",
        parameterType="Required",
        direction="Input")

    # Second parameter
    param1 = arcpy.Parameter(
        displayName="Sinuosity Field",
        name="sinuosity_field",
        datatype="Field",
        parameterType="Optional",
        direction="Input")
    param1.value = "sinuosity"

    # Third parameter
    param2 = arcpy.Parameter(
        displayName="Output Features",
        name="out_features",
        datatype="GPFeatureLayer",
        parameterType="Derived",
        direction="Output")
    param2.parameterDependencies = [param0.name]
    param2.schema.clone = True

    params = [param0, param1, param2]

    return params

value

This is the value of the parameter that the user entered or you set programmatically. You can set the value in the getParameterInfo method, in which case it serves as the initial default value for the parameter. You can also set the value in updateParameters in response to user input as shown below.

def updateParameters(self, parameters):
    # Set the default distance threshold to 1/100 of the larger of the width
    #  or height of the extent of the input features.  Do not set if there is no 
    #  input dataset yet, or the user has set a specific distance (Altered is true).
    #
    if parameters[0].valueAsText:
        if not parameters[6].altered:
            extent = arcpy.Describe(parameters[0]).extent
        if extent.width > extent.height:
            parameters[6].value = extent.width / 100
        else:
            parameters[6].value = extent.height / 100

    return

A parameter's value property returns an object, unless the parameter isn't populated, in which case the value returns None. To safeguard against a parameter not being populated, use an if check prior to using its value.

The code snippet below tests whether the value is equal to the string "Get Spatial Weights From File". This test works because the parameter data type is a string.

# If the option to use a weights file is selected, enable the 
#   parameter for specifying the file, otherwise disable it

if parameters[3].value:  # check that parameter has a value
    if parameters[3].value == "Get Spatial Weights From File":
        parameters[8].enabled = True
    else:
        parameters[8].enabled = False

As a Value object does not support string manipulation, use the Value object's value property whenever a string is to be manipulated or parsed. The code sample uses the os.path.dirname method to return the directory from a dataset.

if parameters[0].value:
    workspace = os.path.dirname(parameters[0].value.value)
Note:

With the exception of Describe, don't use methods that take a catalog path, such as ListFields, in validation. The dataset may not exist when your tool is validated in ModelBuilder, and the method may fail or give unexpected results.

In the specific case of ListFields, the Describe object's fields property will provide the equivalent information.

Note:

Don't set a parameter value in updateMessages() since the value will not be validated by the internal validation routine.

altered

altered is true if the value of a parameter is changed—by entering an output path, for example. Once a parameter has been altered, it remains altered until the user empties (blanks out) the value, in which case it returns to being unaltered. Programmatically changing a value with validation code will change the altered state. That is, if you set a value for a parameter, the altered state of the parameter will be updated.

altered is used to determine whether you can change the value of a parameter. As an example, suppose a tool has a feature class parameter and a keyword parameter. If the feature class contains points or polygons, the keywords are RED, GREEN, and BLUE, and if lines, ORANGE, YELLOW, PURPLE, and WHITE.

Suppose the user enters a point feature class. If the keyword parameter is unaltered, you set the value to RED, since it's the default value.

If a line feature class is entered, you set the default value to ORANGE as long as the keyword parameter is unaltered.

However, if the keyword parameter has been altered by the user (that is, the keyword is set to GREEN), you should not reset the keyword—the user has made their choice (GREEN) and you don't know their intention—they may change the feature class so that GREEN is valid or they may change the keyword (to PURPLE, for example). Since GREEN isn't a member of the set of keywords you created for lines, internal validate flags the parameter an error. The user has two options at this point: change the input feature class or change the keyword.

if not parameters[2].altered:
    parameters[2].value = "POINT"

hasBeenValidated

hasBeenValidated is false if a parameter's value has been modified by the user since the last time updateParameters and internal validate were called. Once internal validate has been called, geoprocessing automatically sets hasBeenValidated to true for every parameter.

hasBeenValidated is used to determine whether the user has changed a value since the last call to updateParameters. You can use this information in deciding whether to do your own checking of the parameter.

def updateParameters(self, parameters):
    # Set the default distance threshold to 1/100 of the larger of the width
    #  or height of the extent of the input features.  Do not set if there is no 
    #  input dataset yet, or the user has set a specific distance.
    #
    if parameters[0].valueAsText:
        if parameters[6].hasBeenValidated:
            extent = arcpy.Describe(parameters[0]).extent
            if extent.width > extent.height:
                parameters[6].value = extent.width / 100
            else:
                parameters[6].value = extent.height / 100

    return

Related topics