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()
Order of parameters
A tool's parameters and their order are defined in the Parameters tab of the tool's properties, as illustrated below.
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. |
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. |
Read/write |
Python List |
A list of indexes of each dependent parameter. |
|
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). |
Read only |
Boolean |
True if the user has modified the value. |
|
Read only |
Boolean |
True if the internal validation routine has checked the parameter. |
|
Read/write |
String |
The category of the parameter. |
|
Read only |
GP Schema object |
The schema of the output dataset. |
|
Read only |
GP Filter object |
The filter to apply to values in the parameter. |
|
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. |
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. |
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.
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.
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.
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"
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:
- 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).
- Once the user interacts with the tool dialog box in any way, updateParameters() is called.
- 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).
- 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.
- 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 |
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 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. |
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. |
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:
|
"AsSpecified" |
The geometry type will be determined by the value of the geometryType property. |
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. |
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. |
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.
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. |
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). |
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.
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. |
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. |
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. |
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.
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:
- A filter only presents the user with valid choices when browsing for data. If you set your filter for point feature classes, only point feature classes are shown when the user browses for data. If you set your filter for text fields, the drop-down list of fields only shows text fields.
- If a user types in a parameter value (rather than picking a value from the list or file browser), the value is checked against the filter. If the user enters an invalid value (a numeric field instead of a text field, for example), a warning or error is automatically given.
- Because values are checked against their filter by internal validation, a filter frees you from having to program your own custom validation in the ToolValidator class.
There are two ways to specify filters:
- On the Parameters tab of the tool's properties dialog box, click the parameter, then click the cell next to Filter and choose the filter type from the drop-down list. After choosing the filter type, a dialog box opens where you specify the values for the filter.
- You can set the values programmatically in a ToolValidator class (examples are given below). Geoprocessing creates filters automatically for parameters of type string, long, double, feature class, file, field, and workspace. Even if you don't choose a filter on the tool's properties dialog box, there is still a filter associated with the parameter—it's just empty. An empty filter is the same as having no filter. By adding values to an empty filter, you activate the filter, and the user's choices are limited by the contents of the filter.
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. |
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. |
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.
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 |
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
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