1

I am attempting to get a simple ArcGIS Python toolbox (pyt) set up that allows me to present a subset of appropriate parameters based on selection from a 'parent' parameter. There are 7 (0-6) total in the list object self.params.

self.params[0] is a ValueList containing Selection A, Selection B, and Selection C. It should be the only parameter enabled at load time.

If the user selects Selection A, self.params[1] and self.params[2] are enabled. If the user selects Selection B, self.params[3] and self.params[4] are enabled; and so on.

Unfortunately this is one of those cases where "read the docs" is a little tricky because I have not found a case where Esri shows a full .pyt with this sort of logic, showing how it all should fit together. After reading the pertinent documentation I've attempted to come up with the following code, however, at run-time it is:

  • Loading all parameters and seeming to ignore the initializeParameters() method,
  • Yielding a TypeError because I am giving "two" arguments where only one is accepted (probably me misunderstanding how the class object is supposed to behave in a Python toolbox).

code:

import arcpy


class Toolbox(object):

    def __init__(self):
        """
        Define the toolbox (the name of the toolbox is the name of
        the .pyt file).
        """
        self.label = "ArcTesting"
        self.alias = ""

        # List of tool classes associated with this toolbox
        self.tools = [TestValidation]


class TestValidation(object):

    def __init__(self):
        """
        Define the tool (tool name is the name of the class).
        """
        self.label = "TestValidation"
        self.description = "Test tool validation logic."
        self.canRunInBackground = False
        self.params = self.getParameterInfo()

    def getParameterInfo(self):
        """
        Define parameters.
        :return: list
        """
        # First parameter (Default Enabled)
        param0 = arcpy.Parameter(
            displayName="Input Choice 1",
            name="input_choice_1",
            datatype="GPString",
            parameterType="Required",
            direction="Input"
        )
        # Set up the first parameter's value list
        param0.filter.type = "ValueList"
        param0.filter.list = ["Selection A", "Selection B", "Selection C"]

        # Second parameter (Default Disabled)
        param1 = arcpy.Parameter(
            displayName="Input Layer A",
            name="input_layer_a",
            datatype="GPLayer",
            parameterType="Optional",
            direction="Input"
        )

        # Third Parameter (Default Disabled)
        param2 = arcpy.Parameter(
            displayName="Input String A",
            name="input_string_a",
            datatype="GPString",
            parameterType="Optional",
            direction="Input"
        )

        # Fourth Parameter (Default Disabled)
        param3 = arcpy.Parameter(
            displayName="Input Layer B",
            name="input_layer_b",
            datatype="GPLayer",
            parameterType="Optional",
            direction="Input"
        )

        # Fifth Parameter (Default Disabled)
        param4 = arcpy.Parameter(
            displayName="Input String B",
            name="input_string_b",
            datatype="GPString",
            parameterType="Optional",
            direction="Input"
        )

        # Sixth Parameter (Default Disabled)
        param5 = arcpy.Parameter(
            displayName="Input Layer C",
            name="input_layer_c",
            datatype="GPLayer",
            parameterType="Optional",
            direction="Input"
        )

        # Seventh Parameter (Default Disabled)
        param6 = arcpy.Parameter(
            displayName="Input String C",
            name="input_string_c",
            datatype="GPString",
            parameterType="Optional",
            direction="Input"
        )

        params = [param0, param1, param2, param3, param4, param5, param6]
        return params

    def isLicensed(self):
        """Set whether tool is licensed to execute."""
        return True

    def initializeParameters(self):
        self.params[0].enabled = True
        for p in self.params[1:]:
            p.enabled = False
        return

    def updateParameters(self):
        """Modify the values/properties of parameters before internal
        validation is performed.  This method is called whenever a
        parameter has been changed."""
        if self.params[0].valueAsText == "Selection A":
            for p in self.params[1:2]:
                p.enabled = True
        elif self.params[0].valueAsText == "Selection B":
            for p in self.params[3:4]:
                p.enabled = True
        elif self.params[0].valueAsText == "Selection C":
            for p in self.params[5:]:
                p.enabled = True

    def updateMessages(self):
        """Modify messages created by internal validation for each tool
        parameter. This method is called after internal validation."""
        return True

    def execute(self):
        """The source code of the tool."""
        self.initializeParameters()
        self.updateParameters()

1
  • I'd try 3 parameters only, redefining ast 2 depending on value picked in first.
    – FelixIP
    Commented Sep 7, 2021 at 19:26

1 Answer 1

2
  • execute is called when you click the run button, not when the tool loads.
  • Set params 1-6 enabled = False in getParameterInfo initially.
  • getParameterInfo is called automatically, don't call it yourself
  • updateParameters and updateMessages are passed a positional parameters argument by ArcGIS, your method def needs to accept this. You don't return the params, just set them, because of the way python passes arguments by reference.
  • You don't need to set the params as instance variables, i.e self.params.
  • You should set uneeded params .enabled=False when changing params[0].
  • python slices exclude the upper bound, so in your updateParameters you need to use params[1:3] to access param[1] and param[2] and params[3:5] to access param[3] and param[4] etc...
  • Python toolbox (*.pyt) tools don't have an initializeParameters method. This is only for ToolValidator classes which you only use in script tools in a custom toolbox (*.tbx)

Example:

import arcpy


class Toolbox(object):

    def __init__(self):
        """
        Define the toolbox (the name of the toolbox is the name of
        the .pyt file).
        """
        self.label = "ArcTesting"
        self.alias = ""

        # List of tool classes associated with this toolbox
        self.tools = [TestValidation]


class TestValidation(object):

    def __init__(self):
        """
        Define the tool (tool name is the name of the class).
        """
        self.label = "TestValidation"
        self.description = "Test tool validation logic."
        self.canRunInBackground = False

    def getParameterInfo(self):
        """
        Define parameters.
        :return: list
        """
        # First parameter (Default Enabled)
        param0 = arcpy.Parameter(
            displayName="Input Choice 1",
            name="input_choice_1",
            datatype="GPString",
            parameterType="Required",
            direction="Input"
        )
        # Set up the first parameter's value list
        param0.filter.type = "ValueList"
        param0.filter.list = ["Selection A", "Selection B", "Selection C"]

        # Second parameter (Default Disabled)
        param1 = arcpy.Parameter(
            displayName="Input Layer A",
            name="input_layer_a",
            datatype="GPLayer",
            parameterType="Optional",
            direction="Input"
        )
        param1.enabled = False

        # Third Parameter (Default Disabled)
        param2 = arcpy.Parameter(
            displayName="Input String A",
            name="input_string_a",
            datatype="GPString",
            parameterType="Optional",
            direction="Input"
        )
        param2.enabled = False

        # Fourth Parameter (Default Disabled)
        param3 = arcpy.Parameter(
            displayName="Input Layer B",
            name="input_layer_b",
            datatype="GPLayer",
            parameterType="Optional",
            direction="Input"
        )
        param3.enabled = False

        # Fifth Parameter (Default Disabled)
        param4 = arcpy.Parameter(
            displayName="Input String B",
            name="input_string_b",
            datatype="GPString",
            parameterType="Optional",
            direction="Input"
        )
        param4.enabled = False

        # Sixth Parameter (Default Disabled)
        param5 = arcpy.Parameter(
            displayName="Input Layer C",
            name="input_layer_c",
            datatype="GPLayer",
            parameterType="Optional",
            direction="Input"
        )
        param5.enabled = False

        # Seventh Parameter (Default Disabled)
        param6 = arcpy.Parameter(
            displayName="Input String C",
            name="input_string_c",
            datatype="GPString",
            parameterType="Optional",
            direction="Input"
        )
        param6.enabled = False

        params = [param0, param1, param2, param3, param4, param5, param6]
        return params

    def isLicensed(self):
        """Set whether tool is licensed to execute."""
        return True

    def updateParameters(self, params):
        """Modify the values/properties of parameters before internal
        validation is performed.  This method is called whenever a
        parameter has been changed."""
        if params[0].valueAsText == "Selection A":
            for p in params[1:3]:
                p.enabled = True
            for p in params[3:]:
                p.enabled = False
        elif params[0].valueAsText == "Selection B":
            for p in params[3:5]:
                p.enabled = True
            for p in params[1:3] + params[5:]:
                p.enabled = False
        elif params[0].valueAsText == "Selection C":
            for p in params[5:]:
                p.enabled = True
            for p in params[1:5]:
                p.enabled = False

    def updateMessages(self, params):
        """Modify messages created by internal validation for each tool
        parameter. This method is called after internal validation."""
        return True

    def execute(self):
        pass

The updateParameters method could be made a bit clearer by using a dictionary:

def updateParameters(self, params):
    """Modify the values/properties of parameters before internal
    validation is performed.  This method is called whenever a
    parameter has been changed."""
    lookup = {
        "Selection A": [1, 2],  # Params to enable
        "Selection B": [3, 4],
        "Selection C": [5, 6]
    }
    enabled = lookup[params[0].valueAsText]
    for i, p in enumerate(params[1:], start=1):
        if i in enabled:
            p.enabled = True
        else:
            p.enabled = False
2
  • Thanks - so I don't know if this is beyond the scope of my initial question but, what's then the use for initializeParameters()? Only dependencies? Because the Esri docs seem particularly slender on that method. Either way, your suggestion worked and I have a better grasp of it now.
    – auslander
    Commented Sep 8, 2021 at 20:28
  • Python toolbox (*.pyt) tools don't have an initializeParameters method, see last dotpoint (edit)
    – user2856
    Commented Sep 8, 2021 at 21:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.