ArcGIS Python Tool - Mengimpor Skrip Kustom Ke Kelas ToolValidator

9

Saya telah memposting pertanyaan minggu lalu tentang mengkustomisasi kelas ToolValidator dan mendapat beberapa jawaban yang sangat bagus. Dalam bekerja dengan solusi yang diusulkan, saya telah membuat modul khusus yang melakukan query pada db, dan akan dipanggil oleh kelas ToolValidator (untuk memberikan nilai untuk daftar drop-down) dan kemudian dalam skrip geoproses (untuk mendapatkan lainnya parameter berdasarkan item yang dipilih dalam daftar drop-down). Namun, sepertinya saya tidak dapat benar-benar memanggil modul khusus di kelas ToolValidator. Saya telah mencoba untuk menambahkan jalan tanpa hasil. Ketika saya mencoba menerapkan perubahan ini pada skrip, saya mendapatkan kesalahan runtime: [Errno 9] deskriptor file buruk. Jika saya mengomentari jalur impor, tidak ada kesalahan.

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

Banyak dari Anda mungkin bertanya mengapa saya tidak mengimplementasikan alat khusus dengan ArcObjects. Alasannya adalah bahwa pengguna akhir saya tidak memiliki hak istimewa yang diperlukan untuk mendaftarkan dll dll di komputer mereka.

UPDATE: Ini terjadi pada saya di ArcGIS 10. Cukup menarik, saya awalnya menambahkan ke jalur di dalam fungsi initialiazeParameters dari kelas ToolValidator. Jika saya menambahkan di luar (yaitu, di atas) dari kelas ToolValidator, semuanya berfungsi seperti yang diharapkan.

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: Saya pikir saya menemukan penyebab sebenarnya dari masalah saya. Dalam cuplikan kode dalam posting ini, saya telah menambahkan apa yang tampak sebagai jalur nyata (mis. C: / Working / SomeFolder) ke sys.path. Di kelas ToolValidator saya yang sebenarnya, saya membuat jalur relatif menggunakan os.path.dirname(__file__)+ "\ my_special_folder ...". Saya mengantisipasi itu os.path.dirname(__file__)akan mengembalikan jalur toolbox, karena itu berisi kelas ToolValidator. Saya datang untuk menemukan ini bukan masalahnya. Sejauh yang saya tahu, kelas ToolValidator tidak pernah benar-benar ditulis ke file .py, dan saya berspekulasi bahwa kode ini diteruskan ke juru bahasa python dalam memori, jadi __file__tidak berguna, atau skrip temp tetap ada dan kemudian execfile ( path_to_script) dipanggil, lagi rendering__file__tak berguna. Saya yakin ada alasan lain saya juga hilang.

Singkatnya, jika saya menggunakan jalur hardcoded, sys.append berfungsi di mana saja, jalur relatif tidak bekerja dengan baik di kelas ToolValidator.

pengguna890
sumber
Apakah ini dalam 9,3 atau 10?
Jason Scheirer
Kami mengalami masalah dalam mereproduksi ini di sini di Esri, jika kami mengisolasi penyebabnya, kami dapat mendukung perbaikan untuk 10.0 SP3. Sementara itu, saya kira Anda terjebak dengan pola penggunaan yang pertama dan bukan yang terakhir.
Jason Scheirer

Jawaban:

3

Cara saya melakukan ini adalah, setelah memulai ArcGIS atau ArcCatalog, pertama jalankan alat dummy ("Jalankan ini sekali") memanggil skrip dummy.py. Setelah melakukan itu, Anda dapat mengimpor skrip python di validator dengan menggunakan sys.argv [0]. Ini akan menunjuk ke folder di mana skrip pertama berada. Setelah itu Anda dapat mengimpor skrip yang diperlukan di Kelas de Validator.

Skrip dummy.py dipanggil oleh alat "Jalankan ini sekali":

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

Maaf, format pemformatannya tidak benar, Maarten Tromp

Maarten Tromp
sumber
3

Akhirnya memecahkan bug mengerikan ini! Misalnya ketika Anda mencoba menerapkan perubahan untuk mengimpor modul atau paket relatif, Anda mungkin melihat kesalahan berikut:

masukkan deskripsi gambar di sini

Opsi 1: Hanya
untuk pengembang, tambahkan path lengkap ke modul ke PYTHONPATH . Anda harus memulai ulang ArcMap / ArcCatalog sebelum diberlakukan. Gunakan kode di bawah ini untuk mengimpor modul dari jalur relatif (untuk penempatan). Jangan khawatir, pengguna akhir tidak perlu menambahkan variabel PYTHONPATH mereka, itu akan berhasil!

Opsi 2:
Tambahkan baris tambahan ke dalam kode di bawah ini untuk menambahkan jalur hard-coded, misalnya: sys.path.append (r "c: \ temp \ test \ scripts")
Ketika Anda siap untuk menggunakan, Anda memiliki direktori asing, tetapi tidak masalah, semua harus bekerja di komputer pengguna akhir karena jalur pertama yang Anda tambahkan adalah direktori relatif (tujuan kami adalah untuk hanya melewati dialog kegagalan).

Kode umum untuk kedua opsi:

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

Memperbarui

Perpisahan kejahatan memotong dan menempel! Saya memperbarui sampel kode sehingga kelas ToolValidator diimpor dari perpustakaan. Saya memotong dan menempel hanya sekali ketika parameter alat ditetapkan pertama kali. Saya menyimpan potongan kode ini di docstring ToolValidator yang sedang diimpor.

Dalam contoh ini, nama direktori sumber didasarkan pada nama tbx. Pendekatan ini menghindari tabrakan jika Anda memiliki dua kotak alat dengan direktori sumber yang berbeda. Standar yang saya gunakan untuk penamaan folder sumber adalah sebagai berikut:
TOOLBOXNAME__anything.tbx -> TOOLBOXNAME.src

Kenapa "__anything"? Karena file biner tidak dapat digabungkan dalam DVCS kami, kami dapat menetapkan alat untuk individu dan tidak khawatir kehilangan perubahan. Ketika alat selesai, itu dipotong dan ditempelkan ke master.

Saya juga perlu mengakses file di folder sumber untuk mengisi dropdown, gunakan metode ini untuk mendapatkan path ke kotak alat dari dalam modul yang diimpor:

import __main__
tbxPath = __main__.__file__.split("#")[0]
Michael Jackson
sumber
Mungkinkah kode ToolValidator menetapkan nilai default parameter? Periksa pengaturan 'Nilai Default' parameter dalam properti alat skrip.
blah238
Terima kasih untuk sarannya. Saya memeriksa, dan nilai default tidak diatur di kotak alat ... tapi saya menyalin kotak alat dan mengganti nama semuanya, dan nilai masih bertahan di kedua salinan. Karenanya saya akan meninggalkan ide cache saya dan menyarankannya mungkin sebenarnya disimpan dalam file .tbx, yang masih merupakan perilaku aneh.
MJ
2

Menempatkan impor di bagian atas modul validasi, di luar ToolValidatorkelas tampaknya berfungsi dengan baik untuk saya - Saya menggunakan 10,0 SP2. Namun saya tidak melakukan apa pun dengan modul yang diimpor di mana pun kecuali di 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:
    ...
blah238
sumber
Saya mencoba mengimpor di luar kelas ToolValidator tetapi akan gagal pada pernyataan impor. Apakah Anda menggunakan ArcCatalog yang baru dibuka, sebelum ada skrip dijalankan? Saya membayangkan inilah sebabnya ESRI mengalami kesulitan mereproduksi kesalahan ... itu hanya terjadi pada aplikasi yang baru dibuka sebelum skrip dijalankan.
MJ
Ini berfungsi untuk saya dengan ArcCatalog yang baru dibuka. Saya bertanya-tanya apakah itu mengimpor kelas vs fungsi yang menjadi masalah?
blah238
Terima kasih, Anda mungkin pada sesuatu .... Samar-samar saya ingat kasus di mana ia bekerja ketika saya langsung mengimpor suatu fungsi, saya akan melakukan beberapa pengujian lagi.
MJ
Perilaku yang sangat aneh ... itu akan berhasil sampai saya berhasil memecahkannya. Setelah memecahnya, itu akan secara konsisten melemparkan kesalahan. Menggunakan PYTHONPATH pada mesin pengembang, atau menambahkan jalur kode keras kedua, seperti diuraikan di atas, melakukan triknya.
MJ
0

Saya dapat memindahkan validasi saya ke file py dengan mengimpornya dan memanggilnya dari dalam validasi alat TBX yang ada. Kuncinya adalah memanggil impor di dalam konstruktor. Jika saya memanggilnya dari luar kelas ToolValidator, impor gagal. Inilah yang saya miliki di dalam tab validasi 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

Logika validasi saya kemudian tinggal di ExportParcelIntersected.ToolValidator (). Di mana itu bisa dipertahankan lebih mudah.

TurboGus
sumber