ArcGIS Python Tool - Importowanie skryptu niestandardowego do klasy ToolValidator

9

W zeszłym tygodniu opublikowałem pytanie dotyczące dostosowywania klasy ToolValidator i otrzymałem kilka bardzo dobrych odpowiedzi. Pracując z proponowanymi rozwiązaniami, stworzyłem moduł niestandardowy, który wykonuje zapytania na bazie danych i będzie wywoływany zarówno przez klasę ToolValidator (w celu dostarczenia wartości dla list rozwijanych), jak i później w skrypcie geoprocessingu (aby uzyskać inne parametry oparte na elementach wybranych z list rozwijanych). Nie wydaje mi się jednak, aby mógł wywoływać moduł niestandardowy w klasie ToolValidator. Próbowałem dołączyć do ścieżki bez powodzenia. Gdy próbuję zastosować te zmiany w skrypcie, pojawia się błąd czasu wykonania: [Errno 9] Zły deskryptor pliku. Jeśli skomentuję linię importu, żadnych błędów.

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

Wielu z was może pyta, dlaczego nie zaimplementuję niestandardowego narzędzia za pomocą ArcObjects. Powodem jest to, że moi użytkownicy końcowi nie mają uprawnień niezbędnych do zarejestrowania ŻADNYCH bibliotek DLL na swoim komputerze.

AKTUALIZACJA: Zdarzyło mi się to w ArcGIS 10. Co ciekawe, początkowo dołączałem się do ścieżki wewnątrz funkcji initialiazeParameters klasy ToolValidator. Jeśli wykonam dołączenie poza (tj. Na górze) klasy ToolValidator, wszystko działa zgodnie z oczekiwaniami.

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

AKTUALIZACJA 2: Myślę, że znalazłem prawdziwą przyczynę mojego problemu. W fragmentach kodu w tym poście dodałem coś, co wydaje się prawdziwymi ścieżkami (np. C: / Working / SomeFolder) do sys.path. W mojej rzeczywistej klasie ToolValidator budowałem ścieżkę względną, używając os.path.dirname(__file__)+ „\ mój_specjalny_folder ...”. Spodziewałem się, os.path.dirname(__file__)że zwróci ścieżkę do przybornika, ponieważ zawiera on klasę ToolValidator. Przekonałem się, że tak nie jest. O ile mogę stwierdzić, klasa ToolValidator nigdy nie jest faktycznie zapisywana do pliku .py, i spekuluję, że ten kod jest przekazywany do interpretera python w pamięci, więc __file__jest bezużyteczny lub jakiś skrypt tymczasowy jest utrwalany, a następnie wykonywalny ( ścieżka_do_skryptu), ponownie renderowane__file__nieprzydatny. Jestem pewien, że są też inne powody, dla których tęsknię.

Krótko mówiąc, jeśli użyję zakodowanej ścieżki, sys.append działa wszędzie, ścieżki względne nie działają tak dobrze w klasie ToolValidator.

użytkownik890
źródło
Czy to w 9.3 czy 10?
Jason Scheirer,
Mamy problem z odtworzeniem tego tutaj w Esri, jeśli wyodrębnimy przyczynę, możemy cofnąć poprawkę dla 10.0 SP3. Tymczasem przypuszczam, że utknąłeś w tym pierwszym, a nie w drugim.
Jason Scheirer,

Odpowiedzi:

3

Sposób, w jaki to robię, to po uruchomieniu ArcGIS lub ArcCatalog najpierw uruchom fałszywe narzędzie („Uruchom raz”), wywołując skrypt dummy.py. Po wykonaniu tej czynności możesz zaimportować skrypty pythonowe w walidatorze za pomocą sys.argv [0]. Wskaże to folder, w którym znajdował się pierwszy skrypt. Następnie możesz zaimportować potrzebny skrypt do klasy de Validator.

Skrypt dummy.py wywoływany przez narzędzie „Uruchom raz”:

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

Niestety, nie można poprawnie sformatować Pozdrawiam, Maarten Tromp

Maarten Tromp
źródło
3

W końcu złamałem ten okropny błąd! Na przykład podczas próby zastosowania zmian w celu zaimportowania względnego modułu lub pakietu może zostać wyświetlony następujący błąd:

wprowadź opis zdjęcia tutaj

Opcja 1:
Tylko dla dewelopera dodaj pełną ścieżkę do modułu do PYTHONPATH . Przed wejściem w życie musisz ponownie uruchomić ArcMap / ArcCatalog. Użyj poniższego kodu, aby zaimportować moduł ze ścieżki względnej (do wdrożenia). Nie martw się, użytkownik końcowy nie potrzebuje żadnych dodatków do swojej zmiennej PYTHONPATH, zadziała!

Opcja 2:
Dodaj dodatkowy wiersz do poniższego kodu, aby dodać ścieżkę zakodowaną na stałe, na przykład: sys.path.append (r "c: \ temp \ test \ scripts")
Gdy jesteś gotowy do wdrożenia, masz katalog zewnętrzny, ale to nie ma znaczenia, wszystko powinno działać na komputerze użytkownika końcowego, ponieważ pierwszą dodaną ścieżką był katalog względny (naszym celem było po prostu ominąć okno dialogowe awarii).

Kod wspólny dla obu opcji:

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

Aktualizacja

Pożegnanie zła wycinanie i wklejanie! Zaktualizowałem przykładowy kod, aby klasa ToolValidator została zaimportowana z biblioteki. Wycinam i wklejam tylko raz, gdy parametry narzędzia są ustawione po raz pierwszy. Przechowuję ten fragment kodu w dokumentacji importowanego narzędzia ToolValidator.

W tym przykładzie nazwa katalogu źródłowego jest oparta na nazwie tbx. Takie podejście pozwala uniknąć kolizji, jeśli masz dwa zestawy narzędzi z różnymi katalogami źródłowymi. Standard, którego użyłem do nazewnictwa folderów źródłowych, jest następujący:
TOOLBOXNAME__anything.tbx -> TOOLBOXNAME.src

Dlaczego „__wszystko”? Ponieważ plików binarnych nie można scalić w naszym systemie DVCS, możemy przypisywać narzędzia do osób i nie martwić się o utratę zmian. Po sfinalizowaniu narzędzie jest wycinane i wklejane do matrycy.

Potrzebowałem również dostępu do plików w folderze źródłowym, aby wypełnić menu rozwijane, użyj tej metody, aby uzyskać ścieżkę do zestawu narzędzi z zaimportowanego modułu:

import __main__
tbxPath = __main__.__file__.split("#")[0]
Michael Jackson
źródło
Czy to możliwe, że kod ToolValidator ustawia domyślną wartość parametru? Sprawdź ustawienie parametru „Wartość domyślna” parametru we właściwościach narzędzia skryptowego.
blah238,
Dzieki za sugestie. Sprawdziłem, a domyślna wartość nie jest ustawiona w przyborniku ... ale skopiowałem przybornik i zmieniłem nazwę wszystkiego, a wartość nadal obowiązywała w obu kopiach. Dlatego porzucę mój pomysł na pamięć podręczną i zasugeruję, że może on być faktycznie zapisany w pliku .tbx, co nadal jest dziwnym zachowaniem.
MJ
2

Umieszczenie importu na górze modułu sprawdzania poprawności, poza ToolValidatorklasą, wydaje mi się działać dobrze - mam 10.0 SP2. Jednak nic nie robię z zaimportowanym modułem nigdzie indziej 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
źródło
Próbowałem importować poza klasą ToolValidator, ale to nie powiedzie się w instrukcji importu. Czy korzystałeś ze świeżo otwartego ArcCatalog, zanim uruchomiono jakieś skrypty? Wyobrażam sobie, że właśnie dlatego ESRI ma problem z odtworzeniem błędu ... występuje on tylko w nowo otwartej aplikacji przed uruchomieniem skryptów.
MJ,
Działa dla mnie z nowo otwartym ArcCatalog. Zastanawiam się, czy to import klasy czy funkcji, która jest problemem?
blah238,
Dzięki, możesz być przy czymś ... Nie pamiętam przypadku, w którym zadziałało, gdy bezpośrednio zaimportowałem funkcję, zrobię więcej testów.
MJ
Bardzo dziwne zachowanie ... działałoby, dopóki nie zdołam go złamać. Po zerwaniu konsekwentnie generowałby błąd. Użycie PYTHONPATH na komputerze programisty lub dodanie drugiej ścieżki zakodowanej na stałe, jak opisano powyżej, załatwiło sprawę.
MJ,
0

Udało mi się przenieść moją weryfikację do pliku py, importując go i wywołując z poziomu istniejącej weryfikacji narzędzi TBX. Kluczem było wywołanie importu wewnątrz konstruktora. Jeśli wywołałem go spoza klasy ToolValidator, import nie powiódł się. Oto, co miałem w zakładce sprawdzania poprawności 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

Moja logika sprawdzania poprawności istniała następnie w ExportParcelIntersected.ToolValidator (). Gdzie można to łatwiej utrzymać.

TurboGus
źródło