Updating schema in a Python toolbox
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, 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, getParameterInfo 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", "FirstDependencyFIDs", "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
#
parameters[2].parameterDependencies = [parameters[0].name, parameters[1].name]
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 getParameterInfo 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.
class ExampleClipTool1(object):
def __init__(self):
self.label = "Example Clip tool 1"
self.description = "Explicitly setting all rules"
def getParameterInfo(self):
# Input feature class
param0 = arcpy.Parameter(
displayName="Input Features",
name="in_features",
datatype="GPFeatureLayer",
parameterType="Required",
direction="Input")
# Input table
param1 = arcpy.Parameter(
displayName="Clip Features",
name="clip_features",
datatype="GPFeatureLayer",
parameterType="Required",
direction="Input")
# Input workspace
param2 = arcpy.Parameter(
displayName="Output Feature Class",
name="out_feature_class",
datatype="DEFeatureClass",
parameterType="Required",
direction="Output")
# Set the dependencies for the output and its schema properties
# The two input parameters are feature classes.
#
param2.parameterDependencies = [param0.name, param1.name]
# Feature type, geometry type, and fields all come from the first
# dependency (parameter 0), the input features
#
param2.schema.featureTypeRule = "FirstDependency"
param2.schema.geometryTypeRule = "FirstDependency"
param2.schema.fieldsRule = "FirstDependency"
# The extent of the output is the intersection of the input features
# and the clip features (parameter 1)
#
param2.schema.extentRule = "Intersection"
params = [param0, param1, param2]
return params
class ExampleClipTool2(object):
def __init__(self):
self.label = "Example Clip tool 2"
self.description = "Using clone to set rules to FirstDependency, then overriding the extent rule"
def getParameterInfo(self):
# Input feature class
param0 = arcpy.Parameter(
displayName="Input Features",
name="in_features",
datatype="GPFeatureLayer",
parameterType="Required",
direction="Input")
# Input table
param1 = arcpy.Parameter(
displayName="Clip Features",
name="clip_features",
datatype="GPFeatureLayer",
parameterType="Required",
direction="Input")
# Input workspace
param2 = arcpy.Parameter(
displayName="Output Feature Class",
name="out_feature_class",
datatype="DEFeatureClass",
parameterType="Required",
direction="Output")
# Set the dependencies for the output and its schema properties
# The two input parameters are feature classes.
#
param2.parameterDependencies = [param0.name, param1.name]
param2.schema.clone = True
params = [param0, param1, param2]
return params
def updateParameters(self, parameters):
# 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)
#
parameters[0].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. |
"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)
#
parameters[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.
parameters[2].schema.extentRule = "AsSpecified"
parameters[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]
parameters[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. |
"FirstDependencyFIDs" |
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. |
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. |
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 getParameterInfo, the output workspace is cloned from its dependent parameter (param2).
class ExampleTool(object):
def __init__(self):
self.label = "Example tool"
self.description = "Example of parameter dependencies"
def getParameterInfo(self):
#Define parameter definitions
# Input feature class
param0 = arcpy.Parameter(
displayName="Input feature class",
name="in_features",
datatype="GPFeatureLayer",
parameterType="Required",
direction="Input")
# Input table
param1 = arcpy.Parameter(
displayName="Input table",
name="in_table",
datatype="GPTableView",
parameterType="Required",
direction="Input")
# Input workspace
param2 = arcpy.Parameter(
displayName="Input workspace",
name="in_workspace",
datatype="DEWorkspace",
parameterType="Required",
direction="Input")
# Derived workspaces
param3 = arcpy.Parameter(
displayName="Derived workspace",
name="out_workspace",
datatype="DEWorkspace",
parameterType="Derived",
direction="Output")
# Set dependencies to the input workspace parameter
param3.parameterDependencies = [param0.name]
# Copy all existing contents to output
param3.schema.clone = True
params = [param0, param1, param2, param3]
return params
Example: Copy the two inputs (no modifications) to the output workspace:
def updateParameters(self, parameters):
inFC = parameters[0].value # input feature class
inTable = parameters[1].value # input table
inWS = parameters[2].value # input workspace
if inFC and inTable and inWS:
parameters[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 ("SummaryPolygon") and type ("polygon").
def updateParameters(self, parameters):
children = [] # New empty list
children.append(parameters[0].value)
children.append(parameters[1].value)
children.append(["polygon", "SummaryPolygon"])
parameters[3].schema.additionalChildren = children
return
Example: Add a field to the input feature class.
def updateParameters(self, parameters):
# 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(parameters[0].value)
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"])
parameters[3].schema.additionalChildren = children
return
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
def updateParameters(self, parameters):
inVT = parameters[0].value # multivalue ValueTable
inWS = parameters[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 # Row count in 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)
parameters[2].schema.additionalChildren = children
return