เครื่องมือ ArcGIS Python - การนำเข้าสคริปต์ที่กำหนดเองไปยังคลาส ToolValidator


9

ฉันโพสต์คำถามเมื่อสัปดาห์ที่แล้วเกี่ยวกับการปรับแต่งคลาส ToolValidator และได้รับคำตอบที่ดีมาก ในการทำงานกับโซลูชันที่เสนอฉันได้สร้างโมดูลแบบกำหนดเองที่ดำเนินการเคียวรีบน db และจะถูกเรียกโดยทั้งชั้น ToolValidator (เพื่อให้ค่าสำหรับรายการดรอปดาวน์) และภายหลังในสคริปต์การประมวลผลทางภูมิศาสตร์ (เพื่อรับอื่น ๆ พารามิเตอร์ตามรายการที่เลือกในรายการแบบหล่นลง) อย่างไรก็ตามฉันไม่สามารถเรียกโมดูลที่กำหนดเองได้ในคลาส ToolValidator ฉันพยายามที่จะผนวกกับเส้นทางโดยไม่มีโชค เมื่อฉันพยายามใช้การเปลี่ยนแปลงเหล่านี้กับสคริปต์ฉันได้รับข้อผิดพลาดรันไทม์: [Errno 9] ตัวอธิบายไฟล์ไม่ถูกต้อง ถ้าฉันใส่ความคิดเห็นออกสายนำเข้าจะไม่มีข้อผิดพลาด

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

พวกคุณหลายคนอาจถามว่าทำไมฉันไม่ใช้เครื่องมือที่กำหนดเองกับ ArcObjects เหตุผลก็คือผู้ใช้ของฉันไม่มีสิทธิ์ที่จำเป็นในการลงทะเบียน DLLs ใด ๆ บนคอมพิวเตอร์ของพวกเขา

UPDATE: สิ่งนี้เกิดขึ้นกับฉันใน ArcGIS 10 น่าสนใจพอฉันเริ่มผนวกเส้นทางภายในฟังก์ชัน initialiazeParameters ของคลาส ToolValidator ถ้าฉันผนวกส่วนนอก (เช่นด้านบน) ของคลาส 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 class ฉันมาเพื่อหาสิ่งนี้ไม่ใช่กรณี เท่าที่ฉันสามารถบอกได้คลาส ToolValidator ไม่เคยเขียนไปยังไฟล์. py และฉันคาดเดารหัสนี้จะถูกส่งผ่านไปยังตัวแปลภาษาไพ ธ อนในหน่วยความจำดังนั้นจึง__file__ไม่มีประโยชน์หรือสคริปต์ temp บางส่วนยังคงอยู่และ execfile ( path_to_script) ถูกเรียกอีกครั้งแสดงผล__file__ไร้ประโยชน์ ฉันแน่ใจว่ามีเหตุผลอื่นที่ฉันขาดหายไปเช่นกัน

เรื่องสั้นสั้นถ้าฉันใช้เส้นทาง hardcoded, sys.append ทำงานได้ทุกที่, เส้นทางสัมพัทธ์ทำงานได้ไม่ดีในคลาส ToolValidator


นี่คือ 9.3 หรือ 10 หรือไม่
Jason Scheirer

เรากำลังประสบปัญหาในการทำซ้ำสิ่งนี้ที่ Esri หากเราแยกสาเหตุที่เราสามารถ backport โปรแกรมแก้ไขสำหรับ 10.0 SP3 ในระหว่างนี้ฉันคิดว่าคุณติดอยู่กับอดีตไม่ใช่รูปแบบการใช้งานหลัง
Jason Scheirer

คำตอบ:


3

วิธีที่ฉันทำคือหลังจากเริ่ม ArcGIS หรือ ArcCatalog ก่อนให้เรียกใช้เครื่องมือจำลอง ("เรียกใช้ครั้งนี้ครั้งเดียว") เพื่อเรียกสคริปต์ dummy.py หลังจากทำเช่นนั้นคุณสามารถนำเข้าสคริปต์หลามในตัวตรวจสอบความถูกต้องโดยใช้ sys.argv [0] สิ่งนี้จะชี้ไปยังโฟลเดอร์ที่มีสคริปต์ตัวแรกตั้งอยู่ หลังจากนั้นคุณสามารถนำเข้าสคริปต์ที่ต้องการได้ใน de 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')

ขออภัยไม่สามารถรับรูปแบบที่ถูกต้องได้ Maarten Tromp


3

ในที่สุดก็แตกข้อผิดพลาดที่น่ากลัวนี้! ตัวอย่างเช่นเมื่อคุณพยายามใช้การเปลี่ยนแปลงเพื่อนำเข้าโมดูลหรือแพ็คเกจที่เกี่ยวข้องคุณอาจเห็นข้อผิดพลาดต่อไปนี้:

ป้อนคำอธิบายรูปภาพที่นี่

ตัวเลือกที่ 1:
สำหรับนักพัฒนาเท่านั้นเพิ่มเส้นทางแบบเต็มไปยังโมดูลไปยังPYTHONPATH คุณจะต้องรีสตาร์ท ArcMap / ArcCatalog ก่อนที่จะมีผล ใช้รหัสด้านล่างเพื่อนำเข้าโมดูลจากเส้นทางสัมพัทธ์ (สำหรับการปรับใช้) ไม่ต้องกังวลผู้ใช้ไม่ต้องการการเพิ่มเติมใด ๆ กับตัวแปร PYTHONPATH ของพวกเขามันจะทำงาน!

ตัวเลือกที่ 2:
เพิ่มบรรทัดเพิ่มเติมลงในรหัสด้านล่างเพื่อผนวกเส้นทางฮาร์ดโค้ดตัวอย่างเช่น: sys.path.append (r "c: \ temp \ test \ script")
เมื่อคุณพร้อมที่จะใช้งานคุณจะมี ไดเรกทอรีภายนอก แต่ไม่สำคัญว่าทั้งหมดควรทำงานบนคอมพิวเตอร์ของผู้ใช้ปลายทางเพราะเส้นทางแรกที่คุณเพิ่มคือไดเรกทอรีที่เกี่ยวข้อง (เป้าหมายของเราคือการผ่านกล่องโต้ตอบความล้มเหลว)

รหัสทั่วไปของทั้งสองตัวเลือก:

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 ถูกนำเข้าจากห้องสมุด ฉันตัดและวางเพียงครั้งเดียวเมื่อตั้งค่าพารามิเตอร์เครื่องมือเป็นครั้งแรก ฉันเก็บรหัสนี้ใน docstring ของ 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 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 ที่เพิ่งเปิดใหม่ ฉันสงสัยว่ามันกำลังนำเข้าคลาส vs ฟังก์ชันที่เป็นปัญหาหรือไม่
blah238

ขอบคุณคุณอาจจะมีบางสิ่งบางอย่าง .... ฉันจำกรณีที่มันทำงานเมื่อฉันนำเข้าฟังก์ชั่นโดยตรงฉันจะทำการทดสอบเพิ่มเติม
MJ

พฤติกรรมแปลก ๆ ... มันจะทำงานจนกว่าฉันจะทำลายมันได้ หลังจากทำลายมันจะทำให้เกิดข้อผิดพลาดอย่างสม่ำเสมอ การใช้ PYTHONPATH บนเครื่องของนักพัฒนาซอฟต์แวร์หรือต่อท้ายเส้นทางรหัสที่สองตามที่อธิบายไว้ข้างต้น
MJ

0

ฉันสามารถย้ายการตรวจสอบความถูกต้องของฉันไปยังไฟล์ py โดยนำเข้าและเรียกมันจากภายในการตรวจสอบเครื่องมือของ TBX ที่มีอยู่ กุญแจสำคัญคือการเรียกการนำเข้าภายในตัวสร้าง ถ้าฉันเรียกมันจากนอกคลาส 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.