Customize tool behavior in a Python toolbox

Validation is everything that happens before a tool's OK button is clicked. 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.

Access 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's 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)

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

setWarningMessage(message)

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

setIDMessage(messageType, messageID, {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/writeValueDescription

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 in which the dependencies may already be set in the getParameterInfo method of the tool.

  • For an output dataset parameter with a derived type, the dependency is the index of the parameter from which the output is derived.
  • 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.

Parameter data typeDependant parameter data type

Areal Unit (GPArealUnit)

A geographic dataset used to determine the default units.

For example, the Feature Layer (GPFeatureLayer), Raster Layer (GPRasterLayer), Feature Set (GPFeatureRecordSetLayer), or Record Set (GPRecordSet) data type can be used.

Field (Field)

The table containing the fields.

For example, the Table View (GPTableView), Feature Layer (GPFeatureLayer), Raster Layer (GPRasterLayer), Feature Set (GPFeatureRecordSetLayer), or Record Set (GPRecordSet) data type can be used.

Field Mappings (GPFieldMapping)

A collection of fields in one or more input tables.

For example, the Table View (GPTableView), Feature Layer (GPFeatureLayer), Raster Layer (GPRasterLayer), Feature Set (GPFeatureRecordSetLayer), or Record Set (GPRecordSet) data type can be used.

Geostatistical Value Table ( GPGAValueTable)

A table of datasets and fields to be used in Geostatistical Analyst tools.

Use the Geostatistical Layer (GPGALayer) data type.

Linear Unit (GPLinearUnit)

A geographic dataset used to determine the default units.

For example, the Feature Layer (GPFeatureLayer), Raster Layer (GPRasterLayer), Feature Set (GPFeatureRecordSetLayer), or Record Set (GPRecordSet) data type can be used.

Network Analyst Hierarchy Settings (GPNAHierarchySettings)

The network dataset containing hierarchy information.

Use the Network Dataset (DENetworkDataset) data type.

Network Travel Mode (NetworkTravelMode)

A list of travel modes.

Use the Network Data Source (GPNetworkDataSource), Network Dataset (DENetworkDataset), or Network Dataset Layer (GPNetworkDatasetLayer) data type.

SQL Expression (GPSQLExpression)

The table containing the fields.

For example, the Table View (GPTableView), Feature Layer (GPFeatureLayer), Raster Layer (GPRasterLayer), Feature Set (GPFeatureRecordSetLayer), or Record Set (GPRecordSet) data type can be used.

parameterDependencies 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 value returns None. To ensure that a parameter is 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

Since 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 below 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 (removes) the value in which case it returns to an unaltered state. 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), do 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 validation flags the parameter an error. Then the user has two options: 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