ArcGIS Pythonツール-ToolValidatorクラスへのカスタムスクリプトのインポート


9

先週、ToolValidatorクラスのカスタマイズに関する質問を投稿し、いくつかの非常に良い答えを得ました。提案されたソリューションを使用して、データベースでクエリを実行するカスタムモジュールを作成しました。これは、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__役に立たないか、一時スクリプトが永続化されてからexecfile( path_to_script)が呼び出され、再びレンダリングされます__file__役に立たない。私が他にも欠けている理由があると私は確信しています。

要するに、ハードコードされたパスを使用すると、sys.appendはどこでも機能し、相対パスはToolValidatorクラスではうまく機能しません。


これは9.3または10ですか?
Jason Scheirer、2011

Esriでこれを再現するのに問題があります。原因を特定すると、10.0 SP3の修正をバックポートできます。それまでの間は、前者の方が使いやすく、後者の方が使いにくいと思います。
Jason Scheirer、2011

回答:


3

これを行う方法は、ArcGISまたはArcCatalogを起動した後、dummy.pyスクリプトを呼び出すダミーツールを実行します(「これを1回実行」)。その後、sys.argv [0]を使用して、バリデーターにPythonスクリプトをインポートできます。これは、最初のスクリプトが配置されていたフォルダーを指します。その後、必要なスクリプトをValidator Classにインポートできます。

「一度だけ実行」ツールによって呼び出される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')

申し訳ありませんが、書式を正しく設定できません。よろしくお願いいたします。MaartenTromp


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クラスがライブラリからインポートされるようにコードサンプルを更新しました。ツールパラメータを最初に設定するときに、1回だけカットアンドペーストします。このコードの抜粋を、インポートされるToolValidatorのdocstringに格納します。

この例では、ソースディレクトリ名はtbx名に基づいています。このアプローチは、異なるソースディレクトリを持つ2つのツールボックスがある場合に衝突を回避します。ソースフォルダーの命名に使用した標準は次のとおりです
。TOOLBOXNAME__anything.tbx-> TOOLBOXNAME.src

なぜ「__何か」?バイナリファイルはDVCSにマージできないため、個人にツールを割り当てることができ、変更が失われる心配はありません。ツールが完成すると、カットされてマスターに貼り付けられます。

ソースフォルダー内のファイルにアクセスしてドロップダウンを作成する必要もありました。このメソッドを使用して、インポートしたモジュール内からツールボックスへのパスを取得します。

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

ToolValidatorコードがパラメーターのデフォルト値を設定している可能性がありますか?スクリプトツールのプロパティでパラメーターの「デフォルト値」設定を確認します。
blah238

提案をありがとう。チェックしたところ、ツールボックスにデフォルト値が設定されていませんでしたが、ツールボックスをコピーしてすべての名前を変更しましたが、値は両方のコピーにまだ残っています。したがって、私は私のキャッシュアイデアを放棄し、それが実際には.tbxファイルに格納される可能性があることを示唆しますが、これはまだ奇妙な動作です。
MJ

2

インポートを検証モジュールの上部に置くと、ToolValidatorクラスの外では問題なく動作するようです-私は10.0 SP2を使用しています。しかし、私はインポートされたモジュールを使って何もしていません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を使用するか、2番目のハードコードされたパスを追加することで、トリックが行われました。
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()にありました。維持しやすい場所。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.