Using a geoprocessing service in Python scripts
You can write a Python script to execute and make use of a geoprocessing service in multiple ways. The primary way to execute a script is to make use of ArcPy. ArcPy has built-in methods to connect to, execute, and handle the result from the service. Alternatively, using the Services Directory, you can use built-in Python modules to make REST calls using a JSON structure to transfer results. You will have to build a client from scratch with Python code to make use of this. The majority of scripts will connect to and use geoprocessing services through ArcPy.
The ArcPy way
A geoprocessing service can be accessed through the Python window in ArcMap, a script tool, or a stand-alone script. A URL is used to connect to and use a geoprocessing service.
Connect to a service using ImportToolbox.
# arcpy.ImportToolbox("http://<hostname>:<port>/arcgis/services;<optional folder>/<service name>","<optional alias>")
arcpy.ImportToolbox("http://degrassi:6080/arcgis/services;GPFolder/BufferService","PointAlias")
The path used to import the tool is the URL of the geoprocessing service. ImportToolbox accepts two parameters: the URL to the service and an optional alias for the toolbox. The URL parameter is broken into two parts separated by a semicolon (;). The first part is the URL (or link) to the service end point, and the second is the service name (optionally, a folder name precedes the service name).
A geoprocessing service can execute either synchronously or asynchronously. As a Python scripter, you need to understand how the service executes in order to use it. The IsSynchronous property can be used to determine the execution type of a service. When a service executes synchronously, the results are automatically returned, but no action can be taken until it has completed. For asynchronous services, the current status of the execution must be queried periodically. Once the service has finished executing, the result can be accessed.
The following Python code shows how to connect to an asynchronous geoprocessing service, and using ArcPy functions, execute it, get the result, and process it further. By setting a result variable when executing the task, a while loop can be used to check the status. The task is finished once a status code of 4 (succeeded) or higher is returned.
Using an asynchronous GP Service to create a buffer and save the result locally
import arcpy
import time
arcpy.ImportToolbox("http://sampleserver1.arcgisonline.com/ArcGIS/services;Elevation/ESRI_Elevation_World", "viewshedAlias")
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"
result.getMessages()
arcpy.CopyFeatures_management(result.getOutput(0), 'localResult.shp')
More information regarding the result object and status codes, as well as creating raster and map image output, is available in the Using tools in Python help topic.
The RESTful way
An alternate (but less common) way to use a geoprocessing service is by building an application that makes REST calls, using JSON as a data exchange format. This method requires you to write code to both send the request and handle the response.
Sending and receiving REST messages is more involved, as you must handle all aspects of the inputs and outputs syntax yourself. The good part about sending and receiving REST messages is that they are returned in a consistent manner. A request can be sent through a HTTP GET method, and a response can come back structured as JSON. The core Python libraries support both sending an HTTP GET request and functions, which make reading and parsing JSON messages straightforward.
The following example uses a service on the Esri sample servers and demonstrates how you would connect to the service, send a request, and handle a response.
Submitting the Request
For example, SampleServer1 contains a geoprocessing service to create viewsheds and is accessible from http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Elevation. This service takes a point and distance as input and returns a feature set. The following inputs can be used to better understand the service:
Parameter Name | Input Value |
---|---|
Input Observation Point (GPFeatureRecordSetLayer) | {"geometryType" : "esriGeometryPoint", "spatialReference" : {"wkid" : 54003}, 'features':[{'geometry':{'x': -13308192.1956127, 'y': 4221903.58555983}}]} |
Viewshed Distance (GPLinearUnit) | { 'distance' : 8.5, 'units' : 'esriMiles' } |
Format (format the output will be in) | JSON |
This request will return the JSON of the visible locations from the service. The full URL used to generate the request can be used in the address bar of a web browser.
http://sampleserver1.arcgisonline.com/ArcGIS/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
The URL can be submitted using the Python module urllib or urllib2. The following Python code would execute the above request in a similar way to using the Service Directory or copying the link into the address bar of a web browser.
import urllib
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 = 'http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Elevation/ESRI_Elevation_World/GPServer/Viewshed/execute'
result = urllib.urlopen(URL, urllib.urlencode(data)).read()
print json.loads(result)
The result object is returned as a string. There are a number of different methods that can be used to make a request and parse a result; the above example is just one method. The JSON returned from a geoprocessing service can be placed into a dictionary by using json.loads() as shown in the previous example. Depending on the output of your geoprocessing service, this might be the best technique, or you may need to explore other options to handle the output from a geoprocessing service when consumed from Python through REST.
If working with result features, be sure that making use of the actual x,y pairs makes sense for your workflow, as you will not be receiving the actual features in a format that supports geometry inside ArcGIS.
A service that executes asynchronously requires that you periodically ask the status of task to see if it has finished, similar to the above example using ArcPy. Your Python code could look for the phrase esriJobSucceeded or esriJobFailed within the jobStatus status message, which is returned when checking the job status. The following code sample demonstrates one technique for working with an asynchronous geoprocessing service (using submitJob).
import urllib, json, time
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 = "http://localhost:6080/arcgis/rest/services/WorldViewshed/GPServer/viewshed"
submitUrl = taskUrl + "/submitJob"
submitResponse = urllib.urlopen(submitUrl, urllib.urlencode(data))
submitJson = json.loads(submitResponse.read())
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)
jobResponse = urllib.urlopen(jobUrl, "f=json")
jobJson = json.loads(jobResponse.read())
if 'jobStatus' in jobJson:
status = jobJson['jobStatus']
if status == "esriJobSucceeded":
if 'results' in jobJson:
resultsUrl = jobUrl + "/results/"
resultsJson = jobJson['results']
for paramName in resultsJson.keys():
resultUrl = resultsUrl + paramName
resultResponse = urllib.urlopen(resultUrl, "f=json")
resultJson = json.loads(resultResponse.read())
print resultJson
if status == "esriJobFailed":
if 'messages' in jobJson:
print jobJson['messages']
else:
print "no jobId found in the response"
Getting started with Python, ArcPy, and script tools
If you are unfamiliar with Python, ArcPy, and script tools, the table below lists a few topics that will help you get started.
Help topic | Contents |
---|---|
Basic concepts of creating your own geoprocessing tools. | |
Introductory topics to Python and ArcPy. These topics lead you to more detailed topics about Python and the ArcPy site package. | |
Introductory topic on creating custom script tools using Python. | |
Once you've become familiar with the process of creating a script tool, this topic is referred to often as it explains in detail how to define script tool parameters. |