La semaine dernière, j'avais posé une question sur la personnalisation d'une classe ToolValidator et obtenu de très bonnes réponses. En travaillant avec les solutions proposées, j'ai créé un module personnalisé qui effectue des requêtes sur une base de données, et sera appelé à la fois par la classe ToolValidator (pour fournir des valeurs pour les listes déroulantes) et plus tard dans le script de géotraitement (pour obtenir d'autres paramètres basés sur les éléments sélectionnés dans les listes déroulantes). Cependant, je n'arrive pas à appeler le module personnalisé dans la classe ToolValidator. J'ai essayé d'ajouter au chemin sans succès. Lorsque j'essaie d'appliquer ces modifications au script, j'obtiens une erreur d'exécution: [Errno 9] Mauvais descripteur de fichier. Si je commente la ligne d'importation, aucune erreur.
sys.path.append('my_custom_module_directory')
import my_custom_module
Beaucoup d'entre vous se demandent peut-être pourquoi je n'implémente pas simplement un outil personnalisé avec ArcObjects. La raison en est que mes utilisateurs finaux ne disposent pas des privilèges nécessaires pour enregistrer des DLL sur leur ordinateur.
MISE À JOUR: Cela m'arrivait dans ArcGIS 10. Assez intéressant, j'étais initialement en train d'ajouter au chemin à l'intérieur de la fonction initialiazeParameters de la classe ToolValidator. Si je fais l'ajout à l'extérieur (c'est-à-dire au-dessus) de la classe ToolValidator, tout fonctionne comme prévu.
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()
MISE À JOUR 2: Je pense avoir trouvé la véritable cause de mon problème. Dans les extraits de code de cet article, j'ai ajouté ce qui semble être de vrais chemins (ex C: / Working / SomeFolder) au sys.path. Dans ma classe ToolValidator actuelle, je construisais un chemin relatif en utilisant os.path.dirname(__file__)
+ "\ my_special_folder ...". os.path.dirname(__file__)
J'anticipais que cela retournerait le chemin de la boîte à outils, car il contient la classe ToolValidator. Je suis venu pour constater que ce n'est pas le cas. Pour autant que je sache, la classe ToolValidator n'est jamais réellement écrite dans un fichier .py, et je spécule que le code est transmis à l'interpréteur python en mémoire, donc __file__
inutile, ou qu'un script temporaire est persistant, puis execfile ( path_to_script) est appelé, rendant à nouveau__file__
inutile. Je suis sûr qu'il y a d'autres raisons qui me manquent également.
Pour faire court, si j'utilise un chemin codé en dur, sys.append fonctionne n'importe où, les chemins relatifs ne fonctionnent pas si bien dans la classe ToolValidator.
la source
Réponses:
Pour ce faire, après avoir démarré ArcGIS ou ArcCatalog, exécutez d'abord un outil factice ("Exécuter cette fois") appelant un script dummy.py. Après cela, vous pouvez importer des scripts python dans le validateur en utilisant sys.argv [0]. Cela pointera vers le dossier où se trouvait le premier script. Par la suite, vous pouvez importer le script nécessaire dans de Validator Class.
Le script dummy.py appelé par l'outil "Exécuter cette fois":
Désolé, impossible d'obtenir le bon formatage Cordialement, Maarten Tromp
la source
Enfin craqué cet horrible bug! Par exemple, lorsque vous essayez d'appliquer des modifications pour importer un module ou un package relatif, vous pouvez voir l'erreur suivante:
Option 1:
pour le développeur uniquement, ajoutez le chemin complet du module au PYTHONPATH . Vous devrez redémarrer ArcMap / ArcCatalog avant qu'il ne prenne effet. Utilisez le code ci-dessous pour importer le module à partir d'un chemin relatif (pour le déploiement). Ne vous inquiétez pas, l'utilisateur final n'a besoin d'aucun ajout à sa variable PYTHONPATH, cela fonctionnera!
Option 2:
ajoutez une ligne supplémentaire dans le code ci-dessous pour ajouter le chemin codé en dur, par exemple: sys.path.append (r "c: \ temp \ test \ scripts")
Lorsque vous êtes prêt à déployer, vous disposez d'un répertoire superflu, mais cela n'a pas d'importance, tout devrait fonctionner sur l'ordinateur de l'utilisateur car le premier chemin que vous avez ajouté était le répertoire relatif (notre objectif était de dépasser la boîte de dialogue d'échec).
Code commun aux deux options:
Mise à jour
Adieu mal couper et coller! J'ai mis à jour l'exemple de code afin que la classe ToolValidator soit importée de la bibliothèque. Je coupe et colle une seule fois lorsque les paramètres de l'outil sont définis pour la première fois. Je stocke cet extrait de code dans la docstring du ToolValidator en cours d'importation.
Dans cet exemple, le nom du répertoire source est basé sur le nom tbx. Cette approche évite les collisions si vous avez deux boîtes à outils avec des répertoires source différents. La norme que j'ai utilisée pour nommer le dossier source est la suivante:
TOOLBOXNAME__anything.tbx -> TOOLBOXNAME.src
Pourquoi le "__anything"? Étant donné que les fichiers binaires ne peuvent pas être fusionnés dans notre DVCS, nous pouvons attribuer des outils à des individus et ne pas craindre de perdre des modifications. Lorsque l'outil est finalisé, il est coupé et collé dans le maître.
J'avais également besoin d'accéder aux fichiers dans le dossier source pour remplir une liste déroulante, utilisez cette méthode pour obtenir le chemin d'accès à la boîte à outils à partir de votre module importé:
la source
Mettre les importations en haut du module de validation, en dehors de la
ToolValidator
classe semble bien fonctionner pour moi - je suis sur 10.0 SP2. Cependant, je ne fais rien avec le module importé ailleurs que dansupdateParameters
.la source
J'ai pu déplacer ma validation dans un fichier py en l'important et en l'appelant depuis la validation d'outil TBX existante. La clé appelait l'importation à l'intérieur du constructeur. Si je l'ai appelé de l'extérieur de la classe ToolValidator, l'importation a échoué. Voici ce que j'avais à l'intérieur de l'onglet de validation du TBX.
Ma logique de validation a ensuite vécu dans ExportParcelIntersected.ToolValidator (). Où il pourrait être maintenu plus facilement.
la source