Usage in Python scripts

You can write a Python script to run and use a web tool or a geoprocessing service in multiple ways. The primary way to run a script is to use ArcPy. ArcPy has built-in methods to connect to, run, and handle the result from a service. Alternatively, to access the service from ArcGIS REST API, use built-in Python modules to make REST calls using a JSON structure to transfer results. You must build a client from scratch with Python code to use this. The majority of scripts will connect to and use geoprocessing services through ArcPy.

Note:

The examples below consume a geoprocessing service on a federated ArcGIS Server. You never use the corresponding web tool item from the portal in Python.

UseArcPy

A web tool can be accessed through the Python window in ArcGIS Pro, a script tool, or a stand-alone script. The ImportToolbox function uses a service URL and other values to connect to and use a web tool.

Example: Connect to a service using ImportToolbox with a SOAP URL, a service in a folder, with username and password.


arcpy.ImportToolbox("https://organization.example.com/<context>/services;GPFolder/BufferService;serverusername;serverpassword")

A web tool or a geoprocessing service can run either synchronously or asynchronously. As a Python script author, you must understand how the service runs in order to use it. The IsSynchronous property is used to determine whether a service runs synchronously or asynchronously. When a service runs synchronously, the results are automatically returned, but no action can be taken until it has completed. When a service runs asynchronously, the current status must be queried periodically. Once the service has finished, you can access the result.

The following Python code shows how to connect to an asynchronous geoprocessing service. The code uses ArcPy functions to run the service, get the result, and process it further. By setting a result variable when running the task, a while loop can be used to check the status of the Result object. The task is finished once a status code of 4 (succeeded) or higher is returned.

Use an asynchronous service to create a buffer and save the result locally.

import arcpy
import time

arcpy.ImportToolbox("https://organization.example.com/<context>/services;Elevation/viewshedAlias;serverusername;serverpassword")

result = arcpy.viewshedAlias.Viewshed(r'c:\data.gdb\inputPoint', "10000 Kilometers")

while result.status < 4:
	   print(result.status)
	   time.sleep(0.2)
print("Tool finished")

print(result.getMessages())
arcpy.management.CopyFeatures(result, r'c:\results.gdb\result')

Learn more about using tools in Python

Use the REST endpoint

An alternate way to use a web tool is by writing a script that makes REST calls, using JSON as a data exchange format. This approach requires writing code to 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. When sending and receiving REST messages, they are returned in a consistent manner. A request can be sent through an HTTP GET or HTTP POST method, and a response can come back structured as JSON.

The following example demonstrates how to send a request, and handle a response.

Send the request

For example, a geoprocessing service to create viewsheds is accessible from https://organization.example.com/<context>/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 nameInput 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 (the format of the output)

JSON

This request returns 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.

https://organization.example.com/<context>/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 runs 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.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://organization.example.com/<context>/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')))

The Result object is returned as a string. A variety of methods can be used to make a request and parse a result; the example above is just one method. The JSON returned from a web tool can be placed into a dictionary using json.loads(). Depending on the output of the web tool, this may be the best technique, or you may need to explore other options to handle the output when consumed from Python through REST.

Note:

When working with result features, ensure that using the actual x,y pairs makes sense for your workflow, as you won't receive the actual features in a format that supports geometry by ArcPy.

A service that runs asynchronously requires that you periodically check the status of a task to see whether it has finished, similar to the example above using ArcPy. Your Python code could search for the phrase esriJobSucceeded or esriJobFailed in the jobStatus status message, which is returned when checking the job status. The following code sample demonstrates one technique for working with an asynchronous web tool (using 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://organization.example.com/<context>/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")

Related topics