Exécuter des scripts Python (avec paramètres) dans un autre script Python avec ArcPy?

23

Un modèle de codage commun utilisé en AML était d'exécuter un AML (avec paramètres) dans un autre AML.

Une application que je développe actuellement gagnerait à pouvoir exécuter un script Python (avec paramètres) dans un autre script Python.

Cependant, cela ne semble pas du tout simple.

En utilisant ArcGIS 10, j'expérimente avec l'encapsulation du script Python "interne" dans un outil ArcGIS qui a les paramètres. Je pensais que ce serait une question simple que le script Python "externe" utilise arcpy.ImportToolbox pour importer la boîte à outils, puis exécuter le ou les outils à l'intérieur. Cependant, jusqu'à présent, toutes mes tentatives pour exécuter l'outil "interne" à partir du script "externe" semblent simplement ignorer l'outil "interne" (aucune erreur n'est levée).

Voici du code de test pour mieux illustrer ce que j'essaie de décrire.

Mon script testinner.py est:

inputString = arcpy.GetParameterAsText(0)

newFC = "C:\\Temp\\test.gdb\\" + inputString
arcpy.Copy_management("C:\\Temp\\test.gdb\\test",newFC)

Mon script testouter.py est:

import arcpy

inputString1 = arcpy.GetParameterAsText(0)
inputString2 = arcpy.GetParameterAsText(1)

arcpy.ImportToolbox("C:\\Temp\\test.tbx")

arcpy.testinner_test(inputString1)

arcpy.testinner_test(inputString2)

Pour testinner.py, son outil a besoin d'un seul paramètre String.

Pour testouter.py, son outil a besoin de deux paramètres String

Les deux outils sont placés dans un test.tbx.

Le test.gdb a juste besoin d'une seule classe d'entités vide appelée test.

Une fois que vous avez assemblé ce qui précède, l'exécution de l'outil testinner avec une chaîne comme 'abc' transmise comme paramètre devrait entraîner la copie de la classe d'entités 'test' dans une autre appelée 'abc' OK.

Mais lorsque vous essayez d'exécuter l'outil testouter avec deux chaînes comme «uvw» et «xyz» comme paramètres, l'outil testinner dans testouter.py semble fonctionner correctement une fois, mais envoie ArcMap 10 SP2 sur Vista SP2 à une grave erreur d'application lorsque essayer de l'utiliser la deuxième fois.

Le même test avec Windows XP SP3 et ArcGIS Desktop 10 SP2 génère également une erreur d'application grave au même point.

PolyGeo
la source
2
Pour répondre à la réponse de @ Dan à ce sujet ... ne considérez pas les fichiers .py comme des "scripts", considérez-les comme des modules que vous pouvez réutiliser et recycler en important les fonctions et les classes dont vous avez besoin à partir de ces modules. Abstenez-vous de ces paramètres GP imbriqués en utilisant un script pour lire un ensemble de paramètres, puis appelez des fonctions dans vos autres modules si nécessaire. Utilisez l' astuce if name __ == '__ main ' pour rendre vos modules à la fois importables et utilisables de manière autonome.
blah238
J'ai l'exemple de Dan qui fonctionne pour produire: C: \ Temp \ Main_program.py ('sum some numbers:', 55) ('sum of squares:', 385) ('hello from 8:', [1, 2, 3 , 4, 5, 6, 7, 8, 9, 10]) mais j'ai du mal à l'adapter à un exemple ArcPy comme je l'ai donné ci-dessus. Toute aide supplémentaire sur l'apparence d'un exemple ArcPy serait grandement appréciée.
PolyGeo
Voir la réponse que j'ai ajoutée - devrait aider à mieux expliquer les choses dans le contexte de votre exemple.
blah238
Je viens de découvrir un excellent article de blog de Jason Pardy qui fournit un modèle ArcPy incorporant le modèle de codage pour les modules Python sur blogs.esri.com/Dev/blogs/geoprocessing/archive/2011/07/21/…
PolyGeo
ce lien a depuis déménagé, et je crois qu'il se trouve ici maintenant: blogs.esri.com/esri/arcgis/2011/08/04/pythontemplate
ndimhypervol

Réponses:

15

Voici votre exemple de test modifié pour importer un module "utilitaire" dans le script principal et appeler une fonction en utilisant les paramètres lus par l'outil de script:


CopyFeaturesTool.py - Outil de script qui lit les paramètres et appelle une fonction dans un autre module

import CopyFeaturesUtility
import arcpy

inputFC = arcpy.GetParameterAsText(0)
outputFCName = arcpy.GetParameterAsText(1)
CopyFeaturesUtility.copyFeaturesToTempGDB(inputFC, outputFCName)

CopyFeaturesUtility.py - Module qui a une seule fonction copyFeaturesToTempGDB. Peut être importé ou exécuté de façon autonome. S'il est exécuté de manière autonome, le code sous if __name__ == '__main__'est exécuté.

import arcpy
import os

def copyFeaturesToTempGDB(inputFeatures, outputName):
    """Copies the input features to a temporary file geodatabase.
    inputFeatures: The input feature class or layer.
    outputName: The name to give the output feature class."""

    tempGDB = r"c:\temp\test.gdb"
    newFC = os.path.join(tempGDB, outputName)
    arcpy.env.overwriteOutput = True
    arcpy.CopyFeatures_management(inputFeatures, newFC)

if __name__ == '__main__':
    inputFC = r"c:\temp\test.gdb\test"
    outputFCName = "testCopy"
    copyFeaturesToTempGDB(inputFC, outputFCName)

Je pense que vous trouverez cette approche modulaire beaucoup plus efficace et logique une fois que vous vous y serez habitué. La section Modules du didacticiel Python standard est également une bonne ressource pour comprendre le fonctionnement de l'importation.

Pour des exemples plus spécifiques à arcpy, jetez un œil aux scripts intégrés dans votre C:\Program Files\ArcGIS\Desktop10.0\ArcToolbox\Scriptsdossier.

blah238
la source
13

Vous pouvez accomplir cela en important un module (ie un script) dans votre script principal et en appelant ses fonctions. Une démonstration simple est contenue dans les deux scripts d'accompagnement.

    '''
Main_program.py

demonstrates how to import and call functions from another module
'''
import sys
import CallingFunctions

a_list = [1,2,3,4,5,6,7,8,9,10]
print sys.argv[0]
print CallingFunctions.func1(a_list)
print CallingFunctions.func5(a_list)
print CallingFunctions.func8(a_list)

pour le programme principal et pour les fonctions qui sont appelées

'''
Callingfunctions.py

imported into another program giving it access to the functions
'''

def func1(inputs=None):
  x = sum(inputs)
  return "sum some numbers: ", x
'''
more functions
'''
def func5(inputs=None):
  x_sq = 0
  for x in inputs:
    x_sq += x**2
  return "sum of squares: ", x_sq
'''
more functions
'''
def func8(inputs=None):
  return "hello from 8: ", inputs

'''
more functions
'''
if __name__ == "__main__":
  a_list = [1,2,3,4,5,6,7,8,9,10]
  inputs = "test inputs"
  a_dict = {1:[func1([1,2,3]) ],
            5:[func5([1,2,3])],
            8:[func8("inputs to 8")]}
  needed = [1,5,8]
  for akey in needed:
    if akey in a_list:
      action = a_dict[akey]
      print "\naction: ", action

il vous suffit de vous assurer que le module principal et le module enfant sont dans le même dossier. Vous pouvez facilement transmettre des paramètres au module enfant et si le module enfant a besoin d'accéder à arcpy (en supposant que vous utilisez la version 10 d'arcmap), transmettez-lui simplement une référence.


la source
6

L'importation et l'exécution d'une fonction est la façon la plus propre de le faire, mais pour être complet, il y a aussi la execfilefonction intégrée ( documentation ) qui vous permettra d'exécuter un fichier arbitraire dans le contexte actuel.

Jason Scheirer
la source
0

La méthode execfile décrite par @JasonScheirer m'a permis de réorganiser mon code en celui ci-dessous et fournit une solution à mon problème de test:

import arcpy

inputString1 = arcpy.GetParameterAsText(0)
inputString2 = arcpy.GetParameterAsText(1)

arcpy.ImportToolbox("H:/Temp/test.tbx")

# Write second Python script to an ASCII file for first parameter & execute it
f = open("H:/Temp/string1.py","w")
f.write('newFC = "H:/Temp/test.gdb/' + inputString1 + '"' + "\n")
f.write('arcpy.Copy_management("H:/Temp/test.gdb/test"' + ',newFC)')
f.close()
execfile("H:/Temp/string1.py")

# Write third Python script to an ASCII file for second parameter & execute it
f = open("H:/Temp/string2.py","w")
f.write('newFC = "H:/Temp/test.gdb/' + inputString2 + '"' + "\n")
f.write('arcpy.Copy_management("H:/Temp/test.gdb/test"' + ',newFC)')
f.close()
execfile("H:/Temp/string2.py")

Cependant, cela peut s'avérer lourd lorsqu'il est appliqué à des scripts non-test qui sont beaucoup plus longs, j'ai donc utilisé le travail de @ blah238 qui a approuvé l'approche de @ DanPatterson et est venu avec le code final (test) suivant qui fait exactement ce dont j'ai besoin.

# CopyFeaturesTool.py

import CopyFeaturesUtility
import arcpy
outputFCName = arcpy.GetParameterAsText(0)
outputFCName2 = arcpy.GetParameterAsText(1)

CopyFeaturesUtility.copyFeaturesToTempGDB("C:\\Temp\\test.gdb\\test", outputFCName)
CopyFeaturesUtility.copyFeaturesToTempGDB("C:\\Temp\\test.gdb\\test", outputFCName2)

et

# CopyFeaturesUtility.py

import arcpy
import os

def copyFeaturesToTempGDB(inputFeatures, outputName):
    """Copies the input features to a temporary file geodatabase.
    inputFeatures: The input feature class or layer.
    outputName: The name to give the output feature class."""

    tempGDB = r"C:\Temp\test.gdb"
    newFC = os.path.join(tempGDB, outputName)
    arcpy.env.overwriteOutput = True
    arcpy.Copy_management(inputFeatures, newFC)

if __name__ == '__main__':
    inputFC = r"C:\Temp\test.gdb\test"
    outputFCName = arcpy.GetParameterAsText(0)
    copyFeaturesToTempGDB(inputFC, outputFCName)
PolyGeo
la source