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