0

I'm trying to build a Python Toolbox where the user selects a layer and then specifies a column in that layer. According to the Parameter documentation, that is done via the parameterDependencies attribute of an arcpy.Parameter instance. That same documentation says that you need a list of integers specifying the indexes of the downstream parameters. Presumably they reference the list of parameters you're supposed to return in the getParameterInfo method of your tool's class.

However, even the most basic of examples fails:

import arcpy

class Flooder(object):
    def __init__(self):
        self.label = "1 - Create Flood Scenarios"
        self.description = ""
        self.canRunInBackground = True

    def getParameterInfo(self):
        polygons = arcpy.Parameter(
            displayName="Zones", 
            name="polygons",
            datatype="DEFeatureClass", 
            parameterType="Required",  
            direction="Input"
        )

        tidegate_column = arcpy.Parameter(
            displayName="ID column", 
            name="tidegate_column",
            datatype="Field",
            parameterType="Required", 
            direction="Input"
        )

        return [polygons, tidegate_column]

    def updateParameters(self, parameters):      
        polygons = parameters[0]
        tgcol = parameters[1]
        polygons.parameterDependencies = [1]

f = Flooder()
p = f.getParameterInfo()
f.updateParameters(p)

Which raises:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-23-504b0ce950cb> in <module>()
      1 f = Flooder()
      2 params = f.getParameterInfo()
----> 3 f.updateParameters(params)

<ipython-input-22-c19883891bbb> in updateParameters(self, parameters)
     11         polygons = parameters[0]
     12         tgcol = parameters[1]
---> 13         polygons.parameterDependencies = [1]
     14 
     15 

C:\Program Files (x86)\ArcGIS\Desktop10.2\arcpy\arcpy\arcobjects\_base.pyc in _set(self, val)
     87                     return val
     88         try:
---> 89             return setattr(self._arc_object, attr_name, cval(val))
     90         except AttributeError:
     91             raise NameError(

ValueError: ParameterObject: Dependency list value out of range

Any idea what's going wrong?

I have triple checked my code and the documentation, and I'm passing the specified list of integers that the property needs.

1

The documentation appears to be wrong. It doesn't want a list of integers. It seems to want a list of integers as strings.

Hopefully, Esri updates the documentation, or even better, allows you to pass actual parameters (or their names) in the future. Change the example above to the following and it will work:

import arcpy

class Flooder(object):
    # [snip]

    def updateParameters(self, parameters):      
        polygons = parameters[0]
        tgcol = parameters[1]
        polygons.parameterDependencies = ["1"]  # <-- ints as strings 0_o

f = Flooder()
p = f.getParameterInfo()
f.updateParameters(p)

Per the comments below, you can also pass the parameter's name. But that still seems messy and a bit too hard-coded/magic-number-y for my taste.

So instead, if you create your parameters as class properties, you can operate in a much more literate fashion:

class Flooder(BaseTool_Mixin):
    def __init__(self):
        self._polygons = None
        self._tidegate_column = None

    @staticmethod
    def _set_parameter_dependency(downstream, *upstream):
        """ Set the dependecy of a downstream arcpy.Parameter
        to the (potentially many) upstream arcpy.Parameters
        """
        downstream.parameterDependencies = [u.name for u in upstream]


    def updateParameters(self, parameters):
        """ Automatically called when any parameter is updated in the
        GUI.
        """
        # tidegate_columns looks into the polygons layer to get a list of fields
        self._set_parameter_dependency(self.tidegate_column, self.polygons)

    @property
    def polygons(self):
        if self._polygons is None:
            self._polygons = arcpy.Parameter(
                displayName="Tidegate Zones of Influence", name="polygons",
                datatype="DEFeatureClass", parameterType="Required", direction="Input"
            )
        return self._polygons

    @property
    def tidegate_column(self):
        if self._tidegate_column is None:
            tidegate_column = arcpy.Parameter(
                displayName="Column with Tidegate IDs", name="tidegate_column",
                datatype="Field", parameterType="Required", direction="Input"
            )
        return self._tidegate_column

    def getParameterInfo(self):
        """ Returns all parameter definitions"""
        return [self.polygons, self.tidegate_column]
  • Parameter names will work for Python toolboxes. (might also want to include parameterDependencies in getParameterInfo) – DWynne Oct 29 '15 at 18:24
  • @DWynne good to know. I'll update the answer with a more complete solution that uses python properties and a static method that makes the whole process much more readable. – Paul H Oct 29 '15 at 18:35
  • I believe there is a syntax error in downstream.parameterDependencies = [u.name for u in *upstream]. It should read downstream.parameterDependencies = [u.name for u in upstream]. Notice the parameter upstream has no '*' when referenced in the function. – dhollema Aug 23 '17 at 15:04
  • you're right @dhollema. I'll fix it – Paul H Aug 23 '17 at 15:57
  • If you are right about the documentation being wrong, then I recommend not just hoping that someone else will notice and fix it. Use your local support team to submit a documentation error report. If you want any software behaviour to change then submit an ArcGIS Idea. – PolyGeo Mar 11 '18 at 22:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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