Hi,
I am working on a custom script tool where the update parameters automatically adjust a list of selectable values. Every time the user selects a value, it is removed from the list of values and returns whichever values remain. This is set up so that either not too many values are selected or a repeat of values is selected. It works, but then this error message appears. Any help on this would be greatly appreciated.
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 parameter 2 values from list generated from parameter 1 input
feature_class = parameters[1].value
TileNumber_field = [field.name for field in arcpy.ListFields(feature_class) if field.name == 'TILE_NUMBER']
scur = arcpy.da.SearchCursor(feature_class, TileNumber_field)
parameters[2].filter.list = [row[0] for row in scur]
Export_values = ['Water', 'Sewer', 'Stormwater', 'Lidar']
Sub_ListValues = []
# Update parameter 3 value list
Selected_value = parameters[3].valueAsText
if Selected_value is None:
parameters[3].filter.list = Export_values
else:
if ';' not in Selected_value:
parameters[3].filter.list = [value for value in Export_values if value != Selected_value]
elif ';' in Selected_value:
converted_str2list = Selected_value.split(';')
parameters[3].filter.list = [value for value in Export_values if value not in converted_str2list]
return
Solved! Go to Solution.
If I understand what you are trying to do, I usually accomplish it by a displaying set of checkboxes that dictate which input fields to display. The example below might seem like overkill but the code is pretty simple - you just have to set up the mapping of checkboxes to input parameters correctly.
def getParameterInfo(self):
cb_0 = arcpy.Parameter(displayName="Checkbox 0", name="cb_0", datatype="GPBoolean", parameterType="Required", direction="Input")
cb_1 = arcpy.Parameter(displayName="Checkbox 1", name="cb_1", datatype="GPBoolean", parameterType="Required", direction="Input")
cb_2 = arcpy.Parameter(displayName="Checkbox 2", name="cb_2", datatype="GPBoolean", parameterType="Required", direction="Input")
in_0 = arcpy.Parameter(displayName="Input 0", name="in_0", datatype="GPString", parameterType="Optional", direction="Input")
in_1 = arcpy.Parameter(displayName="Input 1", name="in_1", datatype="GPString", parameterType="Optional", direction="Input")
in_2 = arcpy.Parameter(displayName="Input 2", name="in_2", datatype="GPString", parameterType="Optional", direction="Input")
in_3 = arcpy.Parameter(displayName="Input 3", name="in_3", datatype="GPString", parameterType="Optional", direction="Input")
in_4 = arcpy.Parameter(displayName="Input 4", name="in_4", datatype="GPString", parameterType="Optional", direction="Input")
return [cb_0, cb_1, cb_2, in_0, in_1, in_2, in_3, in_4]
def updateParameters(self, parameters):
# Parameter indexes
CB_0 = 0
CB_1 = 1
CB_2 = 2
IN_0 = 3
IN_1 = 4
IN_2 = 5
IN_3 = 6
IN_4 = 7
# Map checkbox parameter to visible input parameters
TBL = {CB_0: [IN_0],
CB_1: [IN_1, IN_2],
CB_2: [IN_2, IN_3, IN_4]}
# Update parameter visibility
for p_in in range (IN_0, IN_4 + 1):
parameters[p_in].enabled = False
for p_cb in [p for p in range (CB_0, CB_2+1) if parameters[p].value == True]:
for p_in in TBL[p_cb]:
parameters[p_in].enabled = True
return
Do you have anything in the in the default value or filter of the parameter of the tool?
I don't have a default nor do I have any filter of the parameter. I haven't tried setting the filter but I guess I could give that a try. I will let you know if I end up with the same result.
Here is the actual error that I keep getting whenever a value is selected (i.e. Water).
ERROR 000800 The value is not a member of Sewer | Stormwater | Lidar.
It looks like the validation is called again by some other trigger deep in the innerworkings of the script tool and since it is no longer part of that list that filter is validating against, it invalidates.
WPF comboboxes does the same type of behavior and will fire actions multiple times on a single click or value change and it takes some backend code to work with it.
You need to add a handler to break out of that cycle. Maybe another class property that stores the previous value and when the method is called again, will check if the value has changed and if not, doesnt try to validate against the filter list again. This is untested, but is something similar to how I worked out the comboboxes firing multiple times on the same value.
def __init__(self):
"""Setup arcpy and the list of tool parameters."""
self.params = arcpy.GetParameterInfo()
self.previous_selection = None
# Update parameter 3 value list
Selected_value = parameters[3].valueAsText
# test if the value has changed from the previous selection and return if its the same
if Selected_value != self.previous_selection:
if Selected_value is None:
parameters[3].filter.list = Export_values
...
# set the previous selection value:
self.previous_selection = Selected_value
Hi @Anonymous User,
I tried your suggestion but the tool either raised an error or there were no values to select. There is another work around that I have thought about that I could give a try. That workaround involving multiple parameters with yes or no values. But I am hoping there is an option for ensuring that only remaining values remain when a value is selected from a list of values.
So if the parameter value is 'Water', want to remove 'Water' from the parameter's filter list? That won't work. The selected value always has to be a member of the filter list or else you get the ERROR 00800. Or maybe I'm not understanding it right...
Hi @DonMorrison1,
When I select a single value, then the error would arise. However, if I were to select two values, the error wouldn't arise despite multiple selected values. I managed to set it and get the behavior to change so the error wouldn't persist but it was only occurring if multiple values were selected.
Ah - it's a multivalue parameter - you can read about my struggles here (not related to your problem). When I run into something like this I try to reduce the code down to the absolute bare minimum to reproduce the problem, then start adding print statements so I can see what is going on. For instance, if you remove parameters 1 and 2 can do you still get the error? Also, it would be useful to see the code in your getParametersInfo function.
Here is what I have thus far. I can easily configure everything else for when the script runs, but I am trying to setup some limitations so that the end user doesn't continuous select information and/or duplicate information. Figuring out how to set limitations based on available values is something that seems easier said than done. I thought, perhaps, to even use a table of values and set each value to only a unique selectable value.
# -*- coding: utf-8 -*-
import arcpy
import sys
import os
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 = "Tool"
self.description = ""
self.canRunInBackground = False
def getParameterInfo(self):
"""Define parameter definitions"""
Select_Folder = arcpy.Parameter(
displayName = "Select Output Folder",
name = "Output_Folder",
datatype = "DEType",
parameterType = "Required",
direction = "Input")
Grid_Index = arcpy.Parameter(
displayName = "Input Grids Feature",
name = "TileIndex",
datatype = "DEFeatureClass",
parameterType = "Required",
direction = "Input")
Select_Grids = arcpy.Parameter(
displayName = "Select Grids",
name = "Select_Grids",
datatype = "GPString",
parameterType = "Required",
direction = "Input",
multiValue = True)
Select_DataExport = arcpy.Parameter(
displayName = "Select Data To Export",
name = "Select_DataExport",
datatype = "GPString",
parameterType = "Required",
direction = "Input",
multiValue = True)
Select_WaterSewerDatabases = arcpy.Parameter(
displayName="Input Databases (Water & Sewer)",
name = "Select_Databases",
datatype = "DEType",
parameterType = "Optional",
direction = "Input",
enabled = False)
Select_StormwaterDatabases = arcpy.Parameter(
displayName="Input Databases (Stormwater)",
name = "Select_Databases",
datatype = "DEType",
parameterType = "Optional",
direction = "Input",
enabled = False)
LidarGridsFolder = arcpy.Parameter(
displayName = "Lidar Grids Folder",
name = "LidarTilesFolder",
datatype = "DEType",
parameterType = "Optional",
direction ="Input",
enabled = False)
LidarGrids = arcpy.Parameter(
displayName = "Input Lidar Grids",
name = "LidarTiles",
datatype = "DEType",
parameterType = "Optional",
direction = "Input",
enabled = False)
parameters = [Select_Folder, Grid_Index, Select_Grids, Select_DataExport, Select_WaterSewerDatabases, Select_StormwaterDatabases, LidarGridsFolder, LidarGrids]
return parameters
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 parameter 2 values from list generated from parameter 1 input
feature_class = parameters[1].value
TileNumber_field = [field.name for field in arcpy.ListFields(feature_class) if field.name == 'TILE_NUMBER']
scur = arcpy.da.SearchCursor(feature_class, TileNumber_field)
parameters[2].filter.list = [row[0] for row in scur]
Export_values = ['Water', 'Sewer', 'Stormwater', 'Lidar']
parameters[3].filter.list = Export_values
# Update either parameter 4, 5, 6, 7 depending on parameter 3 value
if parameters[3].valueAsText is None:
pass
elif parameters[3].valueAsText in Export_values[:2]:
parameters[4].enabled = True
if parameters[6].enabled:
parameters[7].enabled = True
return
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."""
## # Input parameters for tool processing
## folder_path = parameters[0].valueAsText
## Grids = parameters[2].valueAsText
## Water_Sewer_Databases = parameters[4].valueAsText
## Stormwater_Databases = parameters[5].valueAsText
## LidarFolder = parameters[6].valueAsText
##
## # Values for intermediate processing or outputs
## new_folder = ''
## Export_GDB = ''
##
## namefolder = os.path.join(folder_path, 'DataExportFolder')
## Export_GDB_name = os.path.join(new_folder, 'Export')
##
## for root, directories, files in os.walk(folder_path):
## if os.path.exists(namefolder) == True:
## new_folder = namefolder
## else:
## new_folder = os.mkdir(namefolder)
##
## for root, directory, file in os.walk(new_folder):
## if Project in os.path.join(root, file):
## pass
## else:
## Export_GDB = arcpy.management.CreateFileGDB(new_folder, Export_GDB_name)
return
If I understand what you are trying to do, I usually accomplish it by a displaying set of checkboxes that dictate which input fields to display. The example below might seem like overkill but the code is pretty simple - you just have to set up the mapping of checkboxes to input parameters correctly.
def getParameterInfo(self):
cb_0 = arcpy.Parameter(displayName="Checkbox 0", name="cb_0", datatype="GPBoolean", parameterType="Required", direction="Input")
cb_1 = arcpy.Parameter(displayName="Checkbox 1", name="cb_1", datatype="GPBoolean", parameterType="Required", direction="Input")
cb_2 = arcpy.Parameter(displayName="Checkbox 2", name="cb_2", datatype="GPBoolean", parameterType="Required", direction="Input")
in_0 = arcpy.Parameter(displayName="Input 0", name="in_0", datatype="GPString", parameterType="Optional", direction="Input")
in_1 = arcpy.Parameter(displayName="Input 1", name="in_1", datatype="GPString", parameterType="Optional", direction="Input")
in_2 = arcpy.Parameter(displayName="Input 2", name="in_2", datatype="GPString", parameterType="Optional", direction="Input")
in_3 = arcpy.Parameter(displayName="Input 3", name="in_3", datatype="GPString", parameterType="Optional", direction="Input")
in_4 = arcpy.Parameter(displayName="Input 4", name="in_4", datatype="GPString", parameterType="Optional", direction="Input")
return [cb_0, cb_1, cb_2, in_0, in_1, in_2, in_3, in_4]
def updateParameters(self, parameters):
# Parameter indexes
CB_0 = 0
CB_1 = 1
CB_2 = 2
IN_0 = 3
IN_1 = 4
IN_2 = 5
IN_3 = 6
IN_4 = 7
# Map checkbox parameter to visible input parameters
TBL = {CB_0: [IN_0],
CB_1: [IN_1, IN_2],
CB_2: [IN_2, IN_3, IN_4]}
# Update parameter visibility
for p_in in range (IN_0, IN_4 + 1):
parameters[p_in].enabled = False
for p_cb in [p for p in range (CB_0, CB_2+1) if parameters[p].value == True]:
for p_in in TBL[p_cb]:
parameters[p_in].enabled = True
return