Utiliser les services de géotraitement dans les scripts Python

Vous pouvez écrire un script Python pour exécuter et utiliser un service de géotraitement de plusieurs façons. Le principal mode d’exécution d’un script consiste à utiliser ArcPy. ArcPy possède des méthodes intégrées permettant de se connecter au service, de l’exécuter et d’en traiter le résultat. Vous pouvez également, si vous accédez au service à partir du répertoire de services ArcGIS Server, utiliser des modules Python intégrés pour effectuer des appels REST à l’aide d’une structure JSON et transférer les résultats. Vous devez créer un client intégralement à l’aide de code Python pour exploiter cette fonction. La majorité des scripts se connecte à des services de géotraitement et les utilise par le biais d’ArcPy.

Utiliser ArcPy

Un service de géotraitement est accessible via la fenêtre Python dans ArcGIS Pro, un outil de script ou un script autonome. L’URL du service permet de se connecter à un service de géotraitement et de l’utiliser.

Connectez-vous à un service avec ImportToolbox ou AddToolbox.

# arcpy.ImportToolbox("https://machine.domain.com/webadaptor/services;<optional folder>/<service name>;{username};{password}")
arcpy.ImportToolbox("https://machine.domain.com/webadaptor/services;GPFolder/BufferService;serverusername;serverpassword")

Le chemin utilisé pour importer l’outil est l’URL de l’outil Web. ImportToolbox and AddToolbox accepte les informations du serveur qui inclut quatre parties séparées par un point-virgule (;). La première partie est l’URL (ou lien) vers l’extrémité du service, la seconde est le nom du service (un nom de dossier précède éventuellement le nom du service), les troisième et quatrième partie sont le nom d’utilisateur et le mot de passe du serveur facultatif. Fournissez le nom d’utilisateur et le mot de passe si vous n’êtes pas autorisé à accéder à l’outil Web.

Un service de géotraitement peut s’exécuter de manière synchrone ou asynchrone. En tant que créateur de script Python, vous devez comprendre comment le service s’exécute pour pouvoir l’utiliser. La propriété IsSynchronous permet de déterminer si le service s’exécute de manière synchrone ou asynchrone. Lorsqu’un service s’exécute de manière synchrone, les résultats sont renvoyés automatiquement, mais aucune autre action ne peut être effectuée avant la fin de son exécution. Pour les services asynchrones, l’état actuel doit être interrogé à intervalles réguliers. Une fois l’exécution du service terminée, vous avez accès au résultat.

Le code Python suivant illustre le mode de connexion à un service de géotraitement asynchrone et la façon dont les fonctions ArcPy l’exécutent, obtiennent le résultat et lui appliquent d’autres traitements. En définissant une variable de résultat lors de l’exécution de la tâche, il est possible de faire appel à une boucle while pour vérifier l’état. La tâche est terminée lorsqu'un code d'état de 4 (réussite) ou supérieur est renvoyé.

Utilisez un service asynchrone pour créer une zone tampon et enregistrer le résultat localement.

import arcpy
import time

arcpy.ImportToolbox("http://machine.domain.com/webadaptor/services;Elevation/viewshedAlias;serverusername;serverpassword")

result = arcpy.Viewshed_viewshedAlias(r'c:\data\inputPoint.shp', "10000 Kilometers")

while result.status < 4:
	   print(result.status)
	   time.sleep(0.2)
print("Execution Finished")

print(result.getMessages())
arcpy.CopyFeatures_management(result[0], 'localResult.shp')

Des informations supplémentaires concernant les codes d’objet et d’état Result, ainsi que la création d’une sortie raster et d’image de carte, sont disponibles dans la rubrique d’aide Utiliser les outils dans Python.

Utiliser REST

Une méthode alternative (mais moins courante) d’utilisation d’un service de géotraitement consiste à écrire un script qui effectue des appels REST, avec JSON comme format d’échange de données. Cette méthode implique d'écrire du code pour envoyer la requête et traiter la réponse.

L'envoi et la réception de messages REST est plus contraignant, car vous devez gérer vous-même tous les aspects de la syntaxe des entrées et des sorties. Lors de l'envoi et de la réception de messages REST, ils sont renvoyés de manière cohérente. Il est possible d'effectuer les envois via une méthode GET HTTP ou HTTP POST, et la réponse peut revenir structurée au format JSON. Les principales bibliothèques Python prennent en charge l’envoi d’une requête et les fonctions, ce qui permet une lecture et une analyse directes des messages JSON.

L’exemple qui suit illustre la façon de se connecter au service, d’envoyer une requête ou de traiter une réponse.

Envoyer la requête

Par exemple, un service de géotraitement destiné à créer des champs de vision est accessible à partir de https://machine.domain.com/webadaptor/rest/services/Elevation. Ce service prend un point et une distance comme entrée et renvoie un jeu d'entités. Les entrées suivantes permettent de mieux comprendre le service :

Nom de paramètreValeur en entrée

Point d'observation en entrée (GPFeatureRecordSetLayer)

{"geometryType" : "esriGeometryPoint", "spatialReference" : {"wkid" : 54003}, 'features':[{'geometry':{'x': -13308192.1956127, 'y': 4221903.58555983}}]}

Distance du champ de vision (GPLinearUnit)

{ 'distance' : 8.5, 'units' : 'esriMiles' }

Format (format de la sortie)

JSON

Cette requête renvoie le format JSON des emplacements visibles à partir du service. L'URL complète permettant de générer la requête peut être utilisée dans la barre d'adresse d'un navigateur Web.

https://machine.domain.com/webadaptor/rest/services/Elevation/ESRI_Elevation_World/GPServer/Viewshed/execute?Input_Observation_Point={%22features%22%3A[{%22geometry%22%3A{%22x%22%3A-13308192.1956127%2C%22y%22%3A4221903.58555983}}]}&Viewshed_Distance={+%27distance%27+%3A+8.5%2C+%27units%27+%3A+%27esriMiles%27+}&env%3AoutSR=&env%3AprocessSR=&f=pjson

Il est possible d’envoyer l’URL à l’aide du module Python urllib ou urllib2. Le code Python suivant exécute la requête ci-dessus, ce qui revient à utiliser un répertoire de service ou à copier un lien dans la barre d’adresse d’un navigateur Web.

# Requires Python 3+
import urllib.request as urlopen
import urllib.parse as urlencode
import urllib.request as request
import json

inPts = {"geometryType" : "esriGeometryPoint",
         "spatialReference" : {"wkid" : 54003},
         'features':[{'geometry': {'x': -13308192.1956127, 'y': 4221903.58555983}}]}
dist = {'distance':8.5,'units':'esriMiles'}

data = {'Input_Observation_Point': inPts,
        'Viewshed_Distance': dist,
        'f': 'pjson'}

URL = 'https://machine.domain.com/webadaptor/rest/services/Elevation/ESRI_Elevation_World/GPServer/Viewshed/execute'

req = request.Request(URL, urlencode.urlencode(data).encode('UTF-8'))
response = urlopen.urlopen(req)
response_bytes = response.read()
print(json.loads(response_bytes.decode('UTF-8')))

L’objet Result est renvoyé sous forme de chaîne. Diverses méthodes peuvent être utilisées pour effectuer une requête et analyser un résultat ; l’exemple ci-dessus illustre l’une d’entre elles. La sortie JSON renvoyée par un service de géotraitement peut être placée dans un dictionnaire grâce à json.loads(), comme illustré dans l’exemple précédent. Selon la sortie de votre service de géotraitement, cette technique peut s’avérer la meilleure, ou vous pouvez avoir besoin d’expérimenter d’autres solutions pour traiter la sortie lorsqu’il est utilisé depuis Python via REST.

Remarque :

Si vous utilisez les entités de résultat, assurez-vous qu’il est pertinent de recourir à des paires x,y dans le cadre de votre processus, car vous ne recevrez pas les entités dans un format prenant en charge la géométrie dans ArcGIS.

Un service qui s’exécute de manière asynchrone nécessite que vous demandiez régulièrement quel est l’état d’une tâche, pour savoir si elle est terminée, comme dans l’exemple ci-dessus avec ArcPy. Votre code Python peut rechercher l’expression esriJobSucceeded ou esriJobFailed dans le message d’état jobStatus renvoyé lors de la vérification de l’état de la tâche. L’exemple de code suivant présente une technique d’utilisation d’un service de géotraitement asynchrone (à l’aide de submitJob) :

import urllib.request as urlopen
import urllib.parse as urlencode
import urllib.request as request
import json
import time

def sendReq(URL, data=None):

    req = request.Request(URL, urlencode.urlencode(data).encode('UTF-8'))
    response = urlopen.urlopen(req)
    response_bytes = response.read()
    return json.loads(response_bytes.decode('UTF-8'))

inPts = {"geometryType": "esriGeometryPoint",
         "spatialReference": {"wkid" : 54003},
         'features': [{'geometry': {'x': -13308192.1956127, 'y': 4221903.58555983}}]}
dist = {'distance': 8.5, 'units': 'esriMiles'}

data = {'Input_Observation_Point': inPts,
        'Viewshed_Distance': dist,
        'f': 'pjson'}

taskUrl = "https://machine.domain.com/webadaptor/rest/services/Elevation/GPServer/viewshed"
submitUrl = taskUrl + "/submitJob"

submitJson = sendReq(submitUrl, data)

if 'jobId' in submitJson:
    jobID = submitJson['jobId']
    status = submitJson['jobStatus']
    jobUrl = taskUrl + "/jobs/" + jobID

    while status == "esriJobSubmitted" or status == "esriJobExecuting":
        print("checking to see if job is completed...")
        time.sleep(1)

        jobJson = sendReq(jobUrl, {"f": "json"})

        if 'jobStatus' in jobJson.keys():
            status = jobJson['jobStatus']

            if status == "esriJobSucceeded":
                if 'results' in jobJson:
                    resultsJson = jobJson['results']
                    for paramName in resultsJson.keys():
                        resultsUrl = jobUrl + "/" + resultsJson[paramName]['paramUrl']
                        resultJson = sendReq(resultsUrl, {"f": "json"})
                        print(resultJson)

            if status == "esriJobFailed":
                if 'messages' in jobJson.keys():
                    print(jobJson['messages'])

else:
    print("no jobId found in the response")

Dans cette rubrique
  1. Utiliser ArcPy
  2. Utiliser REST