Select to view content in your preferred language

Using domain as input parameter in geoprocessing tool

274
2
11-26-2024 04:45 AM
JamesTurner2
Regular Contributor

I have a feature class with trails data in it, it has a field named 'club_name.' The club_name field uses a domain to restrict entries. I want to create a geoprocessing tool that allows users to select a club name from the domain as in input parameter. Is this possible? Essentially I am trying to use a domain to feed a select one/multiple input parameter. 

0 Kudos
2 Replies
Robert_LeClair
Esri Esteemed Contributor

Hmmm...I know the Select by Attribute GP tool does "see" attribute domains for selections.  For the 2nd part of the question, you want features selected that meet the selected "club_name" attribute domain value AND only those attribute values based upon the "club_name".  Right?  I think a graphic or stepped workflow would help me process it better.

0 Kudos
JamesTurner2
Regular Contributor

So as it turns out, this is a classic case not knowing what to google. I kept digging and was able to piece together what I was looking for. The PYT code is below for anyone else who might find themselves in my shoes down the road. Please feel free to offer suggestions on the code, I'm no developer.

While this works as I want, I have not been able to get any error or warning messages to work in this code, I am not sure what I am doing wrong, there are a few 'setErrorMessage' lines (88, 100) in the code that do not appear to do anything when they should be firing. Because of this, to debug I used a rather brute method of changing the parameter value so it would appear in the GP window (commented out). I am trying to trigger this (picture below) sort of warning in my code, but it's not working. You can see in line 100, I'm trying to get it to trigger the warning no matter what and it still does not appear. Surely I am missing something stupid. We're on ArcPro 2.9

JamesTurner2_0-1733267523886.png

 

Domain-restricted parameter 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 = "Toolbox"
        self.alias = "toolbox"

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


class Tool(object):
    def __init__(self):
        """Define the tool (tool name is the name of the class)."""
        self.label = "Generate Club Map"
        self.description = "Creates a map of a ATV or Snowmobile club(s) trail system."
        self.canRunInBackground = False
       

    def getParameterInfo(self):
        """Define parameter definitions"""
        # First parameter
        param0 = arcpy.Parameter(
        displayName="Trail Type",
        name="inputTrails",
        datatype="GPFeatureLayer",
        parameterType="Required",
        direction="Input")
        
        # Filter available options to polygon layers
        param0.filter.list = ["Polygon"]        
        
        # Second parameter
        param1 = arcpy.Parameter(
        displayName="Select Clubs",
        name="inputClubs",
        datatype="GPString",
        parameterType="Required",
        direction="Input",
        multiValue=True)
        
        # Third parameter
        param2 = arcpy.Parameter(
        displayName="Output Folder",
        name="outputFolder",
        datatype="DEFolder",
        parameterType="Required",
        direction="Input")
        
        params = [param0, param1, param2]
        return params

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

    def updateParameters(self, parameters):
        """Modify the values and properties of parameters before internal
        validation is performed.  This method is called whenever a parameter
        has been changed."""
        
        """Update the second parameter based on the first parameter's value."""
        # If trail type has been modified and not validated, reset clubs parameter and fetch club names from domain again
        if parameters[0].value and not parameters[0].hasBeenValidated:

            # Reset club selection
            parameters[1].value = None

            # Clear out club list from trail layer domain
            coded_values = []

            # Selected trails layer
            inputTrails = parameters[0].valueAsText
            
            # Initialize the inputClubs parameter
            inputClubs_param = parameters[1]

            # Get domain values for club_name based on trail type
            try:
                field = "club_name"
                coded_values = self.get_coded_values(inputTrails, field)

                # No values returned
                if not coded_values:
                    inputClubs_param.setErrorMessage("No clubs returned, check that there is club_name domain for the selected layer")
                    #parameters[1].value = 'no clubs'   #error not working, use this to debug
                    return

                # Populate the second parameter (inputClubs) with the coded values
                inputClubs_param.filter.type = "ValueList"
                inputClubs_param.filter.list = coded_values
                
            except Exception as e:
                parameters[0].setErrorMessage(f"Error: {str(e)}")
                #parameters[1].value = f"Error: {str(e)}"   #error not working, use this to debug

            parameters[0].setWarningMessage("Warning message")
            
    
    def get_coded_values(self, feature, field):
        """Helper function to retrieve coded values from the domain."""
        try:
            feature_fields = [f for f in arcpy.ListFields(feature)]

            if field.upper() not in [x.name.upper() for x in feature_fields]:
                raise ValueError("Did not find field: {} in {}".format(field, feature))

            gdb = arcpy.Describe(feature).path

            target_field = [f for f in feature_fields if f.name.upper() == field.upper()][0]
            target_field_domain = target_field.domain

            if target_field_domain:
                field_domain = [d for d in arcpy.da.ListDomains(gdb) if d.name == target_field_domain][0]
                domain_dict = field_domain.codedValues
                domain_desc = list(domain_dict.values())

            return domain_desc
        
        except Exception as e:
            arcpy.AddError(f"Error retrieving domain values: {str(e)}")
            return False


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

    def execute(self, parameters, messages):
        """The source code of the tool."""
        return

 

 

0 Kudos