Remove items from list in python toolbox tool

939
4
Jump to solution
08-11-2022 10:40 AM
WadeWall
Occasional Contributor

Hi all,

I am trying to create an ArcGIS Pro python tool that prepopulates a list with field names from an imported shapefile. I want to be able to delete field names from the list, but the tool I have created won't allow it. I am guessing that I need to add some type of update part to the script, but just not sure. In the tool, a red "X" appears next to each field name, but when clicked does not actually delete the field name. Any help would be appreciated. here is the tool as it currently exists:

class FieldNames(object):
    def __init__(self):
        """Define the tool (tool name is the name of the class)."""
        self.label = "FieldNames"
        self.description = ""
        self.canRunInBackground = False

    def getParameterInfo(self):
        """Define parameter definitions"""
        
        fc = arcpy.Parameter(
            displayName="fc",
            name="fc",
            datatype="GPFeatureLayer",
            parameterType="Required",
            direction="Input")
       names = arcpy.Parameter(
            displayName="field names",
            name="fields",
            datatype="GPString",
            parameterType="Required",
            direction="Input"
        )
        names.parameterDependencies = [fc.name]
        names.multiValue = True
                       
                
        params = [fc,names]
        
        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."""
        # This comes from here https://gis.stackexchange.com/questions/330672/deriving-field-parameter-from-table-parameter-in-python-toolbox
        
        if parameters[0].altered:
            parameters[1].values = [field.name for field in arcpy.ListFields(parameters[0].valueAsText)]
            
        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."""
        # sat = parameters[0]
        fc = parameters[0].valueAsText
        fields = parameters[1].valueAsText
        
        return
0 Kudos
1 Solution

Accepted Solutions
JohannesLindner
MVP Frequent Contributor

Yeah, Python toolboxes have some weird quirks you have to work around.

Personally, I've never gotten Parameter.altered to work. I always do the check myself by comparing the current parameter value to the previous value stored in a variable. But it doesn't work with a variable of the Tool class. Something to do with the internal conversion into C code, I guess. My workaround for this:

Create an empty class in the toolbox file. Use this class to store variables from your tool classes:

# Toolbox.pyt

class ABC():
    """This class is used to store tool variable."""
    pass


class FieldNames(object):
    def __init__(self):
        self.label = "FieldNames"
        self.description = ""
        self.canRunInBackground = False

    def getParameterInfo(self):
        fc = arcpy.Parameter(
            displayName="fc",
            name="fc",
            datatype="GPFeatureLayer",
            parameterType="Required",
            direction="Input")

        names = arcpy.Parameter(
            displayName="field names",
            name="fields",
            datatype="GPString",
            parameterType="Required",
            direction="Input"
            )
        names.multiValue = True

        # set the variable. Doesn't work with self!
        ABC.fc = ""
                       
        params = [fc,names]
        return params

    def isLicensed(self):
        return True

    def updateParameters(self, parameters):
        # instead of Parameter.altered, do the check yourself
        if ABC.fc != parameters[0].valueAsText:
            ABC.fc = parameters[0].valueAsText
            parameters[1].values = [field.name for field in arcpy.ListFields(ABC.fc)]

    def updateMessages(self, parameters):
        return

    def execute(self, parameters, messages):
        fc = parameters[0].valueAsText
        fields = parameters[1].valueAsText
        arcpy.AddMessage(f"fc: {fc}")
        arcpy.AddMessage(f"fields: {fields}")

	
class Toolbox(object):
    def __init__(self):
        self.label = "test"
        self.alias = "test"
        self.tools = [FieldNames]

Have a great day!
Johannes

View solution in original post

4 Replies
DanPatterson
MVP Esteemed Contributor

Code formatting ... the Community Version - Esri Community

will get rid of the sad faces and provide code line numbers


... sort of retired...
WadeWall
Occasional Contributor

Thanks. I will follow the rules next time!

0 Kudos
JohannesLindner
MVP Frequent Contributor

Yeah, Python toolboxes have some weird quirks you have to work around.

Personally, I've never gotten Parameter.altered to work. I always do the check myself by comparing the current parameter value to the previous value stored in a variable. But it doesn't work with a variable of the Tool class. Something to do with the internal conversion into C code, I guess. My workaround for this:

Create an empty class in the toolbox file. Use this class to store variables from your tool classes:

# Toolbox.pyt

class ABC():
    """This class is used to store tool variable."""
    pass


class FieldNames(object):
    def __init__(self):
        self.label = "FieldNames"
        self.description = ""
        self.canRunInBackground = False

    def getParameterInfo(self):
        fc = arcpy.Parameter(
            displayName="fc",
            name="fc",
            datatype="GPFeatureLayer",
            parameterType="Required",
            direction="Input")

        names = arcpy.Parameter(
            displayName="field names",
            name="fields",
            datatype="GPString",
            parameterType="Required",
            direction="Input"
            )
        names.multiValue = True

        # set the variable. Doesn't work with self!
        ABC.fc = ""
                       
        params = [fc,names]
        return params

    def isLicensed(self):
        return True

    def updateParameters(self, parameters):
        # instead of Parameter.altered, do the check yourself
        if ABC.fc != parameters[0].valueAsText:
            ABC.fc = parameters[0].valueAsText
            parameters[1].values = [field.name for field in arcpy.ListFields(ABC.fc)]

    def updateMessages(self, parameters):
        return

    def execute(self, parameters, messages):
        fc = parameters[0].valueAsText
        fields = parameters[1].valueAsText
        arcpy.AddMessage(f"fc: {fc}")
        arcpy.AddMessage(f"fields: {fields}")

	
class Toolbox(object):
    def __init__(self):
        self.label = "test"
        self.alias = "test"
        self.tools = [FieldNames]

Have a great day!
Johannes
WadeWall
Occasional Contributor

I am not sure how you figured that out, but thanks a lot. I would have never arrived at this for a solution.

0 Kudos