Programming a ToolValidator class |
|
Release 9.3
Last modified June 3, 2010 |
![]() ![]() ![]() Print all topics in : "Creating script tools" |
Note:
This topic was updated for 9.3.1.
For an overview of the ToolValidator class and use of parameter methods, see Customizing script tool behavior.
def __init__(self): import arcgisscripting as ARC self.GP = ARC.create(9.3) self.params = self.GP.getParameterInfo()
import arcgisscripting gp = arcgisscripting.create() params = gp.getParameterInfo()
NOTE: The list of parameters is 0-based, so the first parameter is at position zero in the list. So, to access the third parameter
p3 = self.params[2]
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 method. |
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. |
Property name | Read/Write | Value(s) | Description |
Name |
![]() |
String | Parameter name as defined on the Parameters tab of the tool's properties. |
Direction |
![]() |
String: "nput, Output | Input/Output direction of the parameter as defined on the Parameters tab of the tool's properties. |
Datatype |
![]() |
String | Data type as defined on the Parameters tab of the tool's properties. |
ParameterType |
![]() |
String: Required, Optional, Derived | Type as defined on the Parameters tab of the tool's properties. |
ParameterDependencies |
![]() |
Python List | A list of indexes of each dependent parameter. |
Value |
![]() |
Value object | The value of the parameter. |
DefaultEnvironmentName |
![]() |
String | Environment as defined on the Parameters tab of the tool's properties. |
Enabled |
![]() |
Boolean | False if the parameter is dimmed (unavailable). |
Altered |
![]() |
Boolean | True if the user has modified the value. |
HasBeenValidated |
![]() |
Boolean | True if the internal validation routine has checked the parameter. |
Category |
![]() |
String | The category of the parameter. |
Schema |
![]() |
GP Schema object | The schema of the output dataset. |
Filter |
![]() |
GP Filter object | The filter to apply to values in the parameter. |
Symbology |
![]() |
String | The pathname to a layer file (.lyr) used for drawing the output. |
Message |
![]() |
String | The message to be displayed to the user. See SetErrorMessage() and SetWarningMessage() above. |
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 |
def initializeParameters(self): # Set the dependencies for the output and its schema properties # self.params[2].ParameterDependencies = [0, 1]
# 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
if str(self.params[0].Value) == "E:\data\example.gdb\roads":
NOTE: When using the geoprocessing describe method, never use the string representation of the value.
desc = self.GP.describe(str(self.params[0].Value))
desc = self.GP.describe(self.params[0].Value)
NOTE: 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 Fields method instead.)
fc = self.params[0].Value shapetype = self.GP.Describe(fc).ShapeType.lower() if shapetype == "point" or shapetype == "multipoint":
if not self.params[2].Altered: self.params[2].Value = "POINT"
# 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 = self.GP.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
def initializeParameters(self): self.params[4].Category = "Options" self.params[5].Category = "Options" self.params[6].Category = "Advanced" self.params[7].Category = "Advanced"
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:
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. |
# Set the dependencies for the output and its schema properties # self.params[2].ParameterDependencies = [0, 1]
E:\Data\TestData\netcity.gdb\infrastructure\roads
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
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
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. |
Value | Description |
Simple | The output will contain simple features. The geometry type of the features is specified with GeometryTypeRul. |
Annotation | The output will contain annotation features. |
Dimension | The output will contain dimension features. |
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. |
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. |
# 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"
self.params[2].Schema.ExtentRule = "AsSpecified" self.params[2].Schema.Extent = "123.32 435.8 987.3 567.9"
xmin = 123.32 ymin = 435.8 xmax = 987.3 ext = [xmin, ymin, xmax, 567.9] self.params[2].Schema.Extent = ext
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. |
"llNoFIDs | All fields except for the ObjectIDs will be written to the output. |
"llFIDsOnly | All ObjectID fields are written to the output, but no other fields from the inputs will be written. |
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
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 cell size 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 cell size.
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 cell size is the smallest cell size of the dependent parameters. Max means it is the largest cell size of the dependent parameters. |
"Environment" | The output cel lsize is calculated based on the cell size environment setting. |
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). |
Form | Description |
Geoprocessing value object | A feature class, table, raster, dimension, or annotation value, as returned by the Value method; for 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. |
Argument | Type | Description |
type | required | One of the following:
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. |
|
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. |
class ToolValidator: def __init__(self): import arcgisscripting as ARC self.GP = ARC.create(9.3) self.params = self.GP.getparameterinfo() def initializeParameters(self): self.params[3].ParameterDependencies = [2] # input workspace self.params[3].Schema.Clone = True # Copy all existing contents to output return
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
children = [] # New empty list children.append(inFC) children.append(inTable) children.append(["polygon", "SummaryPolygon"]) self.params[3].Schema.AdditionalChildren = children
# Create a field object with the name "Category" and type "Long" # newField = self.GP.CreateObject("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 = self.GP.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
# 0 - input features (multivalue) # 1 - input workspace # 2 - derived workspace class ToolValidator: def __init__(self): import arcgisscripting as ARC self.GP = ARC.create(9.3) self.params = self.GP.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 = self.GP.CreateObject("Field") newField.Name = "ProjectID" newField.Type = "Long" for row in range(0, rowCount): value = inVT.GetValue(row, 0) if value: d = self.GP.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
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.
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. 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. |
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. |
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
NOTE: The list of values you provide in ToolValidator always replaces the values set in the tool's properties dialog. This behavior allows you to update the values based on other parameters.
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"
# 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]
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
def initializeParameters(self) # Utility values must be between -10 and 10. # self.params[7].Filter.List = [-10, 10]
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]
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 = self.GP.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
def initializeParameters(self) # Set the input file type to our recognized options file suffixes # self.params[0].Filter.List = ["opt56", "opt57", "globalopt"] return
Display name | Internal name |
Short | SmallInteger |
Long | Integer |
Float | Single |
Text | String |
self.params[1].Filter.List = ["short", "long", "float", "text"] self.params[1].Filter.List = ["smallinteger", "integer", "single", "string"]
self.params[1].Filter.List = ["short", "long"] # if self.params[1].Filter.List[0].lower() == "smallinteger": # do something
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 = self.GP.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
NOTE: Do not use the geoprocessing ListFields method in ToolValidator. Instead, use the Describe method as shown above.