Here's the script I used for debugging my Tool Validator code. Since it is tested outside ArcMap, there are some modifications that are necessary. For example, a full path to the feature containing your PINs is needed.
# HELP at http://desktop.arcgis.com/en/arcmap/latest/analyze/creating-tools/debugging-a-toolvalidator-class.htm
import arcpy
# Load the toolbox and get the tool's parameters, using the tool
# name (not the tool label).
#
arcpy.ImportToolbox(r"C:\Path\to\toolbox.tbx") # toolbox location
params = arcpy.GetParameterInfo("SearchParcel") # name of script (not tool label)
# Set required parameters
#
params[0].value = r"C:\Path\to\geodatabase.gdb\PARCELS_BASE" # feature layer
# params[1].value = '0401' # first part of PIN
# params[2].value = '02' # middle part of PIN
# ToolValidator class block
# ----------------------------------------------------------------
class ToolValidator(object):
def __init__(self):
import arcpy
self.params = arcpy.GetParameterInfo()
def initializeParameters(self):
# (initializeParameters code here)
return
def updateParameters(self):
if self.params[0].value: # feature has been selected
useFields = ['PIN'] # name of field used by tool (parcel identification number - a string)
desc = arcpy.Describe(self.params[0].value) # information about the input feature
print(desc.dataType) # # Debug # #
fieldNames = { f.name: f.type for f in desc.fields } # dictionary used to keep field names and types together
print(fieldNames) # # Debug # #
if set(useFields).issubset(fieldNames.keys()): # all fields were found by tool
print("Field found in feature class") # # Debug # #
# NOTE: If feature has selections, only the selections will be searched
fc, fld = str(self.params[0].value), useFields
self.params[1].filter.list = sorted(set([f[0][:4] for f in arcpy.da.SearchCursor(fc,fld)]))
if self.params[1].value not in self.params[1].filter.list:
self.params[1].value = self.params[1].filter.list[0]
print(self.params[1].filter.list[0]) # # Debug # #
print(len(self.params[1].filter.list)) # # Debug # #
print(self.params[1].filter.list) # # Debug # #
where_1 = "PIN LIKE '{}%'".format(self.params[1].value)
print(where_1) # # Debug # #
self.params[2].filter.list = sorted(set([f[0][5:7] for f in arcpy.da.SearchCursor(fc,fld,where_1)]))
if self.params[2].value not in self.params[2].filter.list:
self.params[2].value = self.params[2].filter.list[0]
print(self.params[2].filter.list[0]) # # Debug # #
print(len(self.params[2].filter.list)) # # Debug # #
print(self.params[2].filter.list) # # Debug # #
where_2 = "PIN LIKE '{} {}%'".format(self.params[1].value, self.params[2].value)
print(where_2) # # Debug # #
self.params[3].filter.list = sorted(set([f[0][8:] for f in arcpy.da.SearchCursor(fc,fld,where_2)]))
if self.params[3].value not in self.params[3].filter.list:
self.params[3].value = self.params[3].filter.list[0]
print(self.params[3].filter.list[0]) # # Debug # #
print(len(self.params[3].filter.list)) # # Debug # #
print(self.params[3].filter.list) # # Debug # #
# output completed whereClause
self.params[4].value = "PIN = '{} {} {}'".format(self.params[1].value, self.params[2].value, self.params[3].value)
print(self.params[4].value) # # Debug # #
else: # at least one of the field names does not exist in feature; using the parameter to hold an error message
if 'PIN' not in fieldNames.keys():
self.params[1].value = "ERROR: Field 'PIN' not in selected feature class."
print(self.params[1].value) # # Debug # #
return
def updateMessages(self):
self.params[0].clearMessage()
self.params[1].clearMessage()
self.params[2].clearMessage()
self.params[3].clearMessage()
if self.params[0].value is not None: # set error message if field not in feature so user can correct problem
if self.params[1].value is not None:
if self.params[1].value.startswith("ERROR:"):
self.params[1].value = None # clear error message in parameter value, if desired
self.params[2].value = None
self.params[3].value = None
self.params[0].setErrorMessage("Field '{}' is not in Input FC '{}'".format('PIN', self.params[0].value))
print('Setting message 0') # # Debug # #
return
# ----------------------------------------------------------------
# Call routine(s) to debug
#
validator = ToolValidator()
validator.updateParameters()
validator.updateMessages()
print('\n')
for p in params:
print(p.name, p.datatype, p.parameterType, p.direction, p.value)
print('\n')
# tool script (modified for debugging):
inFC = params[0].value # arcpy.GetParameterAsText(0) # input feature class (Input, Data Type 'Feature Layer')
PIN_a = params[1].value # arcpy.GetParameterAsText(1) # PIN[:4] (Input, Data Type 'String')
PIN_b = params[2].value # arcpy.GetParameterAsText(2) # PIN[5:7] (Input, Data Type 'String')
PIN_c = params[3].value # arcpy.GetParameterAsText(3) # PIN[8:] (Input, Data Type 'String')
whereClause = params[4].value # arcpy.GetParameterAsText(4) # set by ToolValidator updateParameters (Output, Derived, Data Type 'String')
arcpy.AddMessage("Where clause used: {}".format(whereClause))
print("Where clause used: {}".format(whereClause)) # # Debug # #
# convert inFC to feature layer since we are outside arcmap
arcpy.MakeFeatureLayer_management(inFC,'inFC_layer')
# use layer created
arcpy.SelectLayerByAttribute_management('inFC_layer', "NEW_SELECTION", where_clause=whereClause)
for i in range(arcpy.GetMessageCount()): # display messages from SelectLayerByAttribute tool
arcpy.AddMessage(arcpy.GetMessage(i))
# print messages created by SelectLayers
print(arcpy.GetMessages()) # # Debug # #
n = arcpy.GetCount_management(inFC)
arcpy.AddMessage("Number of records selected: {}".format(n))
print("Number of records selected: {}".format(n)) # # Debug # #
You will notice that I've added some print statements inside the Tool Validator. Normally I wouldn't try to debug the tool's script while working on the validator's code, but it can be placed at the bottom and will need some modification. Even then, you may get some unexpected results.
For testing the params (just before the validator class), I started with just the feature and added parts of the PIN to see what changes this would make.
Hope this helps.