Skip To Content

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:

  1. 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).
  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 nameValue(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

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
#
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 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
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
Example 2: Use clone to set rules to FirstDependency and override the extent rule:
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.

ValueDescription

"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.

ValueDescription

"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.

ValueDescription

"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:

  • 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

ValueDescription

"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)
#
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 list with four values. The sequence is xmin, ymin, xmax, ymax.

Example
parameters[2].schema.extentRule = "AsSpecified"
parameters[2].schema.extent = "123.32 435.8 987.3 567.9"
# Alternatively use a list, as follows:
# parameters[2].schema.extent = [123.32, 435.8, 987.3, 567.9]

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.

ValueDescription

"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.

fieldsRule values

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.

ValueDescription

"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.

ValueDescription

"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.

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:

FormDescription

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.

Member lists for additionalChildren

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

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

ArgumentTypeDescription

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 a 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 nameProperties

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.

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

Related topics