<jupyter_start><jupyter_text>Ordering and DeliveryThis notebook demonstrates ordering and download with the orders api. In this notebook, we check authentication by requesting an orders list, then we create an order for two Analytic `PSScene4Band` images. We poll for order success then download images individually. And finally, we create, poll, and download the same order delivered as a single zip file.Reference information can be found at [Ordering & Delivery](https://developers.planet.com/docs/orders/ordering-delivery/).<jupyter_code>import json
import os
import pathlib
import time

import requests
from requests.auth import HTTPBasicAuth<jupyter_output><empty_output><jupyter_text>Authenticating<jupyter_code># API Key stored as an env variable
PLANET_API_KEY = os.getenv('PL_API_KEY')
orders_url = 'https://api.planet.com/compute/ops/orders/v2'<jupyter_output><empty_output><jupyter_text>Curl exampleTo check your orders list and make sure you have the permissions you need, uncomment the following line to run `curl`<jupyter_code>!curl -L -H "Authorization: api-key $PLANET_API_KEY" $orders_url<jupyter_output>{"_links":{"_self":"https://api.planet.com/compute/ops/orders/v2"},"orders":[]}<jupyter_text>Requests exampleIn this notebook, we will be using `requests` to communicate with the orders v2 API. First, we will check our orders list to make sure authentication and communication is working as expected.We want to get a response code of `200` from this API call. To troubleshoot other response codes, see the [List Orders](https://developers.planet.com/docs/orders/reference/operation/listOrders) AOI reference.<jupyter_code>auth = HTTPBasicAuth(PLANET_API_KEY, '')
response = requests.get(orders_url, auth=auth)
response<jupyter_output><empty_output><jupyter_text>Now we will list the orders we have created thus far. Your list may be empty if you have not created an order yet.<jupyter_code>orders = response.json()['orders']
len(orders)<jupyter_output><empty_output><jupyter_text>OrderingIn this example, we will order two `PSScene4Band` analytic images. For variations on this kind of order, see [Ordering Data](https://developers.planet.com/docs/orders/ordering-delivery/ordering-data_1).In this order, we request an `analytic` bundle. A bundle is a group of assets for an item. The `analytic` bundle for the  `PSScene4Band` item contains 3 assets: the analytic image, the analytic xml file, and the udm. See the [Product bundles reference](https://developers.planet.com/docs/orders/product-bundles-reference/) to learn about other bundles and other items. Place Order<jupyter_code># set content type to json
headers = {'content-type': 'application/json'}
request = {  
   "name":"simple order",
   "products":[
      {  
         "item_ids":[  
            "20151119_025740_0c74",
            "20151119_025741_0c74"
         ],
         "item_type":"PSScene4Band",
         "product_bundle":"analytic"
      }
   ],
}
def place_order(request, auth):
    response = requests.post(orders_url, data=json.dumps(request), auth=auth, headers=headers)
    print(response)
    order_id = response.json()['id']
    print(order_id)
    order_url = orders_url + '/' + order_id
    return order_url
order_url = place_order(request, auth)<jupyter_output><Response [202]>
44bab5ef-c584-4a1f-b583-505cd93e8c89<jupyter_text>Cancel an Order<jupyter_code># report order state
requests.get(order_url, auth=auth).json()['state']
oid = oids[0]
response = requests.put(order_url, auth=auth)
response
# report order state - it could take a little while to cancel
requests.get(order_url, auth=auth).json()['state']<jupyter_output><empty_output><jupyter_text>Poll for Order Success<jupyter_code># re-order since we canceled our last order
order_url = place_order(request, auth)
def poll_for_success(order_url, auth, num_loops=30):
    count = 0
    while(count < num_loops):
        count += 1
        r = requests.get(order_url, auth=auth)
        response = r.json()
        state = response['state']
        print(state)
        end_states = ['success', 'failed', 'partial']
        if state in end_states:
            break
        time.sleep(10)
        
poll_for_success(order_url, auth)<jupyter_output>running
running
running
running
running
running
running
running
running
success<jupyter_text>View Results<jupyter_code>r = requests.get(order_url, auth=auth)
response = r.json()
results = response['_links']['results']
[r['name'] for r in results]<jupyter_output><empty_output><jupyter_text>Download Downloading each asset individually<jupyter_code>def download_results(results, overwrite=False):
    results_urls = [r['location'] for r in results]
    results_names = [r['name'] for r in results]
    print('{} items to download'.format(len(results_urls)))
    
    for url, name in zip(results_urls, results_names):
        path = pathlib.Path(os.path.join('data', name))
        
        if overwrite or not path.exists():
            print('downloading {} to {}'.format(name, path))
            r = requests.get(url, allow_redirects=True)
            path.parent.mkdir(parents=True, exist_ok=True)
            open(path, 'wb').write(r.content)
        else:
            print('{} already exists, skipping {}'.format(path, name))
download_results(results)<jupyter_output>10 items to download
downloading e1ae4b94-3e38-48e8-9cdb-1bc3bae259b7/2/manifest.json to data/e1ae4b94-3e38-48e8-9cdb-1bc3bae259b7/2/manifest.json
downloading e1ae4b94-3e38-48e8-9cdb-1bc3bae259b7/2/files/PSScene4Band/20151119_025741_0c74/20151119_025741_0c74_metadata.json to data/e1ae4b94-3e38-48e8-9cdb-1bc3bae259b7/2/files/PSScene4Band/20151119_025741_0c74/20151119_025741_0c74_metadata.json
downloading e1ae4b94-3e38-48e8-9cdb-1bc3bae259b7/2/files/PSScene4Band/20151119_025741_0c74/analytic/20151119_025741_0c74_3B_AnalyticMS.tif to data/e1ae4b94-3e38-48e8-9cdb-1bc3bae259b7/2/files/PSScene4Band/20151119_025741_0c74/analytic/20151119_025741_0c74_3B_AnalyticMS.tif
downloading e1ae4b94-3e38-48e8-9cdb-1bc3bae259b7/2/files/PSScene4Band/20151119_025741_0c74/analytic/20151119_025741_0c74_3B_AnalyticMS_DN_udm.tif to data/e1ae4b94-3e38-48e8-9cdb-1bc3bae259b7/2/files/PSScene4Band/20151119_025741_0c74/analytic/20151119_025741_0c74_3B_AnalyticMS_DN_udm.tif
downloading e1ae4b94-3e38-48e8-9cdb-1bc3bae[...]<jupyter_text>Downloading as a single zipTo download all of the order assets as a single zip, the order request needs to be changed slightly with delivery instructions. After that, polling and downloading are the same.<jupyter_code>zip_delivery = {"delivery": {"single_archive": True, "archive_type": "zip"}}
request_zip = request.copy()
request_zip.update(zip_delivery)
request_zip
order_url = place_order(request_zip, auth)
poll_for_success(order_url, auth)
r = requests.get(order_url, auth=auth)
response = r.json()
results = response['_links']['results']
download_results(results)<jupyter_output>2 items to download
data/ad3a2d3f-c98a-4afe-acb5-37e7c48f3799/1/manifest.json already exists, skipping ad3a2d3f-c98a-4afe-acb5-37e7c48f3799/1/manifest.json
data/ad3a2d3f-c98a-4afe-acb5-37e7c48f3799/1/files/output.zip already exists, skipping ad3a2d3f-c98a-4afe-acb5-37e7c48f3799/1/files/output.zip
{'fraction_non_alphanumeric': 0.10551224944320713, 'fraction_numerical': 0.07196547884187082, 'mean_word_length': 5.236979166666667, 'pattern_counts': {'":': 11, '<': 42, '<?xml version=': 0, '>': 41, 'https://': 6, 'lorem ipsum': 0, 'www.': 0, 'xml': 1}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 20, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '11', 'dir': 'jupyter-structured-clean-dedup', 'id': '152703', 'license': 'Apache-2.0', 'n_tokens_mistral': 2776, 'n_tokens_neox': 2486, 'n_words': 545, 'path': 'jupyter-notebooks/orders/ordering_and_delivery.ipynb', 'repo_name': 'mapninja/notebooks', 'size': '7184'}