Programming a ToolValidator class

For an overview of the ToolValidator class and use of parameter methods, see Customizing script tool behavior.

Parameter object

Accessing the tool parameters

Every tool parameter has an associated parameter object with properties and methods that are useful in tool validation. Parameters are contained in a Python list. The standard practice is to create the list of parameters in the ToolValidator class __init__ method, as shown in the code below.

def __init__(self):
  import arcpy 
  self.params = arcpy.GetParameterInfo()

You can also access parameters in your script (as opposed to the ToolValidator class) as shown below. The only reason to access the parameter list within a script is to set the symbology property.

  import arcpy
  params = arcpy.GetParameterInfo()

Learn more about setting symbology in scripts

Order of parameters

A tool's parameters and their order are defined in the Parameters tab of the tool's properties, as illustrated below.

Parameters and their order
NoteNote:

The list of parameters is 0-based, so the first parameter is at position zero in the list. So, to access the third parameter, you would enter p3 = self.params[2]

Methods

Method name

Usage 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 name

Read/Write

Value(s)

Description

name

Read only

String

Parameter name as defined on the Parameters tab of the tool's properties.

direction

Read only

String: "Input", "Output"

Input/Output direction of the parameter as defined on the Parameters tab of the tool's properties.

datatype

Read only

String

Data type as defined on the Parameters tab of the tool's properties.

parameterType

Read only

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

Type as defined on the Parameters tab of the tool's properties.

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 as defined on the Parameters tab of the tool's properties.

enabled

Read/write

Boolean

False if the parameter is dimmed (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

GP Schema object

The schema of the output dataset.

filter

Read only

GP Filter object

The filter to apply to values in the parameter.

symbology

Read/write

String

The pathname to a layer file (.lyr) 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

Some code examples are shown below. For other coding examples, see Customizing script tool behavior.

ToolValidator properties versus script tool properties

A parameter's default value, filter, symbology, and dependencies can be set in both the Parameters tab of the script tool's properties dialog box and in the ToolValidator class.

Properties you set in ToolValidator always override those set in the script tool properties dialog box. For example, if you set the default value of a parameter to "BLUE" in the script tool properties dialog box, and reset it to "RED" in initializeParameters(), the default value becomes "RED". Once initializeParameters() has been called, the script tool properties dialog box will display "RED" as the default value. If you (or your users) get into the situation where changes you make to one of these four parameter properties in the script's properties dialog box do not get saved, it is probably because the property is overridden within the ToolValidator class.

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 Parameters tab of the tool's properties.

  • 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 type

Dependent data type

Description

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.

Obtained from data types

Dependencies are typically set in the initializeParameters() method:

def initializeParameters(self):
  # Set the dependencies for the output and its schema properties
  #
  self.params[2].parameterDependencies = [0, 1]

value

This is the value of the parameter that the user entered or you set programmatically. You can set the value in initializeParameters(), in which case it serves as the initial default value for the parameter. You can also set values in updateParameters() in response to user input (view an example).

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

A value is an object that has a string representation. 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 self.params[3].value == "Get Spatial Weights From File":
      self.params[8].enabled = True
  else:
      self.params[8].enabled = False

The test in the above code would not work if the parameter data type is a feature class, or any value representing a dataset. Values that represent data on disk, such as feature classes and rasters, need to be converted to strings before doing string operations. The built-in Python function str converts value objects to strings, as follows:

  if str(self.params[0].value) == "E:/data/example.gdb/roads":

You only need to use the str function for values with data types that represent datasets. For these types of values, the str function returns the catalog path to the dataset. You don't need to use this function for other data types, such as long or linear unit, since these data types don't represent datasets and are automatically converted to strings.

CautionCaution:

When using the geoprocessing Describe() method in ToolValidator, never use the string representation of the value.

Incorrect (str function used):

  desc = arcpy.Describe(str(self.params[0].value))

Correct: (str not used)

  desc = arcpy.Describe(self.params[0].value)

You should not use the string representation for datasets (which yields the catalog path to the dataset) since the dataset may not exist—it may be a model variable, and the model has to be run before the dataset exists on disk. If you use the string representation for the dataset, Describe may fail, since the dataset may not yet exist on disk.

CautionCaution:

Don't use geoprocessing object methods that take a catalog path, such as ListFields, in ToolValidator. The dataset may not exist when your tool is validated in ModelBuilder, and the method may fail. (In the case of ListFields, you can use the Describe object fields property instead.)

When you are testing strings for equivalence, you should use case-insensitive comparisons. The code below shows using the Python lower function to lowercase the shape type of a feature class and comparing lowercase strings. (Alternatively, you can use the upper function to compare uppercase strings.)

  fc = self.params[0].value
  shapetype = arcpy.Describe(fc).shapeType.lower()
    if shapetype == "point" or shapetype == "multipoint":

altered

altered is true if the user changed the value of a parameter—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 does not change the altered state. That is, if you set a value for a parameter, the altered state of the parameter does not change.

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 self.params[2].altered:
      self.params[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 was 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.

# 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 if the input features have already been validated,
#  or the user has set a specific distance (Altered is true).
# 
import string
if self.params[0].value and not self.params[0].hasBeenValidated:
  if not self.params[6].altered: 
    extent = arcpy.Describe(self.params[0].value).extent
    width = extent.width
    height = extent.height
    if width > height:
      self.params[6].value = width / 100
    else:
      self.params[6].value = height / 100

category

You can put parameters in different categories to minimize the size of the tool dialog box. The Network Analyst tools use categories, as shown below.

Parameter categories

Since you can only set the category once, set it in initializeParameters(). Setting categories in updateParameters() has no effect. The code below shows putting parameters 4 and 5 into the "Options" category and parameters 6 and 7 into the "Advanced" category.

  def initializeParameters(self):
    self.params[4].category = "Options"
    self.params[5].category = "Options"
    self.params[6].category = "Advanced"
    self.params[7].category = "Advanced"

Categories are always shown after noncategorized parameters. Do not put required parameters into categories, since the user may not see them on the tool dialog box.

symbology

The symbology property associates a layer file (.lyr) with an output parameter.

params[2].symbology = "E:/tools/extraction/ToolData/ClassByDist.lyr"

Learn more about output symbology

schema object

Every output parameter of type feature class, table, raster, or workspace has a schema object. Only output feature classes, tables, rasters, and workspaces have a schema—other types do not. The schema object is created for you by geoprocessing. You access this schema through the parameter object and set the rules for describing the output of your tool. After you set the schema rules, and on return from the ToolValidator class, the geoprocessing internal validation code examines the rules you set and updates the description of the output.

To review, the flow of control is as follows:

  1. When the tool dialog box is first opened, initializeParameters() is called. You set up the static rules (rules that don't change based on user input) for describing the output. No output description is created at this time, since the user hasn't specified values for any of the parameters (unless you've provided default values).
  2. Once the user interacts with the tool dialog box in any way, updateParameters() is called.
  3. updateParameters() can modify the schema object to account for dynamic behavior that can't be determined from the parameter dependencies (such as adding a new field like Add Field).
  4. After returning from updateParameters(), the internal validation routines are called and the rules found in the schema object are applied to update the description of the output data.
  5. updateMessages() is then called. You can examine the warning and error messages that internal validation may have created and modify them or add your own custom warning and error messages.

All schema properties are read and write except for type, which is read-only.

Property name

Value(s)

type

String: "Feature", "Table", "Raster" , "Container" (for workspaces and feature datasets) (Read-only property)

clone

Boolean

featureTypeRule

String: "AsSpecified", "FirstDependency"

featureType

String: "Simple", "Annotation", "Dimension"

geometryTypeRule

String: "Unknown", "FirstDependency", "Min", "Max", "AsSpecified"

geometryType

String: "Point", "Multipoint", "Polyline", "Polygon"

extentRule

String: "AsSpecified", "FirstDependency", "Intersection", "Union", "Environment"

extent

Extent object

fieldsRule

String: "None", "FirstDependency", "FirstDependencyFIDsOnly", "All", "AllNoFIDs", "AllFIDsOnly"

additionalFields

Python list of field objects

cellSizeRule

String: "AsSpecified", "FirstDependency", "Min", "Max", "Environment"

cellsize

double

rasterRule

String: "FirstDependency", "Min", "Max", "Integer", "Float"

rasterFormatRule

String: "Img", "Grid"

additionalChildren

Python list of datasets to add to a workspace schema

Schema object properties

Using FirstDependency

Several of the rules can be set to "FirstDependency", which means to use the value of the first parameter found in parameter dependency array set with parameter.parameterDependencies. In the code example below, parameter 2 has two dependent parameters, 0 and 1, and the first dependency is parameter 0.

  # Set the dependencies for the output and its schema properties
  #
  self.params[2].parameterDependencies = [0, 1]

If any dependent parameter is a multivalue (a list of values), the first value in the multivalue list is used.

type

The type property is read-only and is set by geoprocessing.

clone

If true, you are instructing geoprocessing to make an exact copy (clone) of the description in the first dependent parameter. The default value is false. Typically, you set clone to true in the initializeParameters() method. If the first dependent parameter is a multivalue (a list of values), the first value in the multivalue list is cloned.

  • If parameter.parameterType is "Derived", an exact copy is made. This is the behavior of the Add Field tool.
  • If parameter.parameterType is "Required", an exact copy is also made, but the catalog path to the dataset is changed. Catalog paths consist of two parts: the workspace and the base name. For example:

    E:/Data/TestData/netcity.gdb/infrastructure/roads

    • Workspace = E:/Data/TestData/netcity.gdb/infrastructure
    • Base name = roads
    The rules used to construct new output names are as follows:
    • The base name is the same as the base name of the first input parameter containing a dataset (not the first dependency but the first parameter) appended with the name of the script tool (for example, roads_MyTool)
    • The workspace is set to the scratch workspace environment setting. If this is empty, the current workspace environment setting is used. If this is empty, the workspace of the first input parameter containing a dataset is used. If this workspace is read-only, then the system temp directory is used.

After setting clone to true, all rule-based methods, such as featureTypeRule, geometryTypeRule, and extentRule, are set to "FirstDependency".

The two code examples below do the equivalent work. Both examples are based on how the Clip tool creates the output schema.

Example 1: Explicitly setting all rules

  def initializeParameters(self):
    # Set the dependencies for the output and its schema properties
    #  The two input parameters are feature classes.
    #
    self.params[2].parameterDependencies = [0, 1]

    # Feature type, geometry type, and fields all come from the first 
    #  dependency (parameter 0), the input features
    #
    self.params[2].schema.featureTypeRule = "FirstDependency"
    self.params[2].schema.geometryTypeRule = "FirstDependency"
    self.params[2].schema.fieldsRule = "FirstDependency"

    # The extent of the output is the intersection of the input features 
    #  and the clip features (parameter 1)
    #
    self.params[2].schema.extentRule = "Intersection"

    return

Example 2: using clone to set rules to FirstDependency, then overriding the extent rule:

  def initializeParameters(self):
    # Set the dependencies for the output and its schema properties
    #  The two input parameters are feature classes.
    #
    self.params[2].parameterDependencies = [0, 1]
    self.params[2].schema.clone = True
    return
    
  def updateParameters(self):
    # The only property of the clone that changes is that the extent 
    #  of the output is the intersection of the input features 
    #  and the clip features (parameter 1)
    #
    self.params[2].schema.extentRule = "Intersection"
    return

featureTypeRule

This setting determines the feature type of the output feature class. This rule has no effect on output rasters or tables.

Value

Description

"AsSpecified"

The feature type will be determined by the featureType property.

"FirstDependency"

The feature type will be the same as the first parameter in the dependencies. If the first dependent parameter is a multivalue (a list of values), the first value in the multivalue list is used.

featureTypeRule values

featureType

When the featureTypeRule is "AsSpecified", the value in featureType is used to specify the feature type of the output.

Value

Description

"Simple"

The output will contain simple features. The geometry type of the features is specified with geometryTypeRule.

"Annotation"

The output will contain annotation features.

"Dimension"

The output will contain dimension features.

featureType values

geometryTypeRule

This setting determines the geometry type (such as point or polygon) of the output feature class.

Value

Description

"Unknown"

This is the default setting. Typically, you should be able to determine the geometry type in updateParameters() based on the values of other parameters. You'd only set the rule to "Unknown" if you don't have enough information to determine the geometry type, such as in initializeParameters().

"FirstDependency"

The geometry type is the same as the first dependent parameter. If the first dependent parameter is a multivalue (a list of values), the first value in the multivalue list is used.

"Min", "Max"

Examines the geometries of all dependent parameters and sets the output geometry type to the minimum or maximum type found. "Min" and "Max" are defined as follows:

  • Point and Multipoint = 0
  • Polyline = 1
  • Polygon = 2
So, if the dependent parameters were a point and polygon feature class, the minimum would be point, and the maximum would be polygon.

"AsSpecified"

The geometry type will be determined by the value of the geometryType property.

geometryTypeRule values

geometryType

Set this to the geometry type to use (either "Point", "Multipoint", "Polyline", or "Polygon") when geometryTypeRule is "AsSpecified".

extentRule

Value

Description

"AsSpecified"

The output extent will be specified in the extent property.

"FirstDependency"

The output extent is the same as the first dependent parameter. If the first dependent parameter is a multivalue (a list of values), the first value in the multivalue list is used.

"Intersection"

The output extent will be the geometric intersection of all dependent parameters. (This is what the Clip tool uses, as shown below.)

"Union"

The output extent will be the geometric union of all dependent parameters.

"Environment"

The output extent will be calculated based on the output extent environment setting.

extentRule values

Example

    # The extent of the output is the intersection of the input features 
    #  and the clip features (the dependent parameters)
    #
    self.params[2].schema.extentRule = "Intersection"

extent

Set this to the extent to use when extentRule is "AsSpecified". You can either set the extent with a space-delimited string or a Python list object with four values. The sequence is xmin, ymin, xmax, ymax.

Example

self.params[2].schema.extentRule = "AsSpecified"
self.params[2].schema.extent = "123.32 435.8 987.3 567.9"

or using a Python list

xmin = 123.32
ymin = 435.8
xmax = 987.3
ext = [xmin, ymin, xmax, 567.9]
self.params[2].schema.extent = ext

fieldsRule

fieldsRule determines what fields will exist on the output feature class or table.

In the table below, FID stands for Feature ID but actually refers to the ObjectID field found on every feature class or table.

Value

Description

"None"

No fields will be output except for the object ID.

"FirstDependency"

Output fields will be the same as the first dependent parameter. If the first dependent parameter is a multivalue (a list of values), the first value in the multivalue list is used.

"FirstDependencyFIDsOnly"

Only the ObjectID of the first dependent input will be written to the output.

"All"

All fields in the list of dependent parameters will be output.

"AllNoFIDs"

All fields except for the ObjectIDs will be written to the output.

"AllFIDsOnly"

All ObjectID fields are written to the output, but no other fields from the inputs will be written.

fieldsRule values

Example of Clip using fieldsRule of "FirstDependency"

  def initializeParameters(self):
    # Set the dependencies for the output and its schema properties
    #  The two input parameters are feature classes.
    #
    self.params[2].parameterDependencies = [0, 1]

    # Feature type, geometry type, and fields all come from the first 
    #  dependency (parameter 0), the input features
    #
    self.params[2].schema.featureTypeRule = "FirstDependency"
    self.params[2].schema.geometryTypeRule = "FirstDependency"
    self.params[2].schema.fieldsRule = "FirstDependency"

    # The extent of the output is the intersection of the input features 
    #  and the clip features (parameter 1)
    #
    self.params[2].schema.extentRule = "Intersection"

    return

additionalFields

Besides the fields that are added by the application of the fieldsRule, you can add additional fields to the output. additionalFields takes a Python list of field objects.

View example of using AdditionalFields

cellSizeRule

This determines the cellsize of output rasters or grids.

Value

Description

"AsSpecified"

The output cellsize is specified in the cellSize property.

"FirstDependency"

The cell size is calculated from the first dependent parameter. If the dependent parameter is a raster, then its cellsize is used. For other types of dependent parameters, such as feature classes or feature datasets, the extent of the data is used to calculate a cellsize. If the first dependent parameter is a multivalue (a list of values), the first value in the multivalue list is used.

"Min", "Max"

"Min" means the output cellsize is the smallest cellsize of the dependent parameters. "Max" means it is the largest cellsize of the dependent parameters.

"Environment"

The output cellsize is calculated based on the cellsize environment setting.

cellSizeRule values

cellSize

Set this to the cellsize to use when cellSizeRule is "AsSpecified".

rasterRule

This determines the data type—integer or float—contained in the output raster.

Value

Description

"FirstDependency"

The data type (integer or float) is the same as the first dependent parameter. If the first dependent parameter is a multivalue (a list of values), the first value in the multivalue list is used.

"Min", "Max"

Integer is considered smaller than float. For example, if there are two dependent parameters, one containing integers and the other containing floats, "Min" creates an integer output, and "Max" creates a float output.

"Integer"

The output raster contains integers (whole numbers).

"Float"

The output raster contains floats (fractional numbers).

rasterRule values

rasterFormatRule

This determines the output raster format, either "Grid" or "Img". The default is "Img", which is ERDAS IMAGINE format. "Grid" is ESRI's format.

Learn more about raster data formats

additionalChildren

A workspace is a container for datasets (features, tables, and rasters). These datasets are children of the workspace (think of the workspace as the parent). If your tool adds datasets to a new or existing workspace, you can update the description of the workspace by adding descriptions of the children. For example, you may have a tool that takes a list of feature classes (a multivalue), modifies them in some way, then writes the modified feature classes to an existing workspace. When the tool is used in ModelBuilder, the workspace is the derived output of the tool, and you may want to use this workspace as input to the Select Data tool. Select Data allows you to select a child dataset found in a container and use it as input to another tool.

The input to additionalChildren is one or more descriptions of the children. There are two forms of child descriptions:

Form

Description

value object

A feature class, table, raster, dimension, or annotation value, as returned by the value property. Example:

inFeatures = self.params[0].value

Python list object of the form [type, name, fields, extent, spatial reference]

A Python list containing a description of the child to be added. Only the first two entries in the list, type and name, are required. The remaining arguments are optional.

Member lists for additionalChildren

When adding more than one child, you provide a list of child descriptions. If you're adding the children using the Python list object form, you'll create a list of lists for additionalChildren.

The Python list form has five arguments, as described in the following table.

Argument

Type

Description

type

required

One of the following: "Point", "Multipoint", "Polyline", "Polygon", "Table", "Raster", "Annotation", "Dimension"

name

required

The name of the dataset. It can just be the base name of the dataset ("streets") or the full catalog path ("E:\mydata\test.gdb\infrastructure\streets"). When a full catalog path is given, all but the base name ("streets") is ignored.

fields

optional

A Python list of field objects. This contains the fields appearing on the child, if known.

extent

optional

A string or Python list containing the spatial extent of the child.

spatial reference

optional

A spatial reference object.

Contents of the child list

These arguments must be supplied in the order shown. To skip over an optional argument, use the Python keyword None, or "#".

Following are some examples of setting a workspace schema. The examples are based on a script tool that has the following arguments:

Parameter name

Properties

0

Input feature class

Feature class—input.

1

Input table

Table—input.

2

Input workspace

Workspace—input (an existing workspace that contains the results of the tool).

3

Derived workspace

Workspace—Derived output, obtained from Input_workspace. The schema of this workspace is modified to contain additional children.

Example tool parameters

The tool takes the input feature class and table, copies both to the workspace, adds a new field to the feature class, then creates a new polygon feature class in the workspace. (The actual work of the tool isn't important as it only serves to illustrate setting a workspace schema.) The code examples below build on one another, starting with simple usage of additionalChildren. If you choose to implement and test some of the code examples below, you can test the code using the model illustrated below.

Model used to view results of validation

In initializeParameters(), the output workspace is cloned from its dependent parameter (parameter 2). This dependency is set in the tool properties but can also be set in initializeParameters() to guard against someone removing the dependency in the tool's properties.

class ToolValidator:
  def __init__(self):
     import arcpy 
     self.params = arcpy.GetParameterInfo()

  def initializeParameters(self):
    self.params[3].parameterDependencies = [2]  # input workspace
    self.params[3].schema.clone = True  # Copy all existing contents to output
    return

Example: Copy the two inputs (no modifications) to the output workspace:

  def updateParameters(self):
    inFC = self.params[0].value     # input feature class
    inTable = self.params[1].value  # input table
    inWS = self.params[2].value     # input workspace
    if inFC and inTable and inWS:
      self.params[3].schema.additionalChildren = [inFC, inTable]
    return

Example: The tool creates a new polygon feature class. The only properties known about this new feature class (when validating) are the name ("SummaryPoly") and type ("polygon").

  children = []    # New empty list
  children.append(inFC)
  children.append(inTable)
  children.append(["polygon", "SummaryPolygon"])
  self.params[3].schema.additionalChildren = children

Example: Add a field to the input feature class.

  # Create a field object with the name "Category" and type "Long"
  #
  newField = arcpy.Field()
  newField.name = "Category"
  newField.type = "Long"

  # Describe the input feature class in order to get its list of fields. The 9.3
  #  version of the geoprocessing object returns fields in a Python list, unlike
  #  previous versions, which returned fields in an enumerator.
  #
  desc = arcpy.Describe(inFC)
  fieldList = desc.fields

  # Add the new field to the list
  #
  fieldList.append(newField)

  # Create a new child based on the input feature class, but with the 
  #  additional field added
  #
   newChild = [desc.shapeType, desc.catalogPath, fieldList, 
               desc.extent, desc.spatialReference]

  # Now create our list of children and add to the schema
  #
  children = []
  children.append(newChild)
  children.append(inTable)
  children.append(["polygon", "SummaryPolygon"])
  self.params[3].schema.additionalChildren = children

To create fields for SummaryPolygon (the new polygon feature class), create a list of field objects similar to the pattern shown in the above example.

Example: Multivalue input

In this example, the first parameter is a multivalue of feature classes. Each feature class in the multivalue is copied to the derived workspace. A new field, ProjectID, is added to each of the copied feature classes.

# 0 - input features (multivalue)
# 1 - input workspace
# 2 - derived workspace

class ToolValidator:
  def __init__(self):
     import arcpy 
     self.params = arcpy.GetParameterInfo()

  def initializeParameters(self):
    self.params[2].parameterDependencies = [1]
    self.params[2].schema.clone = True
    return

  def updateParameters(self):
    inVT = self.params[0].value   # multivalue ValueTable
    inWS = self.params[1].value   # WorkSpace

    # Add each feature class to the output workspace. In addition,
    #  add a new field "ProjectID" to each feature class
    #
    if inVT and inWS:
        rowCount = inVT.rowCount  # Number of rows in the MultiValue table
        children = []
        newField = arcpy.Field()
        newField.name = "ProjectID"
        newField.type = "Long"
        for row in range(0, rowCount):
            value = inVT.getValue(row, 0)
            if value:
                d = arcpy.Describe(value)
                fieldList = d.fields

                # Note -- not checking if field already exists
                #
                fieldList.append(newField)

                # Create new child with additional ProjectID field and
                #  add child to list of children
                #
                child = [d.shapeType, d.catalogPath, fieldList]
                children.append(child)            
                      
        self.params[2].schema.additionalChildren = children
    return

  def updateMessages(self):
    return

filter object

The filter object allows you to specify the choices available to the user for a parameter. For example, you can set up a field filter that limits choices to just text fields. A filter does three jobs:

There are two ways to specify filters:

There are six kinds of filters, as shown in the table below:

Filter type

Values

ValueList

A list of string or numeric values. Used with String, Long, Double, and Boolean data types.

Range

A minimum and maximum value. Used with Long and Double data types.

FeatureClass

A list of allowable feature class types, specified with the values "Point", "Multipoint", "Polyline", "Polygon", "MultiPatch", "Sphere", "Annotation", "Dimension". More than one value can be supplied to the filter.

File

A list of file suffixes,for example, ".txt", ".e00", ".ditamap".

Field

A list of allowable field types, specified by the values "Short", "Long", "Single", "Double", "Text", "Date", "OID", "Geometry", "Blob", "Raster", "GUID", "GlobalID", "XML". More than one value can be supplied to the filter.

Workspace

A list of allowable workspace types, specified by the values "FileSystem", "LocalDatabase", and "RemoteDatabase". More than one value can be supplied.

Filter type and values

Properties

Property

Description

type

The type of filter (ValueList, Range, FeatureClass, File, Field, and Workspace). You can set the type of filter when dealing with Long and Double parameters (see note below). For other types of parameters, there is only one valid type of filter, so setting the type on these parameters is ignored. If you do not want to filter values, set the list property to an empty list.

list

A Python list of values for the filter. If you do not want to filter values, set the list property to an empty list.

filter properties

ValueList

ValueList for String parameters

For a string parameter, the list can contain any number of strings. Below is an example of setting the list of string values in initializeParameters(). The parameter contains two choices, "NEW_FORMAT" and "OLD_FORMAT".

  def initializeParameters(self):
    # Set the fixed list of "file format type" parameter choices and its
    #  default value
    #
    self.params[1].filter.list = ["OLD_FORMAT", "NEW_FORMAT"]
    self.params[1].value = "OLD_FORMAT"
    return

In the above example, you could have just as easily set the list of values in the Parameter tab of the tool's Properties dialog box. In fact, if you had set the list of values to something else (like "OLD" and "NEW") in the tool's properties, these values would be replaced by "OLD_FORMAT" and "NEW_FORMAT" when initializeParameters() is called. The same is true for the default value—it can be set in the tool's Properties dialog box, then reset in ToolValidator.

NoteNote:

The list of values you provide in ToolValidator always replaces the values set in the tool's Properties dialog box. This behavior allows you to update the values based on other parameters.

Continuing with this example, the code below shows updateParameters() changing a list of values in another parameter based on whether the user chose "OLD_FORMAT" or "NEW_FORMAT":

  def updateParameters(self):
    # Update the value list filter of the "feature type in file" parameter 
    #   depending on the "file format type" parameter.
    #
    if self.params[1].value.upper() == "OLD_FORMAT":
      self.params[2].filter.list = ["POINT", "LINE", "POLYGON"]
    elif self.params[1].value.upper() == "NEW_FORMAT":
      self.params[2].filter.list = ["POINT", "LINE", "POLYGON", 
                                    "POINT_WITH_ANNO", 
                                    "LINE_WITH_ANNO", 
                                    "POLYGON_WITH_ANNO"]

    # Provide default value for "feature type in file" parameter
    #
    if not self.params[2].altered:
      self.params[2].value = "POINT"

ValueList for Long and Double parameters

A Long or Double parameter can have a list of numeric values. The user can only choose or enter values that are in the list.

  # Set filter for a Long parameter
  #
  self.params[7].filter.list = [10, 20, 30, 40, 50]

  # Set filter for a Double parameter
  #
  self.params[8].filter.list = [10.0, 12.5, 15.0]

ValueList for Boolean parameters

There are two values for a Boolean parameter: the true value and false value. The true value is always the first value in the list.

  def initializeParameters(self):
    # Set the Boolean choice for including or excluding angles
    #
    self.params[6].filter.list = ["ANGLE", "NO_ANGLE"]
    
    # Set the default value to false (no angle)
    #
    self.params[6].value = "NO_ANGLE"
    return

  def updateParameters(self):
    # Enable angle format parameter if user wants angles
    #
    if self.params[6].value.upper() == "ANGLE":
      self.params[7].enabled = True

Range

A Long or Double parameter can have a Range filter. Range filters have two values, the minimum and maximum. The first value in the list is the minimum. The range is inclusive, meaning the minimum and maximum are valid choices.

  def initializeParameters(self)
    # Utility values must be between -10 and 10.
    #
    self.params[7].filter.list = [-10, 10]

Setting filter type on long and double parameters

For Long and Double parameters, the default filter type is ValueList. If you want it to be a Range filter, set the filter type in initializeParameters(), as follows:

  def initializeParameters(self)
    # Set the 'score' value parameters to a range filter
    #
    self.params[7].filter.type = "Range"
    self.params[7].filter.list = [-10, 10]

You can only set the filter type for Long and Double parameters.

FeatureClass

The example below shows setting the feature type of one input parameter based on the feature type of another input parameter.

  def updateParameters(self):
    # Set the input feature type of the second parameter based
    #  on the feature type of the first parameter.
    #
    if self.params[0].value:
      desc = arcpy.Describe(self.params[0].value)
      feature_type = desc.shapeType.lower()

      if feature_type == "polygon":
        self.params[1].filter.list = ["point", "multipoint"]

      elif feature_type == "polyline":
        self.params[1].filter.list = ["polygon"]
      
      elif feature_type == "point" or \
           feature_type == "multipoint":
        self.params[1].filter.list = ["polyline"]

      else:
        self.params[1].filter.list = []
      
    return

File

The file filter contains a list of file suffixes that a file can have, such as ".txt" (simple text file) and ".csv" (comma separated value). You can supply any text for a suffix—it doesn't have to be a suffix that ArcGIS recognizes. The suffix can be of any length and does not include the dot. The example below shows setting the filter for an input File parameter.

  def initializeParameters(self)
    # Set the input file type to our recognized options file suffixes
    #
    self.params[0].filter.list = ["opt56", "opt57", "globalopt"]
    return

Field

The field filter defines the permissible field types. Values can be "Short", "Long", "Single", "Double", "Text", "Date", "OID", "Geometry", "Blob", "Raster", "GUID", "GlobalID", "XML".

Display versus internal name

There are four field types that have an internal name, shown in the table below.

Display name

Internal name

Short

SmallInteger

Long

Integer

Float

Single

Text

String

Field filter aliases

When specifying a field filter, you can use either the display or internal name. That is, the following two lines of code are equivalent:

  self.params[1].filter.list = ["short", "long", "float", "text"]
  self.params[1].filter.list = ["smallinteger", "integer", "single", "string"]

If you supply the display name, such as "short", it is converted and stored in the filter as "SmallInteger". You should rarely need to access values in the field filter, but if you do, be aware that the internal name is stored. The code snippet below shows how to account for this:

  self.params[1].filter.list = ["short", "long"]
  # 
  if self.params[1].filter.list[0].lower() == "smallinteger":
    # do something

Setting a default field value

You may want to provide a default value for a field parameter. The way you do this is to loop through the fields on the input table and pick the first field that satisfies the filter, as follows:

  def initializeParameters(self):
    self.params[1].filter.list = ["short", "long", "float", "double"]
    return

  def updateParameters(self):
    if self.params[0].value and not self.params[1].altered:
        self.params[1].value = ""
        desc = arcpy.Describe(self.params[0].value)
        fields = desc.fields

        # Set default to the first field that matches our filter
        #
        for field in fields:
            fType = field.type.lower()
            if fType == "smallinteger" or \
               fType == "integer" or \
               fType == "single" or \
               fType == "double":
                self.params[1].value = field.name
                break
    return
CautionCaution:

Do not use the geoprocessing ListFields function in ToolValidator. Instead, use the Describe function as shown above.

Workspace

The workspace filter specifies the types of input workspaces that are permissible. There are three values:

  • " FileSystem"

    A system folder, used to store shapefiles, ArcInfo coverages, INFO tables, and grids

  • " LocalDatabase"

    A personal or file geodatabase

  • " RemoteDatabase"

    An ArcSDE database connection


4/14/2011