[GIS] ArcGIS Python Tool – Importing Custom Script Into ToolValidator Class

arcgis-10.0geoprocessingpython

I had posted a question last week about customizing a ToolValidator class and got some very good answers. In working with the proposed solutions, I have created a custom module that performs queries on a db, and will be called by both the ToolValidator class (to provide values for the drop-down lists) and later in the geoprocessing script (to get other parameters based on items selected in drop-down lists). However, I can't seem to actually call the custom module in the ToolValidator class. I have been trying to append to path with no luck. When I try to apply these changes to the script, I get a runtime error: [Errno 9] Bad file descriptor. If I comment out import line, no errors.

sys.path.append('my_custom_module_directory')
import my_custom_module

Many of you may be asking why don't I just implement a custom tool with ArcObjects. The reason is that my end users don't have the privleges necessary to register ANY dlls on their computer.

UPDATE: This was happening to me in ArcGIS 10. Interestingly enough, I was initially appending to the path inside of the initialiazeParameters function of the ToolValidator class. If I do the append outside (i.e., on top of) of the ToolValidator class, everything works as expected.

sys.path.append('C:/Working/SomeFolder')
import somescript -------->THIS WORKS

class ToolValidator:
  """Class for validating a tool's parameter values and controlling
  the behavior of the tool's dialog."""

  def __init__(self):
    """Setup arcpy and the list of tool parameters."""
    import arcpy
    sys.path.append('C:/Working/SomeFolder')
    import somescript -------> THIS DOESNT WORK
    self.params = arcpy.GetParameterInfo()

UPDATE 2: I think I found the true cause of my problem. In the code snippets in this post, I have been appending what appear to be real paths (ex C:/Working/SomeFolder) to the sys.path. In my actual ToolValidator class, I was constructing a relative path using os.path.dirname(__file__) +"\my_special_folder…". I was anticipating that os.path.dirname(__file__) would return the path of the toolbox, since that contains the ToolValidator class. I have come to find this is not the case. As far as I can tell, the ToolValidator class is never actually written to a .py file, and I speculate the the this code is passed to the python interpreter in memory, so __file__ is useless, or some temp script is persisted and then execfile(path_to_script) is called, again rendering __file__ useless. I'm sure there are other reasons I am missing as well.

Long story short, if I use a hardcoded path, the sys.append works anywhere, relative paths don't work so well in the ToolValidator class.

Best Answer

The way I do this is, after starting ArcGIS or ArcCatalog, first run a dummy tool ("Run this once") calling a dummy.py script. After doing that you can import python scripts in the validator by using sys.argv[0]. This will point to the folder where the first script was located. Thereafter you can import the needed script in de Validator Class.

The dummy.py script called by "Run this once" tool:

import arcgisscripting, sys, os
gp = arcgisscripting.create(9.3)

# set up paths to Toolshare, scripts en Tooldata
scriptPath = sys.path[0]  
toolSharePath = os.path.dirname(scriptPath)
toolDataPath = toolSharePath + os.sep + "ToolData"
gp.addmessage("scriptPath: " + scriptPath)
gp.addmessage("toolSharePath: " + toolSharePath)
gp.addmessage("toolDataPath: " + toolDataPath)

# Use this to read properties, VERY handy!!
import ConfigParser
config = ConfigParser.SafeConfigParser()
config.readfp(open(scriptPath + os.sep + 'properties.ini'))
activeOTAP = config.get('DEFAULT', 'activeOTAP')
activeprojectspace = config.get('DEFAULT', 'activeprojectspace')
activeproject = config.get('DEFAULT', 'activeproject')
activesdeconnection = config.get('DEFAULT', 'activesdeconnection')

Sorry, can't get the formatting right Regards, Maarten Tromp

Related Question