Python toolbox - some strange behaviours

914
2
Jump to solution
04-08-2014 02:36 PM
ColinLang
New Contributor III
I am trying to build a python toolbox.  See the attached file (just turn the .py extension .pyt)

I am having a couple of issues:

1.  I get error messages that the parameters[1].valueAsText property doesn't exist on my multivalue parameter, but I found on a forum once the exportToString() method that I'm using and it seems to work.  The .value property comes accross as empty if I try to access it directly.

2.  When I try to Add my toolbox to the ArcToolbox window in ArcGIS, it shows an X on it in the browse window, which should indicate a code error that prevents it from loading, however, when I comment out all the code in the execute routine, load it, uncomment out the code, re-save the file and right-click --> refresh in the ArcToolbox, it loads just fine and runs.  So there are no code errors that should prevent it from loading in the first place.

3.  I'm using a cursor.  According to the documentation on those, using the WITH command should eliminate the need to do garbage cleanup to release the locks on the data, however that didn't seem to be the case.  I tried adding commands to set the row and the cursor to None after they were not needed, but that didn't help.  The behaviour I get is that the first run works fine, but on the second run, the layer I ran it on the first time doesn't appear in the layer list on the parameters dialog.  It's like it knows it's locked and can't use it, so it decides not to display it.

For those who like to know such things, I'm running ArcMap 10.1 SP1 for Desktop, Build 3143, on Windows 7 SP1, on a Dell Optiplex 990, with 16 GB of RAM, and two Intel i7-2600, 3.40 GHz cores.


Any help or suggestions would be greatly appreciated.  I'm getting pretty frustrated right now.
Tags (2)
0 Kudos
1 Solution

Accepted Solutions
ColinLang
New Contributor III
Thanks Doug.  Your tips helped.  Eventually I had to put the cursor operation into an edit session, to get the dissappearing layer in the layer list issue solved.  For those who are curious here is the final code:

import arcpy   class Toolbox(object):      def __init__(self):         """Define the toolbox (the name of the toolbox is the name of the         .pyt file)."""         self.label = "Set Values for Multiple Fields"         self.alias = "SetValues"          # List of tool classes associated with this toolbox         self.tools = [SetValues]   class SetValues(object):     def __init__(self):         """Define the tool (tool name is the name of the class)."""         self.label = "Set Values"         self.description = "Sets values for many fields to one value, for all selected features"         self.canRunInBackground = False      def getParameterInfo(self):         """Define parameter definitions"""         params = None          param0 = arcpy.Parameter(             displayName="Choose Layer",             name="layer",             datatype="GPLayer",             parameterType="Required",             direction="Input")          param1 = arcpy.Parameter(             displayName="Choose Fields",             name="field_list",             datatype="Field",             parameterType="Required",             direction="Input",             multiValue=True)         param1.parameterDependencies = [param0.name]          param2 = arcpy.Parameter(             displayName="Value to Set",             name="set_value",             datatype="GPLong",             parameterType="Required",             direction="Input")          mxd = arcpy.mapping.MapDocument("CURRENT")         layerlist = []         layerlist = arcpy.mapping.ListLayers(mxd)          param0.filter.list = []         param0.filter.type = "ValueList"         for layer in layerlist:             param0.filter.list += [layer.name]          params = [param0, param1, param2]          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."""         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."""          param0 = parameters[0].value         param1 = parameters[1].value.exportToString()         param2 = parameters[2].value          #arcpy.AddError(param0)         #arcpy.AddError(param1)         #arcpy.AddError(param2)          mymxd = arcpy.mapping.MapDocument("CURRENT")         selectedlayer = arcpy.mapping.ListLayers(mymxd, param0)[0]         workspace = "C:\Users\Public\Documents"  # never used, just needed a folder that would always exist on any computer, and have write access.         # Start an edit session. Must provide the worksapce.         edit = arcpy.da.Editor(workspace)         # Edit session is started without an undo/redo stack for versioned data         #  (for second argument, use False for unversioned data)         edit.startEditing(True)          # Start an edit operation         edit.startOperation()          #param1 = "test2;test3"         param1list = param1.split(";")         fieldnamelist = []         for fieldname in param1list:             fieldnamelist += [fieldname]          setvalue = param2          with arcpy.da.UpdateCursor(selectedlayer, fieldnamelist) as cursor:             for row in cursor:                 for index in range(len(row)):                     row[index] = setvalue                 cursor.updateRow(row)                 row = None         del cursor                         # Stop the edit operation.         edit.stopOperation()          # Stop the edit session and save the changes         edit.stopEditing(True)          return

View solution in original post

0 Kudos
2 Replies
DouglasSands
Occasional Contributor II
Since you've numbered your questions I'll try and address them in the same way:

1. Could this be related to the way you are updating the field list in the updateParameters() method? Have you tried:

class SetValues(object):
    def __init__(self):
        """Define the tool (tool name is the name of the class)."""
        self.label = "Set Values"
        self.description = "Sets the values for several fields to a set numeric value, for all features in the selection set"
        self.canRunInBackground = False

    def getParameterInfo(self):
        """Define parameter definitions"""
        params = None

        param0 = arcpy.Parameter(
            displayName="Choose Layer",
            name="layer",
            datatype="GPLayer",
            parameterType="Required",
            direction="Input")
            
        param1 = arcpy.Parameter(
            displayName="Choose Fields",
            name="field_list",
            datatype="GPString",
            parameterType="Required",
            direction="Input",
            multiValue=True)

        param1.parameterDependencies = [param0.name]



Then change updateParameters to:

    def updateParameters(self, parameters):
        return


I'm not sure if this will fix the problem, but it may be a simpler way of accomplishing what you've done.

2. Not sure about this one.

3. Instead of setting cursor to None, try:
del cursor


The with statement won't to delete the object you created. For example:

sample_file = 'C:\\New_Text_file.txt'
with open(sample_file, 'w') as f:
    f.write('Sample Text')
f


would return:


<closed file 'C:\\New_Text_file.txt', mode 'w' at 0x0000000004BAAC90>


I'm not 100% on this, but I don't think that setting the cursor variable to None will delete the object you created.



Hope this helps!
- Doug
0 Kudos
ColinLang
New Contributor III
Thanks Doug.  Your tips helped.  Eventually I had to put the cursor operation into an edit session, to get the dissappearing layer in the layer list issue solved.  For those who are curious here is the final code:

import arcpy   class Toolbox(object):      def __init__(self):         """Define the toolbox (the name of the toolbox is the name of the         .pyt file)."""         self.label = "Set Values for Multiple Fields"         self.alias = "SetValues"          # List of tool classes associated with this toolbox         self.tools = [SetValues]   class SetValues(object):     def __init__(self):         """Define the tool (tool name is the name of the class)."""         self.label = "Set Values"         self.description = "Sets values for many fields to one value, for all selected features"         self.canRunInBackground = False      def getParameterInfo(self):         """Define parameter definitions"""         params = None          param0 = arcpy.Parameter(             displayName="Choose Layer",             name="layer",             datatype="GPLayer",             parameterType="Required",             direction="Input")          param1 = arcpy.Parameter(             displayName="Choose Fields",             name="field_list",             datatype="Field",             parameterType="Required",             direction="Input",             multiValue=True)         param1.parameterDependencies = [param0.name]          param2 = arcpy.Parameter(             displayName="Value to Set",             name="set_value",             datatype="GPLong",             parameterType="Required",             direction="Input")          mxd = arcpy.mapping.MapDocument("CURRENT")         layerlist = []         layerlist = arcpy.mapping.ListLayers(mxd)          param0.filter.list = []         param0.filter.type = "ValueList"         for layer in layerlist:             param0.filter.list += [layer.name]          params = [param0, param1, param2]          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."""         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."""          param0 = parameters[0].value         param1 = parameters[1].value.exportToString()         param2 = parameters[2].value          #arcpy.AddError(param0)         #arcpy.AddError(param1)         #arcpy.AddError(param2)          mymxd = arcpy.mapping.MapDocument("CURRENT")         selectedlayer = arcpy.mapping.ListLayers(mymxd, param0)[0]         workspace = "C:\Users\Public\Documents"  # never used, just needed a folder that would always exist on any computer, and have write access.         # Start an edit session. Must provide the worksapce.         edit = arcpy.da.Editor(workspace)         # Edit session is started without an undo/redo stack for versioned data         #  (for second argument, use False for unversioned data)         edit.startEditing(True)          # Start an edit operation         edit.startOperation()          #param1 = "test2;test3"         param1list = param1.split(";")         fieldnamelist = []         for fieldname in param1list:             fieldnamelist += [fieldname]          setvalue = param2          with arcpy.da.UpdateCursor(selectedlayer, fieldnamelist) as cursor:             for row in cursor:                 for index in range(len(row)):                     row[index] = setvalue                 cursor.updateRow(row)                 row = None         del cursor                         # Stop the edit operation.         edit.stopOperation()          # Stop the edit session and save the changes         edit.stopEditing(True)          return
0 Kudos