Refresh default values in GPValue table parameter in Python toolbox

2617
3
06-05-2014 02:48 PM
MarshallUdo
New Contributor
I am working in ArcGIS 10.1 SP 1 on Windows Server 2008 R2 Enterprise.

I created a python toolbox that is opened from a python addin and displays records from a feature class in a value table. It allows users to change values (by reordering the records)  or delete records in that feature class.  I would like the tool to open and display the records that are currently in the feature class.  It does this the first time it is opened and completes the edits,  however, when I launch the tool again, the value table does not refresh to reflect the changes to the feature class.  Instead, the records(and their values) that were in the feature class prior to any changes and tool execution are shown in the value table.

I have tried calling the getParameterInfo() method from various places in the code with no luck. 

The only way I can get it to update is to manually refresh the python toolbox in ArcCatalog.  Any help is appreciated. 

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 = ""
        # List of tool classes associated with this toolbox
        self.tools = [ReorderPages]


class ReorderPages(object):
    # TODO How to refresh parameter list
    def __init__(self):
        """Define the tool (tool name is the name of the class)."""
        self.label = "Reorder Pages"
        self.description = ""
        self.canRunInBackground = False

    def getParameterInfo(self):
        """Define parameter definitions"""
        params = []
        mxd = arcpy.mapping.MapDocument("CURRENT")
        param0 = arcpy.Parameter(
            displayName = 'Pages',
            name = 'pages',
            datatype = 'GPValueTable',
            parameterType = 'Optional',
            direction = 'Input'
            )
        param0.columns = [['String', 'Map Page']]
        gridFc = os.path.dirname(mxd.filePath) + r"\SourceData.gdb\Grid_Index"
        param0.values = sorted([[r[0] + " pg. " + str(r[1])] for r in arcpy.da.SearchCursor(gridFc, ["MXD_NAME", "PAGE_NUM"])])
        params = [param0]
        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."""
        pass

    def updateMessages(self, parameters):
        """Modify the messages created by internal validation for each tool
        parameter.  This method is called after internal validation."""
        pass

    def getNewIndex(self, map_name, pos_list):
        # Get a single map name and the updated position list from the user
        # to create a dictionary holding the map names (e.g. "Timber Sales Map pg. 1")
        # and the user specified position relative to other maps of the same name.
        # The format will be {"Timber Sales Map pg. 1: 3, "Timber Sales Map pg. 2: 2, ...}
        list_by_map = [mp.strip("'") for mp in pos_list if mp and re.match(map_name, mp)]
        dict_by_map = {m: list_by_map.index(m) + 1 for m in list_by_map}
        return dict_by_map

    def getMapNames(self, index_feature):
        search_nms = arcpy.da.SearchCursor(index_feature, ["MXD_NAME"])
        names = []
        for record in search_nms:
            names.append(record[0])
            map_list = list(set(names))
        del record, search_nms, names
        return map_list

    def updateIndex(self, index_feature, pos_list):
        map_set = self.getMapNames(index_feature)
        for mp in map_set:
            expr = "MXD_NAME = '" + mp + "'"
            new_pos = self.getNewIndex(mp, pos_list)
            update_indx = arcpy.da.UpdateCursor(index_feature, ["MXD_NAME", "PAGE_NUM"], expr)
            for ind_rec in update_indx:
                map_page = ind_rec[0] + " pg. " + str(ind_rec[1])
                if map_page in pos_list:
                    ind_rec[1] = new_pos[map_page]
                    update_indx.updateRow(ind_rec)
                else:
                    update_indx.deleteRow()
            del ind_rec, update_indx
        del map_set

    def execute(self, parameters, messages):
        """The source code of the tool."""
        new_list = parameters[0].valueAsText
        pg_list = new_list.split(";")
        pg_clean = [m.strip("'") for m in pg_list]
        mxd = arcpy.mapping.MapDocument("CURRENT")
        path = os.path.dirname(mxd.filePath)
        grid_fc = path + r"\SourceData.gdb\Grid_Index"
        self.updateIndex(grid_fc, pg_clean)
        del mxd, new_list, pg_list, pg_clean, grid_fc, path
Tags (2)
0 Kudos
3 Replies
JasonScheirer
Occasional Contributor III
It's only refreshed in the updateParameters() method. Add this to it:

gridFC = os.path.dirname(arcpy.mapping.MapDocument("CURRENT").filePath) + r"\SourceData.gdb\Grid_Index"
parameters[0].values = sorted([[r[0] + " pg. " + str(r[1])] for r in arcpy.da.SearchCursor(gridFc, ["MXD_NAME", "PAGE_NUM"])])
0 Kudos
MarshallUdo
New Contributor
Thanks Jason.  I tried your suggestion, but it did not give me the behavior I was looking for.  I want the user to be able to manipulate the records in the value table (reorder, delete) and then execute the tool with their changes as input to the tool.  The updateParameters() method is called any time the user changes the value table, and their changes are lost when the feature class is used to update the value table.  I have a regular script tool that uses a ToolValidator class, and what I'm looking for is the same functionality provided by the initializeParameters() method, but in my python toolbox.  I chose to use a python toolbox because, at 10.1, it was the only way to use a value table, but I am open to other suggestions.
0 Kudos
MarshallUdo
New Contributor
I thought I would post a possible solution to my issue (not thoroughly tested).  I used Jason's suggestion to update the parameter in the updateParameters method, but I added a test so changes that users make to the parameter persist until the tool is executed.

if not parameters[0].altered and parameters[0].value and parameters[0].values <> a_list_of_vals_from_feature_class:
            parameters[0].values = a_list_of_vals_from_feature_class
0 Kudos