Unfortunately, programming python toolboxes is not very well documented by Esri. I can't find any good examples anywhere of what a fully, completed toolbox with validation and source code should look like. It also seems like "parameters" and "messages" behave as magic arcpy variables that don't need to be expressly instantiated; I'm having trouble finding explicit guidance/documentation on that.
Either way, could someone who has done this take a look at my code and help me understand why it's failing?
The validation code works just fine, but every time I run it, it yields the somewhat cryptic error 000820: The parameters need repair.
import arcpy
class Toolbox(object):
def __init__(self):
self.label = "ToolboxTest"
self.alias = ""
self.tools = [DummyTool]
class DummyTool(object):
def __init__(self):
self.label = "DummyTool"
self.description = "A dummy tool"
self.canRunInBackground = False
def getParameterInfo(self):
p = arcpy.mp.ArcGISProject('CURRENT')
m = p.activeMap
param0 = arcpy.Parameter(
displayName="Choice One",
name="input_choice_1",
datatype="GPLayer",
parameterType="Required",
direction="Input"
)
poly_list = [] # list only polygon feature layers
for lyr in m.listLayers():
desc = arcpy.Describe(lyr)
if desc.dataType == "FeatureLayer":
if desc.shapeType == "Polygon":
poly_list.append(lyr.name)
param0.filter.type = "ValueList"
param0.filter.list = poly_list
params = [param0]
return params
def isLicensed(self):
return True
def updateParameters(self, parameters):
pass
def updateMessages(self, parameters):
return True
def execute(self, parameters, messages):
# All I want to do here is just access
# the parameter value and report some
# facts about it for testing
self.updateParameters(parameters)
lyr = parameters[0].value
d = arcpy.Describe(lyr)
arcpy.AddMessage(d.name)
arcpy.AddMessage(d.dataType)
arcpy.AddMessage(d.shapeType)
Solved! Go to Solution.
I was able to get it to work by changing the data type of the input variable from GPLayer to GPString. I have no idea why, but this is typical with toolbox programming in that you just have to keep trying things until you find something that works. I guess in a way it makes sense since you really are just setting it to a string and not a layer object. On line 28 you also have to initialize the variable (eg poly_list = []). Good luck on your tool, the fun is just beginning 😉
Sorry, I should have tested it...
It works with datatype GPFeatureLayer and not setting the filter type.
I edited the post above accordingly for future reference.
I was able to get it to work by changing the data type of the input variable from GPLayer to GPString. I have no idea why, but this is typical with toolbox programming in that you just have to keep trying things until you find something that works. I guess in a way it makes sense since you really are just setting it to a string and not a layer object. On line 28 you also have to initialize the variable (eg poly_list = []). Good luck on your tool, the fun is just beginning 😉
Hi Don, your suggestion worked, (and I did instantiate the list, I just failed to put it in the example) but this part:
this is typical with toolbox programming in that you just have to keep trying things until you find something that works
is what is so frustrating.... show me the book I'll buy it, or tell me which class to attend and I'll register for it - it's the poking around in the dark that is so maddening!!
Still this did work so thanks 🙂
You could do it like this:
class DummyTool
def getParameterInfo(self):
param0 = arcpy.Parameter(
displayName="Choice One",
name="input_choice_1",
datatype="GPFeatureLayer",
parameterType="Required",
direction="Input"
)
param0.filter.list = ["Polygon"]
params = [param0]
return params
Hi @JohannesLindner that just gives me one option in the parameter drop-down called "Polygon." What I'm looking for is a filter list of only the Polygon type feature layers
Sorry, I should have tested it...
It works with datatype GPFeatureLayer and not setting the filter type.
I edited the post above accordingly for future reference.
Hi EricEagle,
There is a bug in your code at line 28, where you did not set polylist to any value. Set this to an empty list and your code works for me.
poly_list = [] # list only polygon feature layers
Alternative Solution
*Edit* JohannesLinder beat me to this solution while I was writing this out =D. I'll leave it below here anyways:
You can accomplish what you are trying to do more concisely by changing dataType to "GPFeatureLayer". You can then choose a "Featureclass" filter type. Note that the default filter type for GPFeatureLayer is "Featureclass", so there is actually no need to explicitly specify this as in the example below. You can safely omit the line param0.filter.type = "Featureclass".
param0 = arcpy.Parameter(
displayName="Choice One",
name="input_choice_1",
datatype="GPFeatureLayer",
parameterType="Required",
direction="Input"
)
param0.filter.type = "Featureclass"
param0.filter.list = ["Polygon"]
Here it is in action:
Also note that you won't be able to do the same with the GPLayer data type. The reason GPLayer doesn't have a data filter type is because GPLayer is for any Layer (which includes tables, raster, etc.) and GPFeatureLayer is explicitly only the subset of Layers with features (Feature Class, Shapefile).
More Info
You can find this in the doc here.
There's an example of a fully fleshed out Python toolbox here, though it doesn't cover your exact case (it'd be difficult to cover every case in the doc).
Also, check out recent presentations on creating toolboxes here, where parts of this topic are covered (haven't watched this one in a while, it might not cover your exact use case but might provide some more insights).
Hope this helps!
@HannesZieglerVery helpful - thanks for all the resources. In the original code, I did instantiate the poly_list variable, but I wrote this on another network and messed up when retyping it here.
I really like the ability that toolboxes give me to maintain 100% of my code in git and not having to worry about updating/moving around .tbx files. It's not practical for every case but feels like a lot cleaner way to work.