ArcGIS Python工具-将自定义脚本导入ToolValidator类


9

我已经发布了一个问题,上周有关自定义ToolValidator类,并得到了一些很好的答案。在使用建议的解决方案时,我创建了一个自定义模块,该模块在db上执行查询,并且将由ToolValidator类(为下拉列表提供值)以及稍后在地理处理脚本(以获取其他信息)中调用参数(基于下拉列表中选择的项目)。但是,我似乎无法实际调用ToolValidator类中的自定义模块。我一直在尝试追加到没有运气的路径。当我尝试将这些更改应用于脚本时,出现运行时错误:[Errno 9]错误的文件描述符。如果我注释掉导入行,则没有错误。

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

你们中的许多人可能会问为什么我不只是使用ArcObjects实现自定义工具。原因是我的最终用户没有在计算机上注册任何dll所必需的特权。

更新:这是在ArcGIS 10中发生的。很有趣的是,我最初是附加到ToolValidator类的initialiazeParameters函数内部的路径。如果我在ToolValidator类的外部(即,在其顶部)进行附加操作,则一切都会按预期进行。

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()

更新2: 我认为我找到了造成问题的真正原因。在本文的代码段中,我一直在将看起来真实的路径(例如C:/ Working / SomeFolder)附加到sys.path中。在我实际的ToolValidator类中,我正在使用os.path.dirname(__file__)+“ \ my_special_folder ...” 构造相对路径。我预计os.path.dirname(__file__)它将返回工具箱的路径,因为其中包含ToolValidator类。我来发现并非如此。据我所知,ToolValidator类实际上从未写入过.py文件,并且我推测此代码将传递给内存中的python解释器,因此__file__是没有用的,或者持久保存了一些临时脚本,然后执行文件( path_to_script)被调用,再次渲染__file__无用。我确定还有其他原因也很想念。

长话短说,如果我使用硬编码路径,则sys.append可以在任何地方使用,相对路径在ToolValidator类中不能很好地工作。


这是9.3还是10?
詹森·谢里尔

我们无法在Esri上重现此错误,如果我们找出原因,可以向后移植10.0 SP3的修复程序。同时,我想您会坚持使用前者而不是后者的使用模式。
詹森·谢里尔

Answers:


3

我这样做的方法是,在启动ArcGIS或ArcCatalog之后,首先运行一个调用dummy.py脚本的虚拟工具(“一次运行一次”)。之后,您可以使用sys.argv [0]在验证器中导入python脚本。这将指向第一个脚本所在的文件夹。之后,您可以在de Validator类中导入所需的脚本。

“运行一次”工具调用的dummy.py脚本:

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')

抱歉,无法正确格式化问候,Maarten Tromp


3

终于破解了这个可怕的错误!例如,当您尝试应用更改以导入相对的模块或程序包时,可能会看到以下错误:

在此处输入图片说明

选项1:
仅对于开发人员,将模块的完整路径添加到PYTHONPATH。您将需要重新启动ArcMap / ArcCatalog才能生效。使用下面的代码从相对路径导入模块(用于部署)。不用担心,最终用户不需要在其PYTHONPATH变量中添加任何内容,它将起作用!

选项2:
在下面的代码中添加另一行以添加硬编码的路径,例如:sys.path.append(r“ c:\ temp \ test \ scripts”)
准备部署时,无关的目录,但这无关紧要,所有目录都应在最终用户的计算机上工作,因为添加的第一个路径是相对目录(我们的目标是跳过故障对话框)。

这两个选项通用的代码:

import os
import sys

tbxPath = __file__.split("#")[0]
srcDirName = os.path.basename(tbxPath).rstrip(".tbx").split("__")[0] + ".src" 
tbxParentDirPath =  os.path.dirname(tbxPath)
srcDirPath = os.path.join(tbxParentDirPath, srcDirName)

sys.path.append(srcDirPath)
# sys.path.append(r"c:\temp\test\scripts")  #option2

from esdlepy.metrics.validation.LandCoverProportions import ToolValidator

更新资料

告别邪恶的剪切和粘贴!我更新了代码示例,以便从库中导入ToolValidator类。首次设置工具参数时,仅剪切和粘贴一次。我将此代码段存储在要导入的ToolValidator的文档字符串中。

在此示例中,源目录名称基于tbx名称。如果您有两个带有不同源目录的工具箱,则此方法可以避免冲突。我用于源文件夹命名的标准如下:
TOOLBOXNAME__anything.tbx-> TOOLBOXNAME.src

为什么是“ __anything”?由于二进制文件无法在DVCS中合并,因此我们可以为个人分配工具,而不必担心丢失更改。最终确定工具后,将其剪切并粘贴到母版中。

我还需要访问源文件夹中的文件以填充下拉列表,请使用此方法从导入的模块中获取工具箱的路径:

import __main__
tbxPath = __main__.__file__.split("#")[0]

可能是ToolValidator代码正在设置参数的默认值吗?在脚本工具属性中检查参数的“默认值”设置。
blah238

谢谢你的建议。我检查了一下,并没有在工具箱中设置默认值...但是我确实复制了该工具箱并重命名了所有内容,并且该值仍保留在两个副本中。因此,我将放弃我的缓存想法,建议它可能实际上存储在.tbx文件中,这仍然是奇怪的行为。
MJ

2

将导入放在验证模块的顶部,在ToolValidator类之外对我来说似乎很好-我使用的是10.0 SP2。但是,除了in中,我对导入的模块什么也不做updateParameters

import os
import sys
scriptDir = os.path.join(os.path.dirname(__file__.split("#")[0]), "Scripts") 
sys.path.append(scriptDir)
from someModuleInScriptDir import someFunction

class ToolValidator:
    ...

我尝试在ToolValidator类之外进行导入,但在导入语句上将失败。在运行任何脚本之前,您是否正在使用刚打开的ArcCatalog?我可以想象这就是为什么ESRI难以重现错误……它仅在运行任何脚本之前在新打开的应用程序中发生。
MJ

它通过新打开的ArcCatalog对我有用。我想知道它是否正在导入一个类与一个函数的问题?
blah238

谢谢,您可能会遇到一些问题。...我隐约记得一个情况,当我直接导入一个函数时,它将进行更多测试。
MJ,

非常奇怪的行为...它将起作用,直到我设法打破它为止。破坏它之后,它将始终抛出错误。如上所述,在开发人员机器上使用PYTHONPATH或附加第二条硬编码路径即可达到目的。
MJ

0

通过将其导入并从现有TBX的工具验证中调用它,我能够将验证移至py文件。关键是在构造函数内部调用导入。如果我从ToolValidator类外部调用它,则导入将失败。这是我在TBX的“验证”标签中拥有的内容。

import arcpy
import os
import sys

class ToolValidator(object):
   """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."""
   self.scriptDir = os.path.dirname(__file__.split("#")[0])
   sys.path.append(self.scriptDir)
   import ExportParcelIntersected
   self.validator = ExportParcelIntersected.ToolValidator()
   self.params = self.validator.params

 def initializeParameters(self):
   """Refine the properties of a tool's parameters.  This method is
   called when the tool is opened."""
   self.validator.initializeParameters()
   return

 def updateParameters(self):
   """Modify the values and properties of parameters before internal
   validation is performed.  This method is called whenever a parameter
   has been changed."""
   self.validator.updateParameters()
   return

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

然后,我的验证逻辑位于ExportParcelIntersected.ToolValidator()中。在哪里可以更容易维护。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.