From 873106577aa38346e65f5e4a1e37e1a92d248ac2 Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Tue, 25 Apr 2023 11:05:10 -0700 Subject: [PATCH 01/45] Skelleton readme and file. --- examples/snippets/README.md | 1 + examples/snippets/orders_api.py | 0 2 files changed, 1 insertion(+) create mode 100644 examples/snippets/README.md create mode 100644 examples/snippets/orders_api.py diff --git a/examples/snippets/README.md b/examples/snippets/README.md new file mode 100644 index 000000000..fd038b65c --- /dev/null +++ b/examples/snippets/README.md @@ -0,0 +1 @@ +Code snippets for each function in the SDK diff --git a/examples/snippets/orders_api.py b/examples/snippets/orders_api.py new file mode 100644 index 000000000..e69de29bb From fc7455c21c1260df412286fdc3cfa924cb0e11dd Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Tue, 25 Apr 2023 13:35:38 -0700 Subject: [PATCH 02/45] Added a few more snippets. --- examples/snippets/orders_api.py | 67 +++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/examples/snippets/orders_api.py b/examples/snippets/orders_api.py index e69de29bb..732db15b3 100644 --- a/examples/snippets/orders_api.py +++ b/examples/snippets/orders_api.py @@ -0,0 +1,67 @@ +# Copyright 2023 Planet Labs PBC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +"""Example of creating and downloading multiple orders. + +This is an example of submitting two orders, waiting for them to complete, and +downloading them. The orders each clip a set of images to a specific area of +interest (AOI), so they cannot be combined into one order. + +[Planet Explorer](https://www.planet.com/explorer/) was used to define +the AOIs and get the image ids. +""" +import json +import planet + + +# create_order() +async def create_order(request): + '''Code snippet for create_order.''' + async with planet.Session() as sess: + client = sess.client('orders') + order = await client.create_order(request) + return order + + +# get_order() +async def get_order(order_id): + '''Code snippet for get_order.''' + async with planet.Session() as sess: + client = sess.client('orders') + order = await client.get_order(order_id) + return order + + +# cancel_order() +async def cancel_order(order_id): + '''Code snippet for cancel_order.''' + async with planet.Session() as sess: + client = sess.client('orders') + json_resp = await client.cancel_order(order_id) + return json.dumps(json_resp) + +# cancel_orders() + +# aggregated_order_stats() + +# download_asset() + +# download_order() + +# validate_checksum() + +# wait() + +# list_orders() + +# \ No newline at end of file From 88cf85fc03809705c3f99d9bb18ce1d0df28b813 Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Tue, 25 Apr 2023 13:54:32 -0700 Subject: [PATCH 03/45] Added a few more snippets. --- examples/snippets/orders_api.py | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/examples/snippets/orders_api.py b/examples/snippets/orders_api.py index 732db15b3..3b858e82f 100644 --- a/examples/snippets/orders_api.py +++ b/examples/snippets/orders_api.py @@ -21,6 +21,7 @@ the AOIs and get the image ids. """ import json +from pathlib import Path import planet @@ -50,18 +51,46 @@ async def cancel_order(order_id): json_resp = await client.cancel_order(order_id) return json.dumps(json_resp) + # cancel_orders() +async def cancel_orders(order_id1, order_id2): + '''Code snippet for cancel_order.''' + order_ids = [order_id1, order_id2] + async with planet.Session() as sess: + client = sess.client('orders') + json_resp = await client.cancel_order(order_ids) + return json.dumps(json_resp) + # aggregated_order_stats() +async def aggregated_order_stats(): + '''Code snippet for aggregated_order_stats.''' + async with planet.Session() as sess: + client = sess.client('orders') + json_resp = await client.aggregated_order_stats() + return json.dumps(json_resp) + # download_asset() +async def download_asset(dl_url, directory): + '''Code snippet for download_asset.''' + async with planet.Session() as sess: + client = sess.client('orders') + filename = await client.download_asset(dl_url, directory=directory) + dl_path = Path(directory, filename) + return dl_path # download_order() + # validate_checksum() + # wait() + # list_orders() -# \ No newline at end of file + +# import asyncio +# resp = asyncio.run(aggregated_order_stats()) \ No newline at end of file From 21953fd21241196314663ca878759d06bd391fc3 Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Tue, 25 Apr 2023 15:15:05 -0700 Subject: [PATCH 04/45] Added all the snippets. --- examples/snippets/orders_api.py | 38 +++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/examples/snippets/orders_api.py b/examples/snippets/orders_api.py index 3b858e82f..15ca6c981 100644 --- a/examples/snippets/orders_api.py +++ b/examples/snippets/orders_api.py @@ -80,17 +80,43 @@ async def download_asset(dl_url, directory): dl_path = Path(directory, filename) return dl_path -# download_order() + +# download_order() w/o checksum +async def download_order_without_checksum(order_id, directory): + '''Code snippet for download_order without checksum.''' + async with planet.Session() as sess: + client = sess.client('orders') + filenames = await client.download_order(order_id, directory=directory) + dl_path = Path(directory, filenames) + return dl_path -# validate_checksum() +# download_order() w checksum +async def download_order_with_checksum(order_id, directory): + '''Code snippet for download_order with checksum.''' + # Options: 'MD5' or 'SHA256' + checksum = 'MD5' + async with planet.Session() as sess: + client = sess.client('orders') + filenames = await client.download_order(order_id, directory=directory) + client.validate_checksum(Path(directory, order_id), checksum) + dl_path = Path(directory, filenames) + return dl_path # wait() +async def wait(order_id): + '''Code snippet for wait.''' + async with planet.Session() as sess: + client = sess.client('orders') + state = await client.wait(order_id) + print(state) # list_orders() - - -# import asyncio -# resp = asyncio.run(aggregated_order_stats()) \ No newline at end of file +async def list_orders(): + '''Code snippet for list_orders.''' + async with planet.Session() as sess: + client = sess.client('orders') + async for order in client.list_orders(): + print(order) From 5d57005f540da23ebd73cb8ef107a1cda78ce324 Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Tue, 25 Apr 2023 15:44:31 -0700 Subject: [PATCH 05/45] Added an order example, though may be not needed. --- examples/snippets/orders_api.py | 45 +++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/examples/snippets/orders_api.py b/examples/snippets/orders_api.py index 15ca6c981..dfbaeb23a 100644 --- a/examples/snippets/orders_api.py +++ b/examples/snippets/orders_api.py @@ -23,6 +23,7 @@ import json from pathlib import Path import planet +import asyncio # create_order() @@ -120,3 +121,47 @@ async def list_orders(): client = sess.client('orders') async for order in client.list_orders(): print(order) + + +def create_request(): + # The Orders API will be asked to mask, or clip, results to + # this area of interest. + aoi = { + "type": + "Polygon", + "coordinates": [[[-91.198465, 42.893071], [-91.121931, 42.893071], + [-91.121931, 42.946205], [-91.198465, 42.946205], + [-91.198465, 42.893071]]] + } + + # In practice, you will use a Data API search to find items, but + # for this example take them as given. + items = ['20200925_161029_69_2223', '20200925_161027_48_2223'] + + order = planet.order_request.build_request( + name='iowa_order', + products=[ + planet.order_request.product(item_ids=items, + product_bundle='analytic_udm2', + item_type='PSScene') + ], + tools=[planet.order_request.clip_tool(aoi=aoi)]) + + return order + + +async def order_example(): + # Create an order request + request = create_request() + + # Create order + order = await create_order(request) + + # Get order ID + order_id = order['id'] + + # Wait for download to be ready + await wait(order_id) + + # Download order + _ = await download_order_with_checksum(order_id, './') From 9dbcacaea9fc058de4bebe04a111b18717094737 Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Tue, 25 Apr 2023 15:45:02 -0700 Subject: [PATCH 06/45] Removed unused lib. --- examples/snippets/orders_api.py | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/snippets/orders_api.py b/examples/snippets/orders_api.py index dfbaeb23a..86b079b32 100644 --- a/examples/snippets/orders_api.py +++ b/examples/snippets/orders_api.py @@ -23,7 +23,6 @@ import json from pathlib import Path import planet -import asyncio # create_order() From a33d17fb8f3be3ebf5816f2477dcf40eeb866638 Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Tue, 25 Apr 2023 15:50:02 -0700 Subject: [PATCH 07/45] Created skeleton for data API snippets. --- examples/snippets/data_api.py | 68 +++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 examples/snippets/data_api.py diff --git a/examples/snippets/data_api.py b/examples/snippets/data_api.py new file mode 100644 index 000000000..22077d3e9 --- /dev/null +++ b/examples/snippets/data_api.py @@ -0,0 +1,68 @@ +# Copyright 2023 Planet Labs PBC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +"""Example of creating and downloading multiple orders. + +This is an example of submitting two orders, waiting for them to complete, and +downloading them. The orders each clip a set of images to a specific area of +interest (AOI), so they cannot be combined into one order. + +[Planet Explorer](https://www.planet.com/explorer/) was used to define +the AOIs and get the image ids. +""" +import json +from pathlib import Path +import planet + + +# search + + +# create_search + + +# update_search + + +# list_searches + + +# delete_search + + +# get_search + + +# run_search + + +# get_stats + + +# list_item_assets + + +# get_asset + + +# activate_asset + + +# wait_asset + + +# download_asset w/o checksum + + +# download_asset w checksum + From 69c717f17c55f871ef84d9035120b35a5af5a5a6 Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Tue, 25 Apr 2023 16:20:25 -0700 Subject: [PATCH 08/45] Added about half the snippets for data. --- examples/snippets/data_api.py | 58 ++++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 8 deletions(-) diff --git a/examples/snippets/data_api.py b/examples/snippets/data_api.py index 22077d3e9..31fe2c024 100644 --- a/examples/snippets/data_api.py +++ b/examples/snippets/data_api.py @@ -26,43 +26,85 @@ # search +async def search(item_types, search_filter, name, sort, limit): + '''Code snippet for search.''' + async with planet.Session() as sess: + client = sess.client('data') + async for item in client.search(item_types=item_types, + search_filter=search_filter, + name=name, + sort=sort, + limit=limit): + print(item) # create_search +async def create_search(item_types, search_filter, name): + '''Code snippet for create_search.''' + async with planet.Session() as sess: + client = sess.client('data') + items = await client.create_search(item_types=item_types, + search_filter=search_filter, + name=name) + print(items) # update_search +async def update_search(search_id, item_types, search_filter, name): + '''Code snippet for update_search.''' + async with planet.Session() as sess: + client = sess.client('data') + items = await client.update_search(search_id=search_id, + item_types=item_types, + search_filter=search_filter, + name=name) + print(items) # list_searches +async def list_searches(sort, search_type, limit): + '''Code snippet for list_searches.''' + async with planet.Session() as sess: + client = sess.client('data') + async for item in client.list_searches(sort=sort, + search_type=search_type, + limit=limit): + print(item) # delete_search +async def delete_search(search_id): + '''Code snippet for delete_search.''' + async with planet.Session() as sess: + client = sess.client('data') + await client.delete_search(search_id) # get_search - +async def get_search(search_id): + '''Code snippet for get_search.''' + async with planet.Session() as sess: + client = sess.client('data') + items = await client.get_search(search_id) + print(items) # run_search - # get_stats - # list_item_assets - # get_asset - # activate_asset - # wait_asset - # download_asset w/o checksum - # download_asset w checksum + +# Create search filters +def create_filters(): + pass From 0a6eb42fc5f8bfcac56c0b2137cf59163375850b Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Wed, 26 Apr 2023 10:55:56 -0700 Subject: [PATCH 09/45] Added all the snippets and a search filter example. --- examples/snippets/data_api.py | 130 +++++++++++++++++++++++++++++++--- 1 file changed, 120 insertions(+), 10 deletions(-) diff --git a/examples/snippets/data_api.py b/examples/snippets/data_api.py index 31fe2c024..768f01798 100644 --- a/examples/snippets/data_api.py +++ b/examples/snippets/data_api.py @@ -20,9 +20,11 @@ [Planet Explorer](https://www.planet.com/explorer/) was used to define the AOIs and get the image ids. """ -import json from pathlib import Path import planet +from planet import data_filter +import json +from datetime import datetime # search @@ -35,7 +37,7 @@ async def search(item_types, search_filter, name, sort, limit): name=name, sort=sort, limit=limit): - print(item) + return item # create_search @@ -46,7 +48,7 @@ async def create_search(item_types, search_filter, name): items = await client.create_search(item_types=item_types, search_filter=search_filter, name=name) - print(items) + return items # update_search @@ -58,7 +60,7 @@ async def update_search(search_id, item_types, search_filter, name): item_types=item_types, search_filter=search_filter, name=name) - print(items) + return items # list_searches @@ -69,7 +71,7 @@ async def list_searches(sort, search_type, limit): async for item in client.list_searches(sort=sort, search_type=search_type, limit=limit): - print(item) + return item # delete_search @@ -86,25 +88,133 @@ async def get_search(search_id): async with planet.Session() as sess: client = sess.client('data') items = await client.get_search(search_id) - print(items) + return items + # run_search +async def run_search(search_id): + '''Code snippet for run_search.''' + async with planet.Session() as sess: + client = sess.client('data') + async for item in client.run_search(search_id): + return item + # get_stats +async def get_stats(item_types, search_filter, interval): + '''Code snippet for get_stats.''' + async with planet.Session() as sess: + client = sess.client('data') + items = await client.get_stats(item_types=item_types, + search_filter=search_filter, + interval=interval) + return items + # list_item_assets +async def list_item_assets(item_type_id, item_id): + '''Code snippet for list_item_assets.''' + async with planet.Session() as sess: + client = sess.client('data') + assets = await client.list_item_assets(item_type_id, item_id) + return assets + # get_asset +async def get_asset(item_type, item_id, asset_type): + '''Code snippet for get_asset.''' + async with planet.Session() as sess: + client = sess.client('data') + asset = await client.get_asset(item_type, item_id, asset_type) + return asset + # activate_asset +async def activate_asset(item_type, item_id, asset_type): + '''Code snippet for activate_asset.''' + async with planet.Session() as sess: + client = sess.client('data') + asset = await client.get_asset(item_type, item_id, asset_type) + await client.activate_asset(asset) + # wait_asset +async def wait_asset(item_type, item_id, asset_type): + '''Code snippet for wait_asset.''' + async with planet.Session() as sess: + client = sess.client('data') + asset = await client.get_asset(item_type, item_id, asset_type) + _ = await client.wait_asset(asset, callback=print) -# download_asset w/o checksum -# download_asset w checksum +# download_asset w/o checksum +async def download_asset_without_checksum(item_type, + item_id, + asset_type, + filename, + directory, + overwrite): + '''Code snippet for download_asset without a checksum.''' + async with planet.Session() as sess: + client = sess.client('data') + asset = await client.get_asset(item_type, item_id, asset_type) + path = await client.download_asset(asset=asset, + filename=filename, + directory=Path(directory), + overwrite=overwrite) + return path + + +# download_asset w/ checksum +async def download_asset_with_checksum(item_type, + item_id, + asset_type, + filename, + directory, + overwrite): + '''Code snippet for download_asset with a checksum.''' + async with planet.Session() as sess: + client = sess.client('data') + asset = await client.get_asset(item_type, item_id, asset_type) + path = await client.download_asset(asset=asset, + filename=filename, + directory=Path(directory), + overwrite=overwrite) + client.validate_checksum(asset, path) + return path # Create search filters -def create_filters(): - pass +def create_search_filter(): + # Geometry you wish to clip to + with open("aoi.geojson") as f: + geom = json.loads(f.read()) + + # Build your filters with all types of requirements + date_range_filter = data_filter.date_range_filter("acquired", + gte=datetime(month=1, + day=1, + year=2017), + lte=datetime(month=1, + day=1, + year=2018)) + clear_percent_filter = data_filter.range_filter('clear_percent', 90) + cloud_cover_filter = data_filter.range_filter('cloud_cover', None, 0.1) + geom_filter = data_filter.geometry_filter(geom) + asset_filter = data_filter.asset_filter( + ["basic_analytic_4b", "basic_udm2", "ortho_visual"]) + permission_filter = data_filter.permission_filter() + std_quality_filter = data_filter.std_quality_filter() + + # Search filter containing all filters listed above + search_filter = data_filter.and_filter([ + date_range_filter, + clear_percent_filter, + cloud_cover_filter, + geom_filter, + asset_filter, + permission_filter, + std_quality_filter + ]) + + return search_filter From e89e8e26fb47ef7ab910cb2684ba800c0d4cbc3e Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Wed, 26 Apr 2023 11:16:48 -0700 Subject: [PATCH 10/45] Changed print to callback and return --- examples/snippets/orders_api.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/snippets/orders_api.py b/examples/snippets/orders_api.py index 86b079b32..aa161074e 100644 --- a/examples/snippets/orders_api.py +++ b/examples/snippets/orders_api.py @@ -109,8 +109,7 @@ async def wait(order_id): '''Code snippet for wait.''' async with planet.Session() as sess: client = sess.client('orders') - state = await client.wait(order_id) - print(state) + state = await client.wait(order_id, callback=print) # list_orders() @@ -119,7 +118,7 @@ async def list_orders(): async with planet.Session() as sess: client = sess.client('orders') async for order in client.list_orders(): - print(order) + return order def create_request(): From c83e2fea8ab9a6d846ba5442a075ea0dde482f4a Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Wed, 26 Apr 2023 11:44:05 -0700 Subject: [PATCH 11/45] Return nothing for wait. --- examples/snippets/orders_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/snippets/orders_api.py b/examples/snippets/orders_api.py index aa161074e..4957f9e98 100644 --- a/examples/snippets/orders_api.py +++ b/examples/snippets/orders_api.py @@ -109,7 +109,7 @@ async def wait(order_id): '''Code snippet for wait.''' async with planet.Session() as sess: client = sess.client('orders') - state = await client.wait(order_id, callback=print) + _ = await client.wait(order_id, callback=print) # list_orders() From bbdc717516e931817c0606b584c89958e5f9048f Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Wed, 26 Apr 2023 12:02:35 -0700 Subject: [PATCH 12/45] Added all snippets. TO DO: create request. --- examples/snippets/subscriptions_api.py | 82 ++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 examples/snippets/subscriptions_api.py diff --git a/examples/snippets/subscriptions_api.py b/examples/snippets/subscriptions_api.py new file mode 100644 index 000000000..8619a9b86 --- /dev/null +++ b/examples/snippets/subscriptions_api.py @@ -0,0 +1,82 @@ +# Copyright 2023 Planet Labs PBC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +"""Example of creating and downloading multiple orders. + +This is an example of submitting two orders, waiting for them to complete, and +downloading them. The orders each clip a set of images to a specific area of +interest (AOI), so they cannot be combined into one order. + +[Planet Explorer](https://www.planet.com/explorer/) was used to define +the AOIs and get the image ids. +""" +import planet + + +def create_request(): + pass + + +# list_subscriptions +async def list_subscriptions(status, limit): + '''Code snippet for list_subscriptions.''' + async with planet.Session() as sess: + client = sess.client('subscriptions') + async for sub in client.list_subscriptions(status=status, limit=limit): + return sub + + +# create_subscription +async def create_subscription(request): + '''Code snippet for create_subscription.''' + async with planet.Session() as sess: + client = sess.client('subscriptions') + sub = await client.create_subscription(request) + return sub + + +# cancel_subscription +async def cancel_subscription(subscription_id): + '''Code snippet for cancel_subscription.''' + async with planet.Session() as sess: + client = sess.client('subscriptions') + _ = await client.cancel_subscription(subscription_id) + + +# update_subscription +async def update_subscription(subscription_id, request): + '''Code snippet for update_subscription.''' + async with planet.Session() as sess: + client = sess.client('subscriptions') + sub = await client.update_subscription(subscription_id, request) + return sub + + +# get_subscription +async def get_subscription(subscription_id): + '''Code snippet for get_subscription.''' + async with planet.Session() as sess: + client = sess.client('subscriptions') + sub = await client.get_subscription(subscription_id) + return sub + + +# get_results +async def get_results(subscription_id, status, limit): + '''Code snippet for get_results.''' + async with planet.Session() as sess: + client = sess.client('subscriptions') + async for result in client.get_results(subscription_id, + status=status, + limit=limit): + return result From 34a2a61430ba19d64fcb590f1294d8965dcf82d6 Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Wed, 26 Apr 2023 12:18:07 -0700 Subject: [PATCH 13/45] Added docstring to order request example. --- examples/snippets/orders_api.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/snippets/orders_api.py b/examples/snippets/orders_api.py index 4957f9e98..3201191a7 100644 --- a/examples/snippets/orders_api.py +++ b/examples/snippets/orders_api.py @@ -122,6 +122,8 @@ async def list_orders(): def create_request(): + '''Create an order request.''' + # The Orders API will be asked to mask, or clip, results to # this area of interest. aoi = { From 74c9ab95e986959c0c31c80d197d4349b5701d87 Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Wed, 26 Apr 2023 12:18:31 -0700 Subject: [PATCH 14/45] Added docstring to search filter creation. --- examples/snippets/data_api.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/snippets/data_api.py b/examples/snippets/data_api.py index 768f01798..ce62c12fb 100644 --- a/examples/snippets/data_api.py +++ b/examples/snippets/data_api.py @@ -186,6 +186,8 @@ async def download_asset_with_checksum(item_type, # Create search filters def create_search_filter(): + '''Create a search filter.''' + # Geometry you wish to clip to with open("aoi.geojson") as f: geom = json.loads(f.read()) From 8595f243e696b5fbf3f41ec73a504741b498a1e1 Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Wed, 26 Apr 2023 12:19:44 -0700 Subject: [PATCH 15/45] Added a create request function. --- examples/snippets/subscriptions_api.py | 28 +++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/examples/snippets/subscriptions_api.py b/examples/snippets/subscriptions_api.py index 8619a9b86..49a26e3f9 100644 --- a/examples/snippets/subscriptions_api.py +++ b/examples/snippets/subscriptions_api.py @@ -21,10 +21,36 @@ the AOIs and get the image ids. """ import planet +from datetime import datetime +from planet.subscription_request import build_request, catalog_source, amazon_s3, harmonize_tool def create_request(): - pass + '''Create a subscription request.''' + + # Geometry you wish to clip to + geom = { + "coordinates": + [[[139.5648193359375, + 35.42374884923695], [140.1031494140625, 35.42374884923695], + [140.1031494140625, + 35.77102915686019], [139.5648193359375, 35.77102915686019], + [139.5648193359375, 35.42374884923695]]], + "type": + "Polygon" + } + source = catalog_source(["PSScene"], ["ortho_analytic_4b"], + geom, + datetime(2021, 3, 1)) + delivery = amazon_s3(ACCESS_KEY_ID, SECRET_ACCESS_KEY, "test", "us-east-1") + tools = harmonize_tool("Sentinel-2") + + # Build your subscriptions request + subscription_request = build_request(name='test_subscription', + source=source, + delivery=delivery, + tools=tools) + return subscription_request # list_subscriptions From 3688ebe8ef946f44c33fd459afad56d64412a9d7 Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Wed, 26 Apr 2023 12:25:19 -0700 Subject: [PATCH 16/45] Added keywords. --- examples/snippets/subscriptions_api.py | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/examples/snippets/subscriptions_api.py b/examples/snippets/subscriptions_api.py index 49a26e3f9..f916e1b18 100644 --- a/examples/snippets/subscriptions_api.py +++ b/examples/snippets/subscriptions_api.py @@ -39,11 +39,15 @@ def create_request(): "type": "Polygon" } - source = catalog_source(["PSScene"], ["ortho_analytic_4b"], - geom, - datetime(2021, 3, 1)) - delivery = amazon_s3(ACCESS_KEY_ID, SECRET_ACCESS_KEY, "test", "us-east-1") - tools = harmonize_tool("Sentinel-2") + source = catalog_source(item_types=["PSScene"], + asset_types=["ortho_analytic_4b"], + geometry=geom, + start_time=datetime(2021, 3, 1)) + delivery = amazon_s3(aws_access_key_id="ACCESS-KEY-ID", + aws_secret_access_key="SECRET_ACCESS_KEY", + bucket="test_bucket", + aws_region="us-east-1") + tools = harmonize_tool(target_sensor="Sentinel-2") # Build your subscriptions request subscription_request = build_request(name='test_subscription', @@ -67,7 +71,7 @@ async def create_subscription(request): '''Code snippet for create_subscription.''' async with planet.Session() as sess: client = sess.client('subscriptions') - sub = await client.create_subscription(request) + sub = await client.create_subscription(request=request) return sub @@ -76,7 +80,7 @@ async def cancel_subscription(subscription_id): '''Code snippet for cancel_subscription.''' async with planet.Session() as sess: client = sess.client('subscriptions') - _ = await client.cancel_subscription(subscription_id) + _ = await client.cancel_subscription(subscription_id=subscription_id) # update_subscription @@ -84,7 +88,8 @@ async def update_subscription(subscription_id, request): '''Code snippet for update_subscription.''' async with planet.Session() as sess: client = sess.client('subscriptions') - sub = await client.update_subscription(subscription_id, request) + sub = await client.update_subscription(subscription_id=subscription_id, + request=request) return sub @@ -93,7 +98,7 @@ async def get_subscription(subscription_id): '''Code snippet for get_subscription.''' async with planet.Session() as sess: client = sess.client('subscriptions') - sub = await client.get_subscription(subscription_id) + sub = await client.get_subscription(subscription_id=subscription_id) return sub @@ -102,7 +107,7 @@ async def get_results(subscription_id, status, limit): '''Code snippet for get_results.''' async with planet.Session() as sess: client = sess.client('subscriptions') - async for result in client.get_results(subscription_id, + async for result in client.get_results(subscription_id=subscription_id, status=status, limit=limit): return result From d719f218d3e3f1b6811ca2877b1690297ddf4be8 Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Wed, 26 Apr 2023 12:32:02 -0700 Subject: [PATCH 17/45] Added keywords. --- examples/snippets/orders_api.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/examples/snippets/orders_api.py b/examples/snippets/orders_api.py index 3201191a7..5f1cbfdd7 100644 --- a/examples/snippets/orders_api.py +++ b/examples/snippets/orders_api.py @@ -30,7 +30,7 @@ async def create_order(request): '''Code snippet for create_order.''' async with planet.Session() as sess: client = sess.client('orders') - order = await client.create_order(request) + order = await client.create_order(request=request) return order @@ -39,7 +39,7 @@ async def get_order(order_id): '''Code snippet for get_order.''' async with planet.Session() as sess: client = sess.client('orders') - order = await client.get_order(order_id) + order = await client.get_order(order_id=order_id) return order @@ -48,7 +48,7 @@ async def cancel_order(order_id): '''Code snippet for cancel_order.''' async with planet.Session() as sess: client = sess.client('orders') - json_resp = await client.cancel_order(order_id) + json_resp = await client.cancel_order(order_id=order_id) return json.dumps(json_resp) @@ -58,7 +58,7 @@ async def cancel_orders(order_id1, order_id2): order_ids = [order_id1, order_id2] async with planet.Session() as sess: client = sess.client('orders') - json_resp = await client.cancel_order(order_ids) + json_resp = await client.cancel_order(order_ids=order_ids) return json.dumps(json_resp) @@ -76,7 +76,8 @@ async def download_asset(dl_url, directory): '''Code snippet for download_asset.''' async with planet.Session() as sess: client = sess.client('orders') - filename = await client.download_asset(dl_url, directory=directory) + filename = await client.download_asset(location=dl_url, + directory=directory) dl_path = Path(directory, filename) return dl_path @@ -98,7 +99,7 @@ async def download_order_with_checksum(order_id, directory): checksum = 'MD5' async with planet.Session() as sess: client = sess.client('orders') - filenames = await client.download_order(order_id, directory=directory) + filenames = await client.download_order(order_id=order_id, directory=directory) client.validate_checksum(Path(directory, order_id), checksum) dl_path = Path(directory, filenames) return dl_path @@ -109,7 +110,7 @@ async def wait(order_id): '''Code snippet for wait.''' async with planet.Session() as sess: client = sess.client('orders') - _ = await client.wait(order_id, callback=print) + _ = await client.wait(order_id=order_id, callback=print) # list_orders() From f6c24cd79ca729d02a625ffdfeee40679b0fd891 Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Wed, 26 Apr 2023 12:32:19 -0700 Subject: [PATCH 18/45] Updated comment. --- examples/snippets/subscriptions_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/snippets/subscriptions_api.py b/examples/snippets/subscriptions_api.py index f916e1b18..cd53ca455 100644 --- a/examples/snippets/subscriptions_api.py +++ b/examples/snippets/subscriptions_api.py @@ -28,7 +28,7 @@ def create_request(): '''Create a subscription request.''' - # Geometry you wish to clip to + # Area of interest for the subscription geom = { "coordinates": [[[139.5648193359375, From ff1526ada55679ba9b1c00fa3a110a143fcea219 Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Wed, 26 Apr 2023 12:33:53 -0700 Subject: [PATCH 19/45] linting --- examples/snippets/orders_api.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/snippets/orders_api.py b/examples/snippets/orders_api.py index 5f1cbfdd7..ef4cf5740 100644 --- a/examples/snippets/orders_api.py +++ b/examples/snippets/orders_api.py @@ -99,7 +99,8 @@ async def download_order_with_checksum(order_id, directory): checksum = 'MD5' async with planet.Session() as sess: client = sess.client('orders') - filenames = await client.download_order(order_id=order_id, directory=directory) + filenames = await client.download_order(order_id=order_id, + directory=directory) client.validate_checksum(Path(directory, order_id), checksum) dl_path = Path(directory, filenames) return dl_path From a81d00b961ec8884a26ce97ffa2e815347e66c1a Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Wed, 26 Apr 2023 12:35:57 -0700 Subject: [PATCH 20/45] linting --- examples/snippets/subscriptions_api.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/snippets/subscriptions_api.py b/examples/snippets/subscriptions_api.py index cd53ca455..a331692e8 100644 --- a/examples/snippets/subscriptions_api.py +++ b/examples/snippets/subscriptions_api.py @@ -22,7 +22,10 @@ """ import planet from datetime import datetime -from planet.subscription_request import build_request, catalog_source, amazon_s3, harmonize_tool +from planet.subscription_request import (build_request, + catalog_source, + amazon_s3, + harmonize_tool) def create_request(): From fdb21da617da1e86b971aa9258c61b1c38535f06 Mon Sep 17 00:00:00 2001 From: Chris Holmes Date: Thu, 27 Apr 2023 14:25:12 -0700 Subject: [PATCH 21/45] new structure for sdk docs, based on cli --- docs/python/sdk-data.md | 557 ++++++++++++++++++++++ docs/python/sdk-intro.md | 17 + docs/python/sdk-orders.md | 764 +++++++++++++++++++++++++++++++ docs/python/sdk-subscriptions.md | 476 +++++++++++++++++++ 4 files changed, 1814 insertions(+) create mode 100644 docs/python/sdk-data.md create mode 100644 docs/python/sdk-intro.md create mode 100644 docs/python/sdk-orders.md create mode 100644 docs/python/sdk-subscriptions.md diff --git a/docs/python/sdk-data.md b/docs/python/sdk-data.md new file mode 100644 index 000000000..752e5571f --- /dev/null +++ b/docs/python/sdk-data.md @@ -0,0 +1,557 @@ +--- +title: Python SDK for Data API Tutorial +--- + +TODO: Update narrative and snippets to be SDK instead of CLI. + +## Introduction + +The `planet data` CLI commands enable interaction with the [Data API](https://developers.planet.com/docs/apis/data/), +which lets you search Planet’s catalog (including select public datasets like Sentinel 2 and Landsat 8). +Currently the CLI has focused on the core search functionality, implementing +[Quick Search](https://developers.planet.com/docs/apis/data/reference/#tag/Item-Search/operation/QuickSearch) +and [stats](https://developers.planet.com/docs/apis/data/reference/#tag/Item-Stats/operation/Stats) plus some +partial saved search functionality. + +## `data search` command basics + +At this point you should have completed [Step 5](../get-started/quick-start-guide.md#step-5-search-for-planet-imagery) +of the quick start guide, and run your first full data search command: + +```sh +planet data search PSScene --filter filter.json > recent-psscene.json +``` + +This saves the descriptions of the latest 100 standard-quality scenes you have permissions to download in a file, that you can open and look at. + +### Pretty printing + +You will likely notice that this file is quite wide, with one very long line for each Planet +item returned. You can make for a more readable file by using the `--pretty` flag: + +```sh +planet data search --pretty PSScene --filter filter.json > recent-psscene.json +``` + +The `--pretty` flag is built into most of the CLI calls. But you can also achieve the +same effect by using another CLI program: `jq`. It is a very powerful library, providing +extensive manipulation of JSON, but simply +piping any JSON output through it prints it in a more readable form. So the following +command will do the same thing as the previous one: + +```sh +planet data search PSScene --filter filter.json | jq > recent-psscene.json +``` + +You can read a bit [more about jq]((cli-intro.md#jq) in the CLI intro. + +### Output to stdin + +You also don't have to save the output to a file. If you don't redirect it into a file then +it will just print out on the console. + +```sh +planet data search PSScene --filter filter.json +``` + +If you enter this command you’ll see the output stream by. Here you can use jq again, and +it’ll often give you nice syntax highlighting in addition to formatting. + +```sh +planet data search PSScene --filter filter.json | jq +``` + +### Create filter and search in one call + +Using a unix command called a 'pipe', which looks like `|`, you can skip the step of saving to disk, +passing the output of the `data filter` command directly to be the input of the `data search` +command: + +```sh +planet data filter --permission --std-quality | planet data search --pretty PSScene --filter - +``` + +Note the dash (`-`), which explicitly tells the CLI to use the output from the call that is piped into it. + +You can learn more about the pipe command, as well as the `>` command above in the +[Piping & redirection section](cli-intro.md#piping-redirection) of the CLI Introduction. + +### Search without filtering + +If no filtering is required, the search command can be called directly: + +```sh +planet data search PSScene +``` + +This outputs the last 100 scenes. + + +### Search on Item Type + +These first searches were done on the [PSScene](https://developers.planet.com/docs/data/psscene/) 'item type', but you +can use any [Item Type](https://developers.planet.com/docs/apis/data/items-assets/#item-types) that Planet offers in +its catalog. The item type is the first argument of the `search` command, followed by the 'filter'. Note that +you can specify any number of item types here: + +```sh +planet data search PSScene,Sentinel2L1C,Landsat8L1G,SkySatCollect +``` + +This will search for all the most recent images captured by PlanetScope, SkySat, Sentinel 2 and Landsat 8 satellites. +Note that you’ll likely mostly see PlanetScope results, as they generate far more individual images than the others. +The filter you specify will apply to all item types, but not all filters work against all satellites, so you may +inadvertently filter some out if you are filtering specific properties. + +### Limits + +By default the `search` command returns only the 100 first scenes. But with the CLI you can set any limit, and the SDK +under the hood will automatically page through all the results from the API. + +```sh +planet data search --limit 3000 PSScene +``` + +Note you can also do a call with no limits if you set the limit to `0`. Though don't use this haphazardly, or you’ll be +generating a lot of JSON from your request. It’s best to use it with a number of filters to constrain the search, so +you don't get hundreds of millions of results. + +### Output as valid GeoJSON + +By default the output of Planet’s Data API is [newline-delimited GeoJSON](https://stevage.github.io/ndgeojson/), which +is much better for streaming. While more and more programs will understand the format, the CLI also provides +the `planet collect` method to transform the output from the Data API to valid GeoJSON. You just pipe the end +output to it: + +```sh +planet data search PSScene | planet collect - +``` + +If you want to visualize this you can save it as a file: + +```sh +planet data search PSScene | planet collect - > planet-search.geojson +``` + +This you can then open with your favorite GIS program, or see this +[geometry visualization](cli-plus-tutorial.md#geometry-inputs) section for some ideas that flow a bit better with +the command-line. + +### Sort + +You can also specify the sorting with your searches. The default sort is ordered by the most recent published +images. But you can also sort by `acquired`, which is often more useful. You can sort in ascending or +descending order. The options are are: + + * 'acquired asc' + * 'acquired desc' + * 'published asc' + * 'published desc' + +This lets you do things like get the ID of the most recent SkySat image taken (and that you have permissions to download): + +```sh +planet data search SkySatCollect --sort 'acquired desc' --limit 1 +``` + +And you can also just get the ID, using `jq` + +```sh +planet data search SkySatCollect --sort 'acquired desc' --limit 1 - | jq -r .id +``` + +## Filtering + +### Run a search on a bounding box + +Most searches you’ll likely want to run on a geometry. To try this out you can use the following bounding box +of Iowa. You can copy it and save as a file called `geometry.geojson` + +```json +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -93.7353, + 41.6236 + ], + [ + -92.2741, + 41.6236 + ], + [ + -92.2741, + 42.3747 + ], + [ + -93.7353, + 42.3747 + ], + [ + -93.7353, + 41.6236 + ] + ] + ] + } + } + ] +} +``` + +!!!note ".geojson and .json files both work" + Here we save it as .geojson, but you can also save it as .json. The CLI is happy with any file + extension, even .txt, but different extensions may make it easier to open the files with other + programs. What’s important is that the text inside the file is valid geojson. + +And then run it with this command: + +```sh +planet data filter --geom geometry.geojson | planet data search PSScene --filter - +``` + +Note that by default all searches with the command-line return 100 results, but you can easily increase that with +the `--limit` flag: + +```sh +planet data filter --geom geometry.geojson | planet data search --limit 500 PSScene --filter - +``` + +Creating geometries for search can be annoying in a command-line workflow, but there are some ideas in the +[Advanced CLI Tutorial](cli-plus-tutorial.md#geometry-inputs). + +### Date Filter + +Some of the most common filtering is by date. You could get all imagery acquired before August 2021: + +```sh +planet data filter --date-range acquired lt 2021-08-01 \ + | planet data search PSScene --filter - +``` + +The 'operator' in this case is 'less than' (`lt`). The options are: + * `gt` - greater than + * `gte` - greater than or equal to + * `lt` - less than + * `lte` - less than or equal to + +You must specify which date field you want to use, either `acquired` or `published`. + +You can use the flags multiple times, and they are logically 'AND'-ed together, so you can +do a search for all images in July of 2021: + +```sh +planet data filter \ + --date-range acquired gte 2021-07-01 \ + --date-range acquired lt 2021-08-01 | \ +planet data search PSScene --filter - +``` + +The date input understands [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339) and +[ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) formats. You can specify just the date, +or include the time, to search for all Planetscope images acquired within 5 seconds at a time +on July 1st 2021: + +```sh +planet data filter \ + --date-range acquired gte 2021-07-01:06:20:10 \ + --date-range acquired lt 2021-07-01:06:20:15 \ + | planet data search PSScene --filter - +``` + +### Range Filter + +The range filter uses the same operators as the date filter, but works against any numerical property. The most useful +of these tend to be ones about cloudy pixels. For example you can search for data with clear pixels greater than 90%: + +```sh +planet data filter --range clear_percent gt 90 \ + | planet data search PSScene --filter - +``` + +### String-In Filter + +For properties that are strings you can use the `string-in` filter. For example search for all planetscope imagery +with PS2 instrument: + +```sh +planet data filter --string-in instrument PS2 \ + | planet data search PSScene --filter - +``` + +You can specify multiple strings to match, with a comma: + +```sh +planet data filter --string-in instrument PS2,PSB.SD \ + | planet data search PSScene --filter - +``` + +Another example is to select all data in a single strip: + +```sh +planet data filter --string-in strip_id 5743640 \ + | planet data search PSScene --filter - +``` + +Note that in all these commands we are piping the results into the search. If you don't include the pipe then you’ll +get the filter output, which can be interesting to inspect to see exactly what is sent to the server. + +### Filter by asset + +You can limit your search to only data with a particular asset, for example search just for 8-band analytic assets: + +```sh +planet data filter --asset ortho_analytic_8b_sr \ + | planet data search PSScene --filter - +``` + +Or 8-band assets that also have a UDM. + +```sh +planet data filter --asset ortho_analytic_8b_sr --asset udm2 \ + | planet data search PSScene --filter - +``` + +You can find the list of available assets in each Item Type Page, like +[available assets](https://developers.planet.com/docs/data/psscene/#available-asset-types) for PSScene. You can see +[a table of all Item Types](https://developers.planet.com/docs/data/psscene/#available-asset-types), which links to +the page for each with their list of asset types. + +Note that the asset filter doesn't perform any validation, so if your searches aren't returning anything check to make +sure you got the asset right, and it’s valid for the item-types you’re searching. + +### Permission Filter + +By default, no search filters are applied. However, many people want to search only for data they have access to download +that are of standard (aka not test) quality. Therefore, these filters can be easily added with the `--permission` and +`--std-quality` flags. To use the permission and standard quality filters: + +```sh +planet data filter --permission --std-quality --asset ortho_analytic_8b_sr \ + | planet data search PSScene --filter - +``` + +## Stats + +One command that can be quite useful for getting a sense of a search is the `stats` command. It works with the +exact same filters as the main `search` command, but it just returns a count of the results, which can be +binned by different time periods. + +This can be used for things like getting the number of items in a strip: + +```sh +planet data filter --string-in strip_id 5743640 \ + | planet data stats PSScene --interval day --filter - +``` + +Or the number of PlanetScope scenes collected in California each year: + +``` +curl -s https://raw.githubusercontent.com/ropensci/geojsonio/main/inst/examples/california.geojson \ + | planet data filter --geom - \ + | planet data stats PSScene --interval year --filter - \ + | jq +``` + +Will result in output like: + +```json +{ + "buckets": [ + { + "count": 5261, + "start_time": "2014-01-01T00:00:00.000000Z" + }, + { + "count": 34377, + "start_time": "2015-01-01T00:00:00.000000Z" + }, + { + "count": 112331, + "start_time": "2016-01-01T00:00:00.000000Z" + }, + { + "count": 504377, + "start_time": "2017-01-01T00:00:00.000000Z" + }, + { + "count": 807086, + "start_time": "2018-01-01T00:00:00.000000Z" + }, + { + "count": 806945, + "start_time": "2019-01-01T00:00:00.000000Z" + }, + { + "count": 776757, + "start_time": "2020-01-01T00:00:00.000000Z" + }, + { + "count": 684095, + "start_time": "2021-01-01T00:00:00.000000Z" + }, + { + "count": 323557, + "start_time": "2022-01-01T00:00:00.000000Z" + }, + { + "count": 56733, + "start_time": "2023-01-01T00:00:00.000000Z" + } + ], + "interval": "year", + "utc_offset": "+0h" +} +``` + +You can see how the yearly output of Planet has gone up, though it actually went down in 2022 as the upgrade to SuperDove meant much larger swaths, so the number of individual items went down even as we captured the whole earth. + +The API does not support an 'all time' interval to get the total of all collections for an area, but +you can easily use [jq]((cli-intro.md#jq) to total up the results of an interval count: + +```sh +curl -s https://raw.githubusercontent.com/ropensci/geojsonio/main/inst/examples/california.geojson \ + | planet data filter --geom - \ + | planet data stats PSScene --interval year --filter - \ + | jq '.buckets | map(.count) | add' + +``` + +Just pipe the results to `jq '.buckets | map(.count) | add'` and it’ll give you the total of all the values. + +## Asset Activation and Download + +While we recommend using the Orders or Subscriptions API’s to deliver Planet data, the Data API has the capability +to activate and download data. Only one asset can be activated at once, and there is no clipping or additional +processing of the data like the great 'tools' of Subscriptions & Orders. But the advantage is that it can often +be faster for working with a small number of items & assets. + +### Activate an Asset + +All items in the Data API have a list of assets. This includes the main imagery geotiff files, usually in a few +different formats, and also accompanying files like the [Usable Data Mask](https://developers.planet.com/docs/data/udm-2/) + (UDM) and JSON metadata. You can't immediately download them, as they must first be created in the cloud, known as +'activated'. To activate data you need to get its item id, plus the name of the asset - the available ones +can be seen by looking at the Item’s JSON. Once you have the item id and asset type you can run the CLI + +```sh +planet data asset-activate PSScene 20230310_083933_71_2431 ortho_udm2 +``` + +This will kick off the activation process, and the command should return immediately. In this example +we’re activating the UDM, which is one of the most common things to do through the Data API, to +first get a sense of where there are clouds before placing a proper clipping order. + +### Download an Asset + +Once an asset is ready you can use `asset-download` with a similar command: + +```sh +planet data asset-download PSScene 20230310_083933_71_2431 ortho_udm2 +``` + +While some assets activate almost immediately (if another user has requested +it recently), some can take a few minutes. If you try to download it before it’s active +you’ll get a message like: `Error: asset missing ["location"] entry. Is asset active?` + +Thankfully the CLI has the great `asset-wait` command will complete when the asset is activated: + +```sh +planet data asset-wait PSScene 20230310_083933_71_2431 ortho_udm2 +``` + +And you can pair with download so that as soon as the asset is active it’ll be downloaded: + +```sh +planet data asset-wait PSScene 20230310_083933_71_2431 ortho_udm2 && \ +planet data asset-download PSScene 20230310_083933_71_2431 ortho_udm2 +``` + +Download has a few different options: + + * `--directory` lets you specify a base directory to put the asset in. + * `--filename` assigns a custom name to the downloaded file. + * `--overwrite` will overwrite files if they already exist. + * `--checksum` checks to make sure the file you downloaded is the exact same as the one on the server. This can be useful if you script thousands of files to download to detect any corruptions in that process. + +## Saved Searches + +The core `planet data search` command uses what is called a 'quick search' in the API. The API +also supports what we call a '[saved searches](https://developers.planet.com/docs/apis/data/quick-saved-search/#saved-search)', +and the CLI supports this as well. + +### List Searches + +You can easily get a list of all the searches you’ve made: + +```sh +planet data search-list +``` + +This defaults to returning 100 results, but you can use `--limit` to return the number you +specify, and set it to 0 to return all your searches. By default this returns both +your quick searches and saved searches, but you can also limit to to only return +your saved searches: + +```sh +planet data search-list --search-type saved +``` + +If you’ve not created any saved searches it may be an empty list. You can create +saved searches with Planet Explorer, or it’s also easy with the command-line. + +### Create Search + +To make a new saved search you can use the exact same filter syntax as the regular `search` command, +but you must also add a 'name' to refer to the search by: + +```sh +planet data filter --geom geometry.geojson \ + | planet data search-create PSScene --name 'my saved search' --filter - +``` + +### Run Search + +When you save a new search you’ll get back the JSON describing the search. If you grab the 'id' field from it then +you can get the current results for that search: + +```sh +planet data search-run da963039dbe94573a3ac9e4629d065b6 +``` + +This is just like running a normal (quick) search, and takes similar arguments: `--limit` and `--pretty`, +and also the same [sort](#sort) parameter (`--sort`). You can also run any previous `quick` search. +They don't have names (the ID is just used as the name), but they are saved in the system and can be +executed again. Searches (except those with an end date that has passed) show new results +if run later and match newly acquired imagery. + +### Update Search + +You can also update an existing search to have a different set of values. This takes similar arguments, and +will overwrite the previous values. + +```sh +planet data filter --string-in instrument PS2,PSB.SD \ + | planet data search-update da963039dbe94573a3ac9e4629d065b6 \ + --name 'my updated search' \ + --filter - SkySatCollect +``` + +### Delete Search + +If you’re no longer using a search you can delete it: + +```sh +planet data search-delete da963039dbe94573a3ac9e4629d065b6 +``` + +If the deletion was successful the command-line won't print out anything except a new line. If the +search didn't exist it will say `Error: {"general": [{"message": "The requested search id does not exist"}], "field": {}}`. +You can also delete `quick` searches, which would remove them from your history. diff --git a/docs/python/sdk-intro.md b/docs/python/sdk-intro.md new file mode 100644 index 000000000..971024cf6 --- /dev/null +++ b/docs/python/sdk-intro.md @@ -0,0 +1,17 @@ +--- +title: Python SDK Introduction +--- + +## Python & Geospatial + +- lots of libraries + +## v2 vs v1 + +## Getting going + +### Your first call + +TODO: narrative on doing auth, creating session, making a data api call +TODO: snippets for the above. No filter, just defaults, but display results in some way. + diff --git a/docs/python/sdk-orders.md b/docs/python/sdk-orders.md new file mode 100644 index 000000000..27f5af174 --- /dev/null +++ b/docs/python/sdk-orders.md @@ -0,0 +1,764 @@ +--- +title: Python SDK for Orders API Tutorial +--- + +TODO: Update narrative and snippets to be SDK instead of CLI. + +## Introduction + +The `planet orders` command enables interaction with the [Orders API](https://developers.planet.com/apis/orders/), +which lets you activate and download Planet data products in bulk, and apply various +'tools' to your processes. This tutorial takes you through all the main capabilities +of the CLI for creating and downloading orders. It depends on several more advanced +command-line concepts, but this tutorial should let you get a sense of what you can do, +with enough examples that you should be able to adapt the commands for what you want to do. +If you’re interested in deeper understanding what is going on +then check out our [CLI Concepts](cli-intro.md) guide. + +## Core Workflows + +### See Recent Orders + +You can use the `list` command to show your recent orders: + +```sh +planet orders list +``` + +If you’ve not placed any orders with Explorer, the CLI or the API directly, then the results +of this call will be blank, so you may want to try out some of the create order commands below. + +Sometimes that list gets too long, so you can put a limit on how many are returned: + +```sh +planet orders list --limit 5 +``` + +You can also filter orders by their `state`, which can be useful to just see orders in +progress: + +```sh +planet orders list --state running +``` + +The other options are queued, failed, success, partial and cancelled. + +Note you can also get a nice list online as well, at https://www.planet.com/account/#/orders + +### Recent Orders with Formatting + +You can also print the list of orders more nicely: + +```sh +planet orders list --pretty +``` + +The `--pretty` flag is built into most Planet CLI commands, and it formats the JSON to be +more readable. + +You can also use `jq`, a powerful command-line JSON-processing tool, that is mentioned in +the [CLI introduction]((cli-intro.md#jq). + +```sh +planet orders list | jq +``` + +Piping any output through jq will format it nicely and do syntax highlighting. You can +also `jq` to just show select information, which can be useful for getting a quick sense +of the state of the state of things and pull out id’s for other operations: + +```sh +planet orders list | jq -rs '.[] | "\(.id) \(.created_on) \(.state) \(.name)"' +``` + +You can customize which fields you want to show by changing the values. + +### Number of recent orders + +You can use jq to process the output for more insight, like +get a count of how many recent orders you’ve done. + +```sh +planet orders list | jq -s length +``` + +This uses `-s` to collect the output into a single array, and `length` then tells the +length of the array. + +### Info on an Order + +For a bit more information about an order, including the location of any downloads, use +the `get` command, using the order id. + +```sh +planet orders get 782b414e-4e34-4f31-86f4-5b757bd062d7 +``` + +### Create an Order Request + +To create an order you need a name, a [bundle](https://developers.planet.com/apis/orders/product-bundles-reference/), + one or more id’s, and an [item type](https://developers.planet.com/docs/apis/data/items-assets/#item-types): + +First lets get the ID of an item you have download access to, using the Data API: + +```sh +planet data filter | planet data search PSScene --limit 1 --filter - | jq -r .id +``` + +If you don't have access to PlanetScope data then replace PSScene with SkySatCollect. +Then make the following call: + +```sh +planet orders request \ + --item-type PSScene \ + --bundle analytic_sr_udm2 \ + --name 'My First Order' \ + 20220605_124027_64_242b +``` + +Running the above command should output the JSON needed to create an order: + +```json +{"name": "My First Order", "products": [{"item_ids": ["20220605_124027_64_242b"], "item_type": "PSScene", "product_bundle": "analytic_sr_udm2"}], "metadata": {"stac": {}}} +``` + +You can also use `jq` here to make it a bit more readable: + +```sh +planet orders request \ + --item-type PSScene \ + --bundle analytic_sr_udm2 \ + --name 'My First Order' \ + 20220605_124027_64_242b \ + | jq +``` + +```json +{ + "name": "My First Order", + "products": [ + { + "item_ids": [ + "20220605_124027_64_242b" + ], + "item_type": "PSScene", + "product_bundle": "analytic_sr_udm2" + } + ], + "metadata": { + "stac": {} + } +} +``` + +### Save an Order Request + +The above command just prints out the necessary JSON to create an order. To actually use it you can +save the output into a file: + +```sh +planet orders request \ + --item-type PSScene \ + --bundle analytic_sr_udm2 \ + --name "My First Order" \ + 20220605_124027_64_242b \ + > request-1.json +``` + +Note that `\` just tells the command-line to treat the next line as the same one. It’s used here so it’s +easier to read, but you can still copy and paste the full line into your command-line and it should work. + +This saves the above JSON in a file called `request-1.json` + +### Create an Order + +From there you can create the order with the request you just saved: + +```sh +planet orders create request-1.json +``` + +The output of that command is the JSON returned from the server, that reports the status: + +```json +{ + "_links": { + "_self": "https://api.planet.com/compute/ops/orders/v2/2887c43b-26be-4bec-8efe-cb9e94f0ef3d" + }, + "created_on": "2022-11-29T22:49:24.478Z", + "error_hints": [], + "id": "2887c43b-26be-4bec-8efe-cb9e94f0ef3d", + "last_message": "Preparing order", + "last_modified": "2022-11-29T22:49:24.478Z", + "metadata": { + "stac": {} + }, + "name": "My First Order", + "products": [ + { + "item_ids": [ + "20220605_124027_64_242b" + ], + "item_type": "PSScene", + "product_bundle": "analytic_sr_udm2" + } + ], + "state": "queued" +} +``` + +Note the default output will be a bit more 'flat' - if you'd like the above formatting in your +command-line just use `jq` as above: `planet orders create request-1.json | jq` (but remember +if you run that command again it will create a second order). + +### Create Request and Order in One Call + +Using a unix command called a 'pipe', which looks like `|`, you can skip the step of saving to disk, +passing the output of the `orders request` command directly to be the input of the `orders create` +command: + +```sh +planet orders request --item-type PSScene --bundle analytic_sr_udm2 --name 'Two Item Order' \ +20220605_124027_64_242b,20220605_124025_34_242b | planet orders create - +``` + +The Planet CLI is designed to work well with piping, as it aims at small commands that can be +combined in powerful ways, so you’ll see it used in a number of the examples. + +### Download an order + +To download all files in an order you use the `download` command: + +```sh +planet orders download 65df4eb0-e416-4243-a4d2-38afcf382c30 +``` + +Note this only works when the order is ready for download. To do that you can +keep running `orders get` until the `state` is `success`. Or for a better +way see the next example. + +### Wait then download an order + +The `wait` command is a small, dedicated command that polls the server to +see if an order is ready for downloading, showing the status. It’s not +so useful by itself, but can be combined with the `download` command to +only start the download once the order is ready: + +```sh +planet orders wait 65df4eb0-e416-4243-a4d2-38afcf382c30 \ +&& planet orders download 65df4eb0-e416-4243-a4d2-38afcf382c30 +``` + +This uses the logical AND operator (`&&`) to say "don't run the second command +until the first is done". + +### Save order ID + +You can also use a unix variable to store the order id of your most recently placed order, +and then use that for the wait and download commands: + +```sh +orderid=$(planet orders list --limit 1 | jq -r .id) +planet orders wait $orderid +planet orders download $orderid +``` + +This can be nicer than copying and pasting it in. + +You could also save the id right when you place the order: + +```sh +orderid=`planet orders create request-1.json | jq -r .id` +``` + +To check the current value of `orderid` just run `echo $orderid`. + +### Create an order and download when ready + +You can then combine these all into one call, to create the order and +download it when it’s available: + +```sh +id=`planet orders create request-1.json | jq -r '.id'` && \ + planet orders wait $id && planet orders download $id +``` + +### Download to a different directory + +You can use the `--directory` flag to save the output to a specific directory. This +call saves it to a directory called `psscene`, at whatever location you are at +currently: + +```sh +mkdir psscene +planet orders download 782b414e-4e34-4f31-86f4-5b757bd062d7 --directory psscene +``` + +You can also specify absolute directories (in this case to my desktop): + +```sh +planet orders download \ + 782b414e-4e34-4f31-86f4-5b757bd062d7 \ + --directory /Users/cholmes/Desktop/ +``` + +### Verify checksum + +The `--checksum` command will do an extra step to make sure the file you got +wasn't corrupted along the way (during download, etc). It checks that the bytes +downloaded are the same as the ones on the server. By default it doesn't show +anything if the checksums match. + +```sh +planet orders download 782b414e-4e34-4f31-86f4-5b757bd062d7 --checksum MD5 +``` + +This command isn't often necessary in single download commands, but is quite +useful if you are downloading thousands of files with a script, as the likelihood +of at least one being corrupted in creases + +## Tools with orders + +Now we’ll dive into the variety of ways to customize your order. These can all be +combined with all the commands listed above. + +### Clipping + +The most used tool is the `clip` operation, which lets you pass a geometry to the +Orders API and it creates new images that only have pixels within the geometry you +gave it. The file given with the `--clip` option should contain valid [GeoJSON](https://geojson.org/). +It can be a Polygon geometry, a Feature, or a FeatureClass. If it is a FeatureClass, +only the first Feature is used for the clip geometry. + +Example: `geometry.geojson` +``` +{ + "geometry": + { + "type": "Polygon", + "coordinates": + [ + [ + [ + -48.4974827, + -1.4967008 + ], + [ + -48.4225714, + -1.4702869 + ], + [ + -48.3998028, + -1.4756259 + ], + [ + -48.4146752, + -1.49898376 + ], + [ + -48.4737304, + -1.5277508 + ], + [ + -48.4974827, + -1.4967008 + ] + ] + ] + } +} +``` + +We’ll work with a geojson that is already saved. You should download the +[geometry](https://raw.githubusercontent.com/planetlabs/planet-client-python/main/docs/cli/request-json/geometry.geojson) +(and you can see it [on github](https://github.com/planetlabs/planet-client-python/blob/main/docs/cli/request-json/geometry.geojson) +or it is also stored in the repo in the [request-json/](request-json/) directory. + +You can move that geometry to your current directory and use the following command, or +tweak the geometry.geojson to refer to where you downloaded it. + +```sh +planet orders request \ + --item-type PSScene \ + --bundle analytic_sr_udm2 \ + --clip geometry.geojson \ + --name clipped-geom \ + 20220605_124027_64_242b \ + | planet orders create - +``` + +### Additional Tools + +Since clip is so heavily used it has its own dedicated command in the CLI. All +the other tools use the `--tools` option, that points to a file. The file should +contain JSON that follows the format for a toolchain, the "tools" section of an order. +The toolchain options and format are given in +[Creating Toolchains](https://developers.planet.com/apis/orders/tools/#creating-toolchains). + +Example: `tools.json` +``` +[ + { + "toar": { + "scale_factor": 10000 + } + }, + { + "reproject": { + "projection": "WGS84", + "kernel": "cubic" + } + }, + { + "tile": { + "tile_size": 1232, + "origin_x": -180, + "origin_y": -90, + "pixel_size": 2.7056277056e-05, + "name_template": "C1232_30_30_{tilex:04d}_{tiley:04d}" + } + } +] +``` + +!!!note Note + Future of the versions of the CLI will likely add `tools` convenience methods, + so composite, harmonize and other tools work like `--clip`. You can follow issue + [#601](https://github.com/planetlabs/planet-client-python/issues/601): + comment there if you'd like to see it prioritized + +### Compositing + +Ordering two scenes is easy, just add another id: + +```sh +planet orders request \ + --item-type PSScene \ + --bundle analytic_sr_udm2 \ + --name 'Two Scenes' \ + 20220605_124027_64_242b,20220605_124025_34_242b \ + | planet orders create - +``` + +And then you can composite them together, using the 'tools' json. You can +use this, just save it into a file called [tools-composite.json](https://raw.githubusercontent.com/planetlabs/planet-client-python/main/docs/cli/request-json/tools-composite.json). + +```json +[ + { + "composite": { + } + } +] +``` + +Once you’ve got it saved you call the `--tools` flag to refer to the JSON file, and you +can pipe that to `orders create`. + +```sh +planet orders request \ + --item-type PSScene \ + --bundle analytic_sr_udm2 \ + --name 'Two Scenes Composited' \ + 20220605_124027_64_242b,20220605_124025_34_242b \ + --no-stac \ + --tools tools-composite.json \ + | planet orders create - +``` + +Note that we add the `--no-stac` option as [STAC Metadata](#stac-metadata) is not yet supported by the composite +operation, but STAC metadata is requested by default with the CLI. + +### Output as COG + +If you'd like to ensure the above order is a Cloud-Optimized Geotiff then you can request it +as COG in the file format tool. + +```json +[ + { + "file_format": { + "format": "COG" + } + } +] +``` + +The following command just shows the output with [tools-cog.json](https://raw.githubusercontent.com/planetlabs/planet-client-python/main/docs/cli/request-json/tools-cog.json): + +```sh +planet orders request \ + --item-type PSScene \ + --bundle analytic_sr_udm2 \ + --name 'COG Order' \ + 20220605_124027_64_242b,20220605_124025_34_242b \ + --tools tools-cog.json +``` + +As shown above you can also pipe that output directly in to `orders create`. + +### Clip & Composite + +To clip and composite you need to specify the clip in the tools (instead of `--clip`), as you can +not use `--clip` and `--tools` in the same call. There is not yet CLI calls to generate the `tools.json`, +so you can just use the [following json](https://raw.githubusercontent.com/planetlabs/planet-client-python/main/docs/cli/request-json/tools-clip-composite.json): + +```json +[ + { + "composite": {} + }, + { + "clip": { + "aoi": { + "type": "Polygon", + "coordinates": [ + [ + [ + -48.492541, + -1.404126 + ], + [ + -48.512879, + -1.504392 + ], + [ + -48.398017, + -1.52127 + ], + [ + -48.380419, + -1.423805 + ], + [ + -48.492541, + -1.404126 + ] + ] + ] + } + } + } +] +``` + +```sh +planet orders request \ + --item-type PSScene \ + --bundle analytic_sr_udm2 \ + --no-stac \ + --name 'Two Scenes Clipped and Composited' \ + 20220605_124027_64_242b,20220605_124025_34_242b \ + --tools tools-clip-composite.json \ + | planet orders create - +``` + +One cool little trick is that you can even stream in the JSON directly with `curl`, piping it into the request: + +```sh +curl -s https://raw.githubusercontent.com/planetlabs/planet-client-python/main/docs/cli/request-json/tools-clip-composite.json \ + | planet orders request \ + --item-type PSScene \ + --bundle analytic_sr_udm2 \ + --name 'Streaming Clip & Composite' \ + --no-stac \ + 20220605_124027_64_242b,20220605_124025_34_242b \ + --tools - \ + | planet orders create - +``` + +### Harmonize + +The harmonize tool allows you to compare data to different generations of satellites by radiometrically harmonizing imagery captured by one satellite instrument type to imagery captured by another. To harmonize your data to a sensor you must define the sensor you wish to harmonize with in your `tools.json`. Currently, only "PS2" (Dove Classic) and "Sentinel-2" are supported as target sensors. The Sentinel-2 target only harmonizes PSScene surface reflectance bundle types (`analytic_8b_sr_udm2`, `analytic_sr_udm2`). The PS2 target only works on analytic bundles from Dove-R (`PS2.SD`). + +```json +[ + { + "harmonize": { + "target_sensor": "Sentinel-2" + } + } +] +``` + +You may create an order request by calling [`tools-harmonize.json`](https://raw.githubusercontent.com/planetlabs/planet-client-python/main/docs/cli/request-json/tools-harmonize.json) with `--tools`. + +```sh +planet orders request --item-type PSScene --bundle analytic_sr_udm2 --name 'Harmonized data' 20200925_161029_69_2223 --tools tools-harmonize.json +``` + +## More options + +### STAC Metadata + +A relatively recent addition to Planet’s orders delivery is the inclusion of [SpatioTemporal Asset Catalog](https://stacspec.org/en) +(STAC) metadata in Orders. STAC metadata provides a more standard set of JSON fields that work with +many GIS and geospatial [STAC-enabled tools](https://stacindex.org/ecosystem). The CLI `orders request` command currently requests +STAC metadata by default, as the STAC files are small and often more useful than the default JSON metadata. +You can easily turn off STAC output request with the `--no-stac` command: + +```sh +planet orders request \ + --item-type PSScene \ + --bundle visual \ + --name 'No STAC' \ + --no-stac \ + 20220605_124027_64_242b +``` + +Currently this needs to be done for any 'composite' operation, as STAC output from composites is not yet +supported (but is coming). You can explicitly add `--stac`, but it is the default, so does not need to +be included. For more information about Planet’s STAC output see the [Orders API documentation](https://developers.planet.com/apis/orders/delivery/#stac-metadata). + +### Cloud Delivery + +Another option is to delivery your orders directly to a cloud bucket, like AWS S3 or Google Cloud Storage. +The file given with the `--cloudconfig` option should contain JSON that follows +the options and format given in +[Delivery to Cloud Storage](https://developers.planet.com/docs/orders/delivery/#delivery-to-cloud-storage). + +An example would be: + +Example: `cloudconfig.json` + +```json +{ + "amazon_s3": { + "aws_access_key_id": "aws_access_key_id", + "aws_secret_access_key": "aws_secret_access_key", + "bucket": "bucket", + "aws_region": "aws_region" + }, + "archive_type": "zip" +} +``` + +### Using Orders output as input + +One useful thing to note is that the order JSON that reports status and location is a valid Orders API request. +It reports all the parameters that were used to make the previous order, but you can also use it directly as a +request. So the following call is a quick way to exactly redo a previous order request: + +```sh +planet orders get | planet orders create - +``` + +Realistically you'd more likely want to get a previous order and then change it in some way (new id’s, different +tools, etc.). You can remove the 'extra' JSON fields that report on status if you'd like, but the Orders +API will just ignore them if they are included in a request. + +There is planned functionality to make it easy to 'update' an existing order, so you can easily grab a past order +and use the CLI to customize it. + +### Basemaps Orders + +One of the newer features in Planet’s Orders API is the ability to [order basemaps](https://developers.planet.com/apis/orders/basemaps/). +The CLI does not yet support a 'convenience' method to easily create the JSON - you unfortunately +can't yet use `planet orders request` to help form an orders request. But all the other CLI functionality +supports ordering basemaps through the Orders API. + +You’ll need to use a full orders request JSON. + +```json +{ + "name": "basemap order with geometry", + "source_type": "basemaps", + "order_type":"partial", + "products": [ + { + "mosaic_name": "global_monthly_2022_01_mosaic", + "geometry":{ + "type": "Polygon", + "coordinates":[ + [ + [4.607406, 52.353994], + [4.680005, 52.353994], + [4.680005, 52.395523], + [4.607406, 52.395523], + [4.607406, 52.353994] + ] + ] + } + } + ], + "tools": [ + {"merge": {}}, + {"clip": {}} + ] +} +``` + +Once you’ve got the JSON, the other commands are all the same. Use create to submit it to the API: + +```sh +planet orders create basemap-order.json +``` + +See the status of the order you just submitted: + +```sh +planet orders list --limit 1 +``` + +Extract the ID: + +```sh +planet orders list --limit 1 | jq -r .id +``` + +Use that ID to wait and download when it’s ready: + +```sh +orderid=605b5472-de61-4563-88ae-d43417d3ed96 +planet orders wait $orderid +planet orders download $orderid +``` + +You can also list only the orders you submitted that are for basemaps, using `jq` to filter client side: + +```sh +planet orders list | jq -s '.[] | select(.source_type == "basemaps")' +``` + +#### Bringing it all together + +The cool thing is you can combine the data and order commands, to make calls +like ordering the most recent skysat image that was published: + +```sh +latest_id=$(planet data filter \ + | planet data search SkySatCollect \ + --sort 'acquired desc' \ + --limit 1 \ + --filter - \ + | jq -r .id) + +planet orders request \ + --item-type SkySatCollect \ + --bundle analytic \ + --name 'SkySat Latest' \ + $latest_id \ + | planet orders create - +``` + +Or get the 5 latest cloud free images in an area and create an order that clips to that area, using +[geometry.geojson](data/geometry.geojson) from above: + +```sh +ids=$(planet data filter --geom geometry.geojson --range clear_percent gt 90 \ + | planet data search PSScene --limit 5 --filter - \ + | jq -r .id \ + | tr '\n' ',' \ + | sed 's/.$//' +) +planet orders request \ + --item-type PSScene \ + --bundle analytic_sr_udm2 \ + --name 'Clipped Scenes' \ + $ids \ + --clip geometry.geojson \ + | planet orders create - +``` + +This one uses some advanced unix capabilities like `sed` and `tr`, along with unix variables, so more +properly belongs in the [CLI Tips & Tricks](cli-tips-tricks.md), but we’ll leave it here to give a taste of what’s possible. diff --git a/docs/python/sdk-subscriptions.md b/docs/python/sdk-subscriptions.md new file mode 100644 index 000000000..a252f8e82 --- /dev/null +++ b/docs/python/sdk-subscriptions.md @@ -0,0 +1,476 @@ +--- +title: Python SDK for Subscriptions API Tutorial +--- + +TODO: Update narrative and snippets to be SDK instead of CLI. + +## Introduction + +The `planet subscriptions` command enables interaction with the +[Subscriptions API](https://developers.planet.com/apis/subscriptions/) +that make it possible to set up a recurring search criteria. Using `planet subscriptions`, you can automatically process +and deliver new imagery to a cloud bucket. It also has a powerful 'backfill' capability +to bulk order historical imagery to your area of interest. This tutorial takes you +through the main commands available in the CLI. + +## Core Workflows + +### Create a Subscription + +Since there is no UI to easily create subscriptions we’ll start with making a new one. + +```json +{ + "name": "First Subscription", + "source": { + "type": "catalog", + "parameters": { + "asset_types": [ + "ortho_analytic_8b" + ], + "end_time": "2023-11-01T00:00:00Z", + "geometry": { + "coordinates": [ + [ + [ + 139.5648193359375, + 35.42374884923695 + ], + [ + 140.1031494140625, + 35.42374884923695 + ], + [ + 140.1031494140625, + 35.77102915686019 + ], + [ + 139.5648193359375, + 35.77102915686019 + ], + [ + 139.5648193359375, + 35.42374884923695 + ] + ] + ], + "type": "Polygon" + }, + "item_types": [ + "PSScene" + ], + "start_time": "2023-03-17T04:08:00.0Z" + } + }, + "tools": [ + { + "type": "clip", + "parameters": { + "aoi": { + "coordinates": [ + [ + [ + 139.5648193359375, + 35.42374884923695 + ], + [ + 140.1031494140625, + 35.42374884923695 + ], + [ + 140.1031494140625, + 35.77102915686019 + ], + [ + 139.5648193359375, + 35.77102915686019 + ], + [ + 139.5648193359375, + 35.42374884923695 + ] + ] + ], + "type": "Polygon" + } + } + } + ], + "delivery": { + "type": "google_cloud_storage", + "parameters": { + "bucket": "pl-sub-bucket", + "credentials": "" + } + } +} +``` + +This is a full subscriptions JSON request, with the credentials redacted, so you’ll have +to replace your own for it to work. Below we’ll show the convenience methods that will +help create a custom one more easily. If you'd like to get things working for now then +just replace the 'delivery' section with your cloud credentials, see the +[core subscriptions delivery docs](https://developers.planet.com/docs/subscriptions/delivery/) +for more information. + +To create a new subscription with the CLI, use the `create` command and the json file you just created: + +```sh +planet subscriptions create my-subscription.json +``` + +!!!note "Note" + The above command assumes that you’ve saved the subscriptions JSON as `my-subscription.json` and that you’ve replaced the delivery information with your own bucket and credentials. + +### List Subscriptions + +Now that you’ve got a subscription working you can make use of the other commands. + +```sh +planet subscriptions list +``` + +outputs the JSON for your first 100 subscriptions. If you'd like more you can set the `--limit` +parameter higher, or you can set it to 0 and there will be no limit. + +You can get nicer formatting with `--pretty` or pipe it into `jq`, just like the other Planet +CLI’s. + +The `list` command also supports filtering by the status of the subscription: + +```sh +planet subscriptions list --status running +``` + +gives you just the currently active subscriptions. The other available statuses are: +`cancelled`, `preparing`, `pending`, `completed`, `suspended`, and `failed`. + +### Get Subscription + +To get the full details on a single subscription you can take the id from your list and use the +`get` command: + +```sh +planet subscriptions get cb817760-1f07-4ee7-bba6-bcac5346343f +``` + +### Subscription Results + +To see what items have been delivered to your cloud bucket you can use the `results` command: + +```sh +planet subscriptions results cb817760-1f07-4ee7-bba6-bcac5346343f +``` + +By default this displays the first 100 results. As with other commands, you can use the `--limit` param to +set a higher limit, or set it to 0 to see all results (this can be quite large with subscriptions results). + +You can also filter by status: + +```sh +planet subscriptions results --status processing +``` + +The available statuses are `created`, `queued`, `processing`, `failed`, and `success`. Note it’s quite useful +to use `jq` to help filter out results as well. + +### Update Subscription + +You can update a subscription that is running, for example to change the 'tools' it’s using or to alter +its geometry. To do this you must submit the full subscription creation JSON, so the easiest way is to +get it with `get` and then alter the values. + +```sh +planet subscriptions update cb817760-1f07-4ee7-bba6-bcac5346343f \ + my-updated-subscriptions.json +``` + +### Cancel a subscription + +Cancelling a subscription is simple with the CLI: + +```sh +planet subscriptions cancel cb817760-1f07-4ee7-bba6-bcac5346343f +``` + +That will stop the subscription from producing any more results, but it will stay in the system so you can +continue to list and get it. + +## Subscription Request Conveniences + +There are a couple of commands that can assist in creating the subscription JSON, used for creation and updates. +A subscription request is a pretty complicated command, consisting of a search, a cloud delivery, as well as +tools to process the data plus notifications on the status. + +### Catalog Request + +The first place to start is the `request-catalog` command, which generates all the JSON for the +[catalog source](https://developers.planet.com/docs/subscriptions/source/#catalog-source-type) block. The core +of this is quite similar to a Data API search request, though with more required fields. The minimal +required commands would be a request like: + +```sh +planet subscriptions request-catalog \ + --item-types PSScene \ + --asset-types ortho_analytic_8b \ + --geometry geometry.geojson \ + --start-time 2023-03-17T04:08:00.0Z +``` + +You request which item types you want to deliver, and the asset types for it. Note that the `asset-types` are a bit +different than the `--bundle` command in Orders, a bundle is a set of asset-types. You can see the list of asset types +for [PSScene](https://developers.planet.com/docs/data/psscene/#available-asset-types), [SkySatCollect](https://developers.planet.com/docs/data/skysatcollect/), +and [SkySatScene](https://developers.planet.com/docs/data/skysatscene/#available-asset-types). The other item-types +also have similar listings of their asset types. For the required `start-time` and optional `end-time` you must +use dates formatted as RFC 3339 or ISO 8601 formats. A nice time converter is available at [time.lol](https://time.lol/). +Just select 'ISO 8601' (third one on the list), or 'RFC 3339' (8th on the list). + +#### Geometry + +In this case we are using a locally saved `geometry.geojson`, which would look like the following if you wanted +it to match the subscription creation request at the top of this documentation page: + +```json +{ + "coordinates": + [ + [ + [ + 139.5648193359375, + 35.42374884923695 + ], + [ + 140.1031494140625, + 35.42374884923695 + ], + [ + 140.1031494140625, + 35.77102915686019 + ], + [ + 139.5648193359375, + 35.77102915686019 + ], + [ + 139.5648193359375, + 35.42374884923695 + ] + ] + ], + "type": "Polygon" +} +``` + +Note this is just the coordinates of either a polygon or multipolygon - the operation +is not flexible to input like the orders command. + +#### RRule + +RRule lets you specify a subscription that repeats at various time intervals: + +```sh +planet subscriptions request-catalog \ + --item-types PSScene \ + --asset-types ortho_analytic_8b \ + --geometry geometry.geojson \ + --start-time 2023-03-17T04:08:00.0Z \ + --rrule 'FREQ=MONTHLY;BYMONTH=3,4,5,6,7,8,9,10' +``` + +For more information on the `rrule` parameter see the [recurrence rules](https://developers.planet.com/docs/subscriptions/source/#rrules-recurrence-rules) +documentation. + +#### Filter + +You can pass in a filter from the data API: + +```sh +planet data filter --range clear_percent gt 90 > filter.json +planet subscriptions request-catalog \ + --item-types PSScene \ + --asset-types ortho_analytic_8b \ + --geometry geometry.geojson \ + --start-time 2022-08-24T00:00:00-07:00 \ + --filter filter.json +``` + +And you can even pipe it in directly: + +```sh +planet data filter --range clear_percent gt 90 \ + | planet subscriptions request-catalog \ + --item-types PSScene \ + --asset-types ortho_analytic_8b \ + --geometry geometry.geojson \ + --start-time 2022-08-24T00:00:00-07:00 \ + --filter - +``` + +Do not bother with geometry or date filters, as they will be ignored in favor of the `--start-time` and `--geometry` values that are required. + +#### Saving the output + +You’ll likely want to save the output of your `request-catalog` call to disk, so that you can more easily use it in constructing the complete subscription +request. + +```sh +planet data filter --range clear_percent gt 90 > filter.json +planet subscriptions request-catalog \ + --item-types PSScene \ + --asset-types ortho_analytic_8b \ + --geometry geometry.geojson \ + --start-time 2022-08-24T00:00:00-07:00 \ + --filter filter.json > request-catalog.json +``` + +### Subscription Tools + +Now we’ll dive into some of the tools options for subscriptions. These are quite similar to the tools for +orders, but unfortunately the syntax is subtly different, and there are less tools supported. Just like +for Orders, future of the versions of the CLI will likely add `tools` convenience methods, you can follow issue +[#601](https://github.com/planetlabs/planet-client-python/issues/601). + +#### Clipping + +The most used tool is the `clip` operation, which lets you pass a geometry to the +Subscriptions API and it creates new images that only have pixels within the geometry you +gave it. We’ll use the same geometry from [above](#geometry), as it is quite +typical to use the same subscription geometry as the clip geometry, so you don't get +any pixels outside of your area of interest (99.9% of all subscriptions use the clip +tool, so it’s strongly recommended to also use clip). The proper 'clip' tool for it +would be: + +```json +[ + { + "type": "clip", + "parameters": { + "aoi": { + "type": "Polygon", + "coordinates": [ + [ + [ + -163.828125, + -44.59046718130883 + ], + [ + 181.7578125, + -44.59046718130883 + ], + [ + 181.7578125, + 78.42019327591201 + ], + [ + -163.828125, + 78.42019327591201 + ], + [ + -163.828125, + -44.59046718130883 + ] + ] + ] + } + } + } +] +``` + +You can save this tools as `tools.json` to include in the `subscriptions request` +command. + +#### Additional Tools + +There are some other tools that are often good to include. To use more than one tool +just put them in an array in the JSON: + +The toolchain options and format are given in +[Supported Tools](https://developers.planet.com/docs/subscriptions/tools/#supported-tools) +section of the subscriptions docs: + +Example: `more-tools.json` +``` +[ + { + "type": "toar", + "parameters": + { + "scale_factor": 10000 + } + }, + { + "type": "reproject", + "parameters": + { + "projection": "WGS84", + "kernel": "cubic" + } + }, + { + "type": "harmonize", + "parameters": + { + "target_sensor": "Sentinel-2" + } + }, + { + "type": "file_format", + "parameters": + { + "format": "COG" + } + } +] +``` + +### Delivery + +One other essential block is the `delivery` JSON. Like with tools there is no convenience +method, as of yet. You must write out the JSON for this section. +You can find the full documentation for the delivery options in +the [Subscriptions Delivery documentation](https://developers.planet.com/docs/subscriptions/delivery/). + +An example of a delivery.json file that you would save as a file to pass into the +`subscriptions request` command is: + +```json +{ + "type": "azure_blob_storage", + "parameters": + { + "account": "accountname", + "container": "containername", + "sas_token": "sv=2017-04-17u0026si=writersr=cu0026sig=LGqc", + "storage_endpoint_suffix": "core.windows.net" + } +} +``` + +The main documentation page also has the parameters for Google Cloud, AWS and Oracle. + +### Subscriptions Request + +Once you’ve got all your sub-blocks of JSON saved you’re ready to make a complete +subscriptions request with the `subscriptions request` command: + +```sh +planet subscriptions request \ + --name 'First Subscription' \ + --source request-catalog.json \ + --tools tools.json \ + --delivery cloud-delivery.json \ + --pretty +``` + +The above will print it nicely out so you can see the full request. You can write it out +as a file, or pipe it directly into `subscriptions create` or `subscriptions update`: + +```sh +planet subscriptions request \ + --name 'First Subscription' \ + --source request-catalog.json \ + --tools tools.json \ + --delivery cloud-delivery.json \ + | planet subscriptions create - +``` From 70269e9aa8cac2bff8536c91258a90f29188e3c5 Mon Sep 17 00:00:00 2001 From: Chris Holmes Date: Thu, 27 Apr 2023 14:25:33 -0700 Subject: [PATCH 22/45] new structure for sdk docs, based on cli --- mkdocs.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mkdocs.yml b/mkdocs.yml index c7b3bdd4e..af7910026 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -81,6 +81,10 @@ nav: - cli/cli-reference.md - "Python": - python/sdk-guide.md + - python/sdk-intro.md + - python/sdk-data.md + - python/sdk-orders.md + - python/sdk-subscriptions.md - python/sdk-reference.md - "Resources": - resources/index.md From 00191ba2bd311907d9757ac31dbd4ec69194ebd0 Mon Sep 17 00:00:00 2001 From: Chris Holmes Date: Thu, 27 Apr 2023 14:48:23 -0700 Subject: [PATCH 23/45] fleshed out subscriptions docs for SDK --- docs/python/sdk-subscriptions.md | 183 +++++++++++++------------------ 1 file changed, 76 insertions(+), 107 deletions(-) diff --git a/docs/python/sdk-subscriptions.md b/docs/python/sdk-subscriptions.md index a252f8e82..9f5630796 100644 --- a/docs/python/sdk-subscriptions.md +++ b/docs/python/sdk-subscriptions.md @@ -6,12 +6,12 @@ TODO: Update narrative and snippets to be SDK instead of CLI. ## Introduction -The `planet subscriptions` command enables interaction with the +The `SubscriptionsClient` enables interaction with the [Subscriptions API](https://developers.planet.com/apis/subscriptions/) -that make it possible to set up a recurring search criteria. Using `planet subscriptions`, you can automatically process -and deliver new imagery to a cloud bucket. It also has a powerful 'backfill' capability -to bulk order historical imagery to your area of interest. This tutorial takes you -through the main commands available in the CLI. +that make it possible to set up a recurring search criteria. Using the subscriptions api +you can automatically process and deliver new imagery to a cloud bucket. It also +has a powerful 'backfill' capability to bulk order historical imagery to your area of interest. +This tutorial takes you through the main commands available for subscriptions in the SDK ## Core Workflows @@ -113,8 +113,9 @@ just replace the 'delivery' section with your cloud credentials, see the [core subscriptions delivery docs](https://developers.planet.com/docs/subscriptions/delivery/) for more information. -To create a new subscription with the CLI, use the `create` command and the json file you just created: +To create a new subscription with the CLI, use the `create_subscription` method and the json file you just created: +TODO: Python snippet here: ```sh planet subscriptions create my-subscription.json ``` @@ -126,6 +127,7 @@ planet subscriptions create my-subscription.json Now that you’ve got a subscription working you can make use of the other commands. +TODO: Python snippet here, should probably have it print too: ```sh planet subscriptions list ``` @@ -133,11 +135,15 @@ planet subscriptions list outputs the JSON for your first 100 subscriptions. If you'd like more you can set the `--limit` parameter higher, or you can set it to 0 and there will be no limit. +TODO: Update narrative here, maybe example? How do we get python to print json nicely? Or does it do it by default? + You can get nicer formatting with `--pretty` or pipe it into `jq`, just like the other Planet CLI’s. -The `list` command also supports filtering by the status of the subscription: +The `list_subscriptions` method also supports filtering by the status of the subscription: + +TODO: Python snippet here: ```sh planet subscriptions list --status running ``` @@ -148,16 +154,18 @@ gives you just the currently active subscriptions. The other available statuses ### Get Subscription To get the full details on a single subscription you can take the id from your list and use the -`get` command: +`get_subscription` method: +TODO: Python snippet here: ```sh planet subscriptions get cb817760-1f07-4ee7-bba6-bcac5346343f ``` ### Subscription Results -To see what items have been delivered to your cloud bucket you can use the `results` command: +To see what items have been delivered to your cloud bucket you can use the `get_results` method: +TODO: Python snippet here: ```sh planet subscriptions results cb817760-1f07-4ee7-bba6-bcac5346343f ``` @@ -167,18 +175,21 @@ set a higher limit, or set it to 0 to see all results (this can be quite large w You can also filter by status: +TODO: Python snippet here: ```sh planet subscriptions results --status processing ``` -The available statuses are `created`, `queued`, `processing`, `failed`, and `success`. Note it’s quite useful -to use `jq` to help filter out results as well. +The available statuses are `created`, `queued`, `processing`, `failed`, and `success`. ### Update Subscription You can update a subscription that is running, for example to change the 'tools' it’s using or to alter its geometry. To do this you must submit the full subscription creation JSON, so the easiest way is to -get it with `get` and then alter the values. +get it with `get_subscription` and then alter the values. + +TODO: Python snippet here - is there a way to programmatically update the resulting json? Could be nice to show that +like change the asset type from 8 band to 4 band ```sh planet subscriptions update cb817760-1f07-4ee7-bba6-bcac5346343f \ @@ -187,8 +198,9 @@ planet subscriptions update cb817760-1f07-4ee7-bba6-bcac5346343f \ ### Cancel a subscription -Cancelling a subscription is simple with the CLI: +Cancelling a subscription is simple with the SDK: +TODO: Python snippet here: ```sh planet subscriptions cancel cb817760-1f07-4ee7-bba6-bcac5346343f ``` @@ -202,13 +214,14 @@ There are a couple of commands that can assist in creating the subscription JSON A subscription request is a pretty complicated command, consisting of a search, a cloud delivery, as well as tools to process the data plus notifications on the status. -### Catalog Request +### Catalog Source -The first place to start is the `request-catalog` command, which generates all the JSON for the +The first place to start is the `catalog-source` command, which generates all the JSON for the [catalog source](https://developers.planet.com/docs/subscriptions/source/#catalog-source-type) block. The core of this is quite similar to a Data API search request, though with more required fields. The minimal required commands would be a request like: +TODO: Python snippet here: ```sh planet subscriptions request-catalog \ --item-types PSScene \ @@ -268,6 +281,7 @@ is not flexible to input like the orders command. RRule lets you specify a subscription that repeats at various time intervals: +TODO: Python snippet here: ```sh planet subscriptions request-catalog \ --item-types PSScene \ @@ -284,6 +298,7 @@ documentation. You can pass in a filter from the data API: +TODO: Python snippet here: ```sh planet data filter --range clear_percent gt 90 > filter.json planet subscriptions request-catalog \ @@ -294,25 +309,14 @@ planet subscriptions request-catalog \ --filter filter.json ``` -And you can even pipe it in directly: - -```sh -planet data filter --range clear_percent gt 90 \ - | planet subscriptions request-catalog \ - --item-types PSScene \ - --asset-types ortho_analytic_8b \ - --geometry geometry.geojson \ - --start-time 2022-08-24T00:00:00-07:00 \ - --filter - -``` - Do not bother with geometry or date filters, as they will be ignored in favor of the `--start-time` and `--geometry` values that are required. #### Saving the output -You’ll likely want to save the output of your `request-catalog` call to disk, so that you can more easily use it in constructing the complete subscription +You may want to save the output of your `catalog-source` to disk, so that you can use it in the future to construct the complete subscription request. +TODO: Python snippet here: ```sh planet data filter --range clear_percent gt 90 > filter.json planet subscriptions request-catalog \ @@ -337,7 +341,11 @@ Subscriptions API and it creates new images that only have pixels within the geo gave it. We’ll use the same geometry from [above](#geometry), as it is quite typical to use the same subscription geometry as the clip geometry, so you don't get any pixels outside of your area of interest (99.9% of all subscriptions use the clip -tool, so it’s strongly recommended to also use clip). The proper 'clip' tool for it +tool, so it’s strongly recommended to also use clip). + +TODO: Make the JSON just the geometry, and show python snippet for the clip tool + +The proper 'clip' tool for it would be: ```json @@ -380,97 +388,58 @@ would be: You can save this tools as `tools.json` to include in the `subscriptions request` command. -#### Additional Tools +#### File Format Tool -There are some other tools that are often good to include. To use more than one tool -just put them in an array in the JSON: +TODO: Narrative on file format +TODO: Python snippet here: -The toolchain options and format are given in -[Supported Tools](https://developers.planet.com/docs/subscriptions/tools/#supported-tools) -section of the subscriptions docs: +#### Harmonize Tool -Example: `more-tools.json` -``` -[ - { - "type": "toar", - "parameters": - { - "scale_factor": 10000 - } - }, - { - "type": "reproject", - "parameters": - { - "projection": "WGS84", - "kernel": "cubic" - } - }, - { - "type": "harmonize", - "parameters": - { - "target_sensor": "Sentinel-2" - } - }, - { - "type": "file_format", - "parameters": - { - "format": "COG" - } - } -] -``` +TODO: Narrative on file format +TODO: Python snippet here: + +#### Reproject Tool + +TODO: Narrative on file format +TODO: Python snippet here: + +#### TOAR Tool + +TODO: Narrative on file format +TODO: Python snippet here: + +#### Band Math Tool + +TODO: Narrative on file format +TODO: Python snippet here: ### Delivery -One other essential block is the `delivery` JSON. Like with tools there is no convenience -method, as of yet. You must write out the JSON for this section. +One other essential part of the request is the `delivery` - the cloud delivery. You can find the full documentation for the delivery options in the [Subscriptions Delivery documentation](https://developers.planet.com/docs/subscriptions/delivery/). -An example of a delivery.json file that you would save as a file to pass into the -`subscriptions request` command is: +#### S3 Delivery -```json -{ - "type": "azure_blob_storage", - "parameters": - { - "account": "accountname", - "container": "containername", - "sas_token": "sv=2017-04-17u0026si=writersr=cu0026sig=LGqc", - "storage_endpoint_suffix": "core.windows.net" - } -} -``` +TODO: Narrative on file format +TODO: Python snippet here: -The main documentation page also has the parameters for Google Cloud, AWS and Oracle. +#### Azure Delivery -### Subscriptions Request +TODO: Narrative on file format +TODO: Python snippet here: -Once you’ve got all your sub-blocks of JSON saved you’re ready to make a complete -subscriptions request with the `subscriptions request` command: +#### Google Cloud Delivery -```sh -planet subscriptions request \ - --name 'First Subscription' \ - --source request-catalog.json \ - --tools tools.json \ - --delivery cloud-delivery.json \ - --pretty -``` +TODO: Narrative on file format +TODO: Python snippet here: -The above will print it nicely out so you can see the full request. You can write it out -as a file, or pipe it directly into `subscriptions create` or `subscriptions update`: +#### Oracle Cloud Delivery -```sh -planet subscriptions request \ - --name 'First Subscription' \ - --source request-catalog.json \ - --tools tools.json \ - --delivery cloud-delivery.json \ - | planet subscriptions create - -``` +TODO: Narrative on file format +TODO: Python snippet here: + +### Subscriptions Request + +TODO: Narrative on making a request that you've built up with convenience methods +TODO: Python snippet here: \ No newline at end of file From 74e945918856784f751385ff40e3900dc451c13d Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Mon, 1 May 2023 09:39:11 -0700 Subject: [PATCH 24/45] Added pymdownx.snippets as a MD ext. --- mkdocs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/mkdocs.yml b/mkdocs.yml index c7b3bdd4e..c3988e8c3 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -91,5 +91,6 @@ markdown_extensions: - pymdownx.superfences - mkdocs-click - admonition + - pymdownx.snippets - toc: permalink: True From 4a1f78d39079caf185ae5a38c95992b9f80f2e6d Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Mon, 1 May 2023 09:39:32 -0700 Subject: [PATCH 25/45] Updated docs requirements. --- setup.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 4a175031d..d061efa40 100644 --- a/setup.py +++ b/setup.py @@ -40,8 +40,10 @@ doc_requires = [ 'mkdocs==1.3', 'mkdocs-click==0.7.0', - 'mkdocs-material==8.2.11', - 'mkdocstrings==0.18.1' + 'mkdocs-material', + 'mkdocstrings==0.18.1', + 'pymdown-extensions==9.11', + 'Pygments>=2.12' ] setup( From 45c132bd173380c3d510cb05558986c1b36b86b3 Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Mon, 1 May 2023 10:54:04 -0700 Subject: [PATCH 26/45] Removed and added to a new branch, for docs, snippets-docs-936. --- docs/python/sdk-data.md | 557 ---------------------- docs/python/sdk-intro.md | 17 - docs/python/sdk-orders.md | 764 ------------------------------- docs/python/sdk-subscriptions.md | 445 ------------------ 4 files changed, 1783 deletions(-) delete mode 100644 docs/python/sdk-data.md delete mode 100644 docs/python/sdk-intro.md delete mode 100644 docs/python/sdk-orders.md delete mode 100644 docs/python/sdk-subscriptions.md diff --git a/docs/python/sdk-data.md b/docs/python/sdk-data.md deleted file mode 100644 index 752e5571f..000000000 --- a/docs/python/sdk-data.md +++ /dev/null @@ -1,557 +0,0 @@ ---- -title: Python SDK for Data API Tutorial ---- - -TODO: Update narrative and snippets to be SDK instead of CLI. - -## Introduction - -The `planet data` CLI commands enable interaction with the [Data API](https://developers.planet.com/docs/apis/data/), -which lets you search Planet’s catalog (including select public datasets like Sentinel 2 and Landsat 8). -Currently the CLI has focused on the core search functionality, implementing -[Quick Search](https://developers.planet.com/docs/apis/data/reference/#tag/Item-Search/operation/QuickSearch) -and [stats](https://developers.planet.com/docs/apis/data/reference/#tag/Item-Stats/operation/Stats) plus some -partial saved search functionality. - -## `data search` command basics - -At this point you should have completed [Step 5](../get-started/quick-start-guide.md#step-5-search-for-planet-imagery) -of the quick start guide, and run your first full data search command: - -```sh -planet data search PSScene --filter filter.json > recent-psscene.json -``` - -This saves the descriptions of the latest 100 standard-quality scenes you have permissions to download in a file, that you can open and look at. - -### Pretty printing - -You will likely notice that this file is quite wide, with one very long line for each Planet -item returned. You can make for a more readable file by using the `--pretty` flag: - -```sh -planet data search --pretty PSScene --filter filter.json > recent-psscene.json -``` - -The `--pretty` flag is built into most of the CLI calls. But you can also achieve the -same effect by using another CLI program: `jq`. It is a very powerful library, providing -extensive manipulation of JSON, but simply -piping any JSON output through it prints it in a more readable form. So the following -command will do the same thing as the previous one: - -```sh -planet data search PSScene --filter filter.json | jq > recent-psscene.json -``` - -You can read a bit [more about jq]((cli-intro.md#jq) in the CLI intro. - -### Output to stdin - -You also don't have to save the output to a file. If you don't redirect it into a file then -it will just print out on the console. - -```sh -planet data search PSScene --filter filter.json -``` - -If you enter this command you’ll see the output stream by. Here you can use jq again, and -it’ll often give you nice syntax highlighting in addition to formatting. - -```sh -planet data search PSScene --filter filter.json | jq -``` - -### Create filter and search in one call - -Using a unix command called a 'pipe', which looks like `|`, you can skip the step of saving to disk, -passing the output of the `data filter` command directly to be the input of the `data search` -command: - -```sh -planet data filter --permission --std-quality | planet data search --pretty PSScene --filter - -``` - -Note the dash (`-`), which explicitly tells the CLI to use the output from the call that is piped into it. - -You can learn more about the pipe command, as well as the `>` command above in the -[Piping & redirection section](cli-intro.md#piping-redirection) of the CLI Introduction. - -### Search without filtering - -If no filtering is required, the search command can be called directly: - -```sh -planet data search PSScene -``` - -This outputs the last 100 scenes. - - -### Search on Item Type - -These first searches were done on the [PSScene](https://developers.planet.com/docs/data/psscene/) 'item type', but you -can use any [Item Type](https://developers.planet.com/docs/apis/data/items-assets/#item-types) that Planet offers in -its catalog. The item type is the first argument of the `search` command, followed by the 'filter'. Note that -you can specify any number of item types here: - -```sh -planet data search PSScene,Sentinel2L1C,Landsat8L1G,SkySatCollect -``` - -This will search for all the most recent images captured by PlanetScope, SkySat, Sentinel 2 and Landsat 8 satellites. -Note that you’ll likely mostly see PlanetScope results, as they generate far more individual images than the others. -The filter you specify will apply to all item types, but not all filters work against all satellites, so you may -inadvertently filter some out if you are filtering specific properties. - -### Limits - -By default the `search` command returns only the 100 first scenes. But with the CLI you can set any limit, and the SDK -under the hood will automatically page through all the results from the API. - -```sh -planet data search --limit 3000 PSScene -``` - -Note you can also do a call with no limits if you set the limit to `0`. Though don't use this haphazardly, or you’ll be -generating a lot of JSON from your request. It’s best to use it with a number of filters to constrain the search, so -you don't get hundreds of millions of results. - -### Output as valid GeoJSON - -By default the output of Planet’s Data API is [newline-delimited GeoJSON](https://stevage.github.io/ndgeojson/), which -is much better for streaming. While more and more programs will understand the format, the CLI also provides -the `planet collect` method to transform the output from the Data API to valid GeoJSON. You just pipe the end -output to it: - -```sh -planet data search PSScene | planet collect - -``` - -If you want to visualize this you can save it as a file: - -```sh -planet data search PSScene | planet collect - > planet-search.geojson -``` - -This you can then open with your favorite GIS program, or see this -[geometry visualization](cli-plus-tutorial.md#geometry-inputs) section for some ideas that flow a bit better with -the command-line. - -### Sort - -You can also specify the sorting with your searches. The default sort is ordered by the most recent published -images. But you can also sort by `acquired`, which is often more useful. You can sort in ascending or -descending order. The options are are: - - * 'acquired asc' - * 'acquired desc' - * 'published asc' - * 'published desc' - -This lets you do things like get the ID of the most recent SkySat image taken (and that you have permissions to download): - -```sh -planet data search SkySatCollect --sort 'acquired desc' --limit 1 -``` - -And you can also just get the ID, using `jq` - -```sh -planet data search SkySatCollect --sort 'acquired desc' --limit 1 - | jq -r .id -``` - -## Filtering - -### Run a search on a bounding box - -Most searches you’ll likely want to run on a geometry. To try this out you can use the following bounding box -of Iowa. You can copy it and save as a file called `geometry.geojson` - -```json -{ - "type": "FeatureCollection", - "features": [ - { - "type": "Feature", - "properties": {}, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [ - -93.7353, - 41.6236 - ], - [ - -92.2741, - 41.6236 - ], - [ - -92.2741, - 42.3747 - ], - [ - -93.7353, - 42.3747 - ], - [ - -93.7353, - 41.6236 - ] - ] - ] - } - } - ] -} -``` - -!!!note ".geojson and .json files both work" - Here we save it as .geojson, but you can also save it as .json. The CLI is happy with any file - extension, even .txt, but different extensions may make it easier to open the files with other - programs. What’s important is that the text inside the file is valid geojson. - -And then run it with this command: - -```sh -planet data filter --geom geometry.geojson | planet data search PSScene --filter - -``` - -Note that by default all searches with the command-line return 100 results, but you can easily increase that with -the `--limit` flag: - -```sh -planet data filter --geom geometry.geojson | planet data search --limit 500 PSScene --filter - -``` - -Creating geometries for search can be annoying in a command-line workflow, but there are some ideas in the -[Advanced CLI Tutorial](cli-plus-tutorial.md#geometry-inputs). - -### Date Filter - -Some of the most common filtering is by date. You could get all imagery acquired before August 2021: - -```sh -planet data filter --date-range acquired lt 2021-08-01 \ - | planet data search PSScene --filter - -``` - -The 'operator' in this case is 'less than' (`lt`). The options are: - * `gt` - greater than - * `gte` - greater than or equal to - * `lt` - less than - * `lte` - less than or equal to - -You must specify which date field you want to use, either `acquired` or `published`. - -You can use the flags multiple times, and they are logically 'AND'-ed together, so you can -do a search for all images in July of 2021: - -```sh -planet data filter \ - --date-range acquired gte 2021-07-01 \ - --date-range acquired lt 2021-08-01 | \ -planet data search PSScene --filter - -``` - -The date input understands [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339) and -[ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) formats. You can specify just the date, -or include the time, to search for all Planetscope images acquired within 5 seconds at a time -on July 1st 2021: - -```sh -planet data filter \ - --date-range acquired gte 2021-07-01:06:20:10 \ - --date-range acquired lt 2021-07-01:06:20:15 \ - | planet data search PSScene --filter - -``` - -### Range Filter - -The range filter uses the same operators as the date filter, but works against any numerical property. The most useful -of these tend to be ones about cloudy pixels. For example you can search for data with clear pixels greater than 90%: - -```sh -planet data filter --range clear_percent gt 90 \ - | planet data search PSScene --filter - -``` - -### String-In Filter - -For properties that are strings you can use the `string-in` filter. For example search for all planetscope imagery -with PS2 instrument: - -```sh -planet data filter --string-in instrument PS2 \ - | planet data search PSScene --filter - -``` - -You can specify multiple strings to match, with a comma: - -```sh -planet data filter --string-in instrument PS2,PSB.SD \ - | planet data search PSScene --filter - -``` - -Another example is to select all data in a single strip: - -```sh -planet data filter --string-in strip_id 5743640 \ - | planet data search PSScene --filter - -``` - -Note that in all these commands we are piping the results into the search. If you don't include the pipe then you’ll -get the filter output, which can be interesting to inspect to see exactly what is sent to the server. - -### Filter by asset - -You can limit your search to only data with a particular asset, for example search just for 8-band analytic assets: - -```sh -planet data filter --asset ortho_analytic_8b_sr \ - | planet data search PSScene --filter - -``` - -Or 8-band assets that also have a UDM. - -```sh -planet data filter --asset ortho_analytic_8b_sr --asset udm2 \ - | planet data search PSScene --filter - -``` - -You can find the list of available assets in each Item Type Page, like -[available assets](https://developers.planet.com/docs/data/psscene/#available-asset-types) for PSScene. You can see -[a table of all Item Types](https://developers.planet.com/docs/data/psscene/#available-asset-types), which links to -the page for each with their list of asset types. - -Note that the asset filter doesn't perform any validation, so if your searches aren't returning anything check to make -sure you got the asset right, and it’s valid for the item-types you’re searching. - -### Permission Filter - -By default, no search filters are applied. However, many people want to search only for data they have access to download -that are of standard (aka not test) quality. Therefore, these filters can be easily added with the `--permission` and -`--std-quality` flags. To use the permission and standard quality filters: - -```sh -planet data filter --permission --std-quality --asset ortho_analytic_8b_sr \ - | planet data search PSScene --filter - -``` - -## Stats - -One command that can be quite useful for getting a sense of a search is the `stats` command. It works with the -exact same filters as the main `search` command, but it just returns a count of the results, which can be -binned by different time periods. - -This can be used for things like getting the number of items in a strip: - -```sh -planet data filter --string-in strip_id 5743640 \ - | planet data stats PSScene --interval day --filter - -``` - -Or the number of PlanetScope scenes collected in California each year: - -``` -curl -s https://raw.githubusercontent.com/ropensci/geojsonio/main/inst/examples/california.geojson \ - | planet data filter --geom - \ - | planet data stats PSScene --interval year --filter - \ - | jq -``` - -Will result in output like: - -```json -{ - "buckets": [ - { - "count": 5261, - "start_time": "2014-01-01T00:00:00.000000Z" - }, - { - "count": 34377, - "start_time": "2015-01-01T00:00:00.000000Z" - }, - { - "count": 112331, - "start_time": "2016-01-01T00:00:00.000000Z" - }, - { - "count": 504377, - "start_time": "2017-01-01T00:00:00.000000Z" - }, - { - "count": 807086, - "start_time": "2018-01-01T00:00:00.000000Z" - }, - { - "count": 806945, - "start_time": "2019-01-01T00:00:00.000000Z" - }, - { - "count": 776757, - "start_time": "2020-01-01T00:00:00.000000Z" - }, - { - "count": 684095, - "start_time": "2021-01-01T00:00:00.000000Z" - }, - { - "count": 323557, - "start_time": "2022-01-01T00:00:00.000000Z" - }, - { - "count": 56733, - "start_time": "2023-01-01T00:00:00.000000Z" - } - ], - "interval": "year", - "utc_offset": "+0h" -} -``` - -You can see how the yearly output of Planet has gone up, though it actually went down in 2022 as the upgrade to SuperDove meant much larger swaths, so the number of individual items went down even as we captured the whole earth. - -The API does not support an 'all time' interval to get the total of all collections for an area, but -you can easily use [jq]((cli-intro.md#jq) to total up the results of an interval count: - -```sh -curl -s https://raw.githubusercontent.com/ropensci/geojsonio/main/inst/examples/california.geojson \ - | planet data filter --geom - \ - | planet data stats PSScene --interval year --filter - \ - | jq '.buckets | map(.count) | add' - -``` - -Just pipe the results to `jq '.buckets | map(.count) | add'` and it’ll give you the total of all the values. - -## Asset Activation and Download - -While we recommend using the Orders or Subscriptions API’s to deliver Planet data, the Data API has the capability -to activate and download data. Only one asset can be activated at once, and there is no clipping or additional -processing of the data like the great 'tools' of Subscriptions & Orders. But the advantage is that it can often -be faster for working with a small number of items & assets. - -### Activate an Asset - -All items in the Data API have a list of assets. This includes the main imagery geotiff files, usually in a few -different formats, and also accompanying files like the [Usable Data Mask](https://developers.planet.com/docs/data/udm-2/) - (UDM) and JSON metadata. You can't immediately download them, as they must first be created in the cloud, known as -'activated'. To activate data you need to get its item id, plus the name of the asset - the available ones -can be seen by looking at the Item’s JSON. Once you have the item id and asset type you can run the CLI - -```sh -planet data asset-activate PSScene 20230310_083933_71_2431 ortho_udm2 -``` - -This will kick off the activation process, and the command should return immediately. In this example -we’re activating the UDM, which is one of the most common things to do through the Data API, to -first get a sense of where there are clouds before placing a proper clipping order. - -### Download an Asset - -Once an asset is ready you can use `asset-download` with a similar command: - -```sh -planet data asset-download PSScene 20230310_083933_71_2431 ortho_udm2 -``` - -While some assets activate almost immediately (if another user has requested -it recently), some can take a few minutes. If you try to download it before it’s active -you’ll get a message like: `Error: asset missing ["location"] entry. Is asset active?` - -Thankfully the CLI has the great `asset-wait` command will complete when the asset is activated: - -```sh -planet data asset-wait PSScene 20230310_083933_71_2431 ortho_udm2 -``` - -And you can pair with download so that as soon as the asset is active it’ll be downloaded: - -```sh -planet data asset-wait PSScene 20230310_083933_71_2431 ortho_udm2 && \ -planet data asset-download PSScene 20230310_083933_71_2431 ortho_udm2 -``` - -Download has a few different options: - - * `--directory` lets you specify a base directory to put the asset in. - * `--filename` assigns a custom name to the downloaded file. - * `--overwrite` will overwrite files if they already exist. - * `--checksum` checks to make sure the file you downloaded is the exact same as the one on the server. This can be useful if you script thousands of files to download to detect any corruptions in that process. - -## Saved Searches - -The core `planet data search` command uses what is called a 'quick search' in the API. The API -also supports what we call a '[saved searches](https://developers.planet.com/docs/apis/data/quick-saved-search/#saved-search)', -and the CLI supports this as well. - -### List Searches - -You can easily get a list of all the searches you’ve made: - -```sh -planet data search-list -``` - -This defaults to returning 100 results, but you can use `--limit` to return the number you -specify, and set it to 0 to return all your searches. By default this returns both -your quick searches and saved searches, but you can also limit to to only return -your saved searches: - -```sh -planet data search-list --search-type saved -``` - -If you’ve not created any saved searches it may be an empty list. You can create -saved searches with Planet Explorer, or it’s also easy with the command-line. - -### Create Search - -To make a new saved search you can use the exact same filter syntax as the regular `search` command, -but you must also add a 'name' to refer to the search by: - -```sh -planet data filter --geom geometry.geojson \ - | planet data search-create PSScene --name 'my saved search' --filter - -``` - -### Run Search - -When you save a new search you’ll get back the JSON describing the search. If you grab the 'id' field from it then -you can get the current results for that search: - -```sh -planet data search-run da963039dbe94573a3ac9e4629d065b6 -``` - -This is just like running a normal (quick) search, and takes similar arguments: `--limit` and `--pretty`, -and also the same [sort](#sort) parameter (`--sort`). You can also run any previous `quick` search. -They don't have names (the ID is just used as the name), but they are saved in the system and can be -executed again. Searches (except those with an end date that has passed) show new results -if run later and match newly acquired imagery. - -### Update Search - -You can also update an existing search to have a different set of values. This takes similar arguments, and -will overwrite the previous values. - -```sh -planet data filter --string-in instrument PS2,PSB.SD \ - | planet data search-update da963039dbe94573a3ac9e4629d065b6 \ - --name 'my updated search' \ - --filter - SkySatCollect -``` - -### Delete Search - -If you’re no longer using a search you can delete it: - -```sh -planet data search-delete da963039dbe94573a3ac9e4629d065b6 -``` - -If the deletion was successful the command-line won't print out anything except a new line. If the -search didn't exist it will say `Error: {"general": [{"message": "The requested search id does not exist"}], "field": {}}`. -You can also delete `quick` searches, which would remove them from your history. diff --git a/docs/python/sdk-intro.md b/docs/python/sdk-intro.md deleted file mode 100644 index 971024cf6..000000000 --- a/docs/python/sdk-intro.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -title: Python SDK Introduction ---- - -## Python & Geospatial - -- lots of libraries - -## v2 vs v1 - -## Getting going - -### Your first call - -TODO: narrative on doing auth, creating session, making a data api call -TODO: snippets for the above. No filter, just defaults, but display results in some way. - diff --git a/docs/python/sdk-orders.md b/docs/python/sdk-orders.md deleted file mode 100644 index 27f5af174..000000000 --- a/docs/python/sdk-orders.md +++ /dev/null @@ -1,764 +0,0 @@ ---- -title: Python SDK for Orders API Tutorial ---- - -TODO: Update narrative and snippets to be SDK instead of CLI. - -## Introduction - -The `planet orders` command enables interaction with the [Orders API](https://developers.planet.com/apis/orders/), -which lets you activate and download Planet data products in bulk, and apply various -'tools' to your processes. This tutorial takes you through all the main capabilities -of the CLI for creating and downloading orders. It depends on several more advanced -command-line concepts, but this tutorial should let you get a sense of what you can do, -with enough examples that you should be able to adapt the commands for what you want to do. -If you’re interested in deeper understanding what is going on -then check out our [CLI Concepts](cli-intro.md) guide. - -## Core Workflows - -### See Recent Orders - -You can use the `list` command to show your recent orders: - -```sh -planet orders list -``` - -If you’ve not placed any orders with Explorer, the CLI or the API directly, then the results -of this call will be blank, so you may want to try out some of the create order commands below. - -Sometimes that list gets too long, so you can put a limit on how many are returned: - -```sh -planet orders list --limit 5 -``` - -You can also filter orders by their `state`, which can be useful to just see orders in -progress: - -```sh -planet orders list --state running -``` - -The other options are queued, failed, success, partial and cancelled. - -Note you can also get a nice list online as well, at https://www.planet.com/account/#/orders - -### Recent Orders with Formatting - -You can also print the list of orders more nicely: - -```sh -planet orders list --pretty -``` - -The `--pretty` flag is built into most Planet CLI commands, and it formats the JSON to be -more readable. - -You can also use `jq`, a powerful command-line JSON-processing tool, that is mentioned in -the [CLI introduction]((cli-intro.md#jq). - -```sh -planet orders list | jq -``` - -Piping any output through jq will format it nicely and do syntax highlighting. You can -also `jq` to just show select information, which can be useful for getting a quick sense -of the state of the state of things and pull out id’s for other operations: - -```sh -planet orders list | jq -rs '.[] | "\(.id) \(.created_on) \(.state) \(.name)"' -``` - -You can customize which fields you want to show by changing the values. - -### Number of recent orders - -You can use jq to process the output for more insight, like -get a count of how many recent orders you’ve done. - -```sh -planet orders list | jq -s length -``` - -This uses `-s` to collect the output into a single array, and `length` then tells the -length of the array. - -### Info on an Order - -For a bit more information about an order, including the location of any downloads, use -the `get` command, using the order id. - -```sh -planet orders get 782b414e-4e34-4f31-86f4-5b757bd062d7 -``` - -### Create an Order Request - -To create an order you need a name, a [bundle](https://developers.planet.com/apis/orders/product-bundles-reference/), - one or more id’s, and an [item type](https://developers.planet.com/docs/apis/data/items-assets/#item-types): - -First lets get the ID of an item you have download access to, using the Data API: - -```sh -planet data filter | planet data search PSScene --limit 1 --filter - | jq -r .id -``` - -If you don't have access to PlanetScope data then replace PSScene with SkySatCollect. -Then make the following call: - -```sh -planet orders request \ - --item-type PSScene \ - --bundle analytic_sr_udm2 \ - --name 'My First Order' \ - 20220605_124027_64_242b -``` - -Running the above command should output the JSON needed to create an order: - -```json -{"name": "My First Order", "products": [{"item_ids": ["20220605_124027_64_242b"], "item_type": "PSScene", "product_bundle": "analytic_sr_udm2"}], "metadata": {"stac": {}}} -``` - -You can also use `jq` here to make it a bit more readable: - -```sh -planet orders request \ - --item-type PSScene \ - --bundle analytic_sr_udm2 \ - --name 'My First Order' \ - 20220605_124027_64_242b \ - | jq -``` - -```json -{ - "name": "My First Order", - "products": [ - { - "item_ids": [ - "20220605_124027_64_242b" - ], - "item_type": "PSScene", - "product_bundle": "analytic_sr_udm2" - } - ], - "metadata": { - "stac": {} - } -} -``` - -### Save an Order Request - -The above command just prints out the necessary JSON to create an order. To actually use it you can -save the output into a file: - -```sh -planet orders request \ - --item-type PSScene \ - --bundle analytic_sr_udm2 \ - --name "My First Order" \ - 20220605_124027_64_242b \ - > request-1.json -``` - -Note that `\` just tells the command-line to treat the next line as the same one. It’s used here so it’s -easier to read, but you can still copy and paste the full line into your command-line and it should work. - -This saves the above JSON in a file called `request-1.json` - -### Create an Order - -From there you can create the order with the request you just saved: - -```sh -planet orders create request-1.json -``` - -The output of that command is the JSON returned from the server, that reports the status: - -```json -{ - "_links": { - "_self": "https://api.planet.com/compute/ops/orders/v2/2887c43b-26be-4bec-8efe-cb9e94f0ef3d" - }, - "created_on": "2022-11-29T22:49:24.478Z", - "error_hints": [], - "id": "2887c43b-26be-4bec-8efe-cb9e94f0ef3d", - "last_message": "Preparing order", - "last_modified": "2022-11-29T22:49:24.478Z", - "metadata": { - "stac": {} - }, - "name": "My First Order", - "products": [ - { - "item_ids": [ - "20220605_124027_64_242b" - ], - "item_type": "PSScene", - "product_bundle": "analytic_sr_udm2" - } - ], - "state": "queued" -} -``` - -Note the default output will be a bit more 'flat' - if you'd like the above formatting in your -command-line just use `jq` as above: `planet orders create request-1.json | jq` (but remember -if you run that command again it will create a second order). - -### Create Request and Order in One Call - -Using a unix command called a 'pipe', which looks like `|`, you can skip the step of saving to disk, -passing the output of the `orders request` command directly to be the input of the `orders create` -command: - -```sh -planet orders request --item-type PSScene --bundle analytic_sr_udm2 --name 'Two Item Order' \ -20220605_124027_64_242b,20220605_124025_34_242b | planet orders create - -``` - -The Planet CLI is designed to work well with piping, as it aims at small commands that can be -combined in powerful ways, so you’ll see it used in a number of the examples. - -### Download an order - -To download all files in an order you use the `download` command: - -```sh -planet orders download 65df4eb0-e416-4243-a4d2-38afcf382c30 -``` - -Note this only works when the order is ready for download. To do that you can -keep running `orders get` until the `state` is `success`. Or for a better -way see the next example. - -### Wait then download an order - -The `wait` command is a small, dedicated command that polls the server to -see if an order is ready for downloading, showing the status. It’s not -so useful by itself, but can be combined with the `download` command to -only start the download once the order is ready: - -```sh -planet orders wait 65df4eb0-e416-4243-a4d2-38afcf382c30 \ -&& planet orders download 65df4eb0-e416-4243-a4d2-38afcf382c30 -``` - -This uses the logical AND operator (`&&`) to say "don't run the second command -until the first is done". - -### Save order ID - -You can also use a unix variable to store the order id of your most recently placed order, -and then use that for the wait and download commands: - -```sh -orderid=$(planet orders list --limit 1 | jq -r .id) -planet orders wait $orderid -planet orders download $orderid -``` - -This can be nicer than copying and pasting it in. - -You could also save the id right when you place the order: - -```sh -orderid=`planet orders create request-1.json | jq -r .id` -``` - -To check the current value of `orderid` just run `echo $orderid`. - -### Create an order and download when ready - -You can then combine these all into one call, to create the order and -download it when it’s available: - -```sh -id=`planet orders create request-1.json | jq -r '.id'` && \ - planet orders wait $id && planet orders download $id -``` - -### Download to a different directory - -You can use the `--directory` flag to save the output to a specific directory. This -call saves it to a directory called `psscene`, at whatever location you are at -currently: - -```sh -mkdir psscene -planet orders download 782b414e-4e34-4f31-86f4-5b757bd062d7 --directory psscene -``` - -You can also specify absolute directories (in this case to my desktop): - -```sh -planet orders download \ - 782b414e-4e34-4f31-86f4-5b757bd062d7 \ - --directory /Users/cholmes/Desktop/ -``` - -### Verify checksum - -The `--checksum` command will do an extra step to make sure the file you got -wasn't corrupted along the way (during download, etc). It checks that the bytes -downloaded are the same as the ones on the server. By default it doesn't show -anything if the checksums match. - -```sh -planet orders download 782b414e-4e34-4f31-86f4-5b757bd062d7 --checksum MD5 -``` - -This command isn't often necessary in single download commands, but is quite -useful if you are downloading thousands of files with a script, as the likelihood -of at least one being corrupted in creases - -## Tools with orders - -Now we’ll dive into the variety of ways to customize your order. These can all be -combined with all the commands listed above. - -### Clipping - -The most used tool is the `clip` operation, which lets you pass a geometry to the -Orders API and it creates new images that only have pixels within the geometry you -gave it. The file given with the `--clip` option should contain valid [GeoJSON](https://geojson.org/). -It can be a Polygon geometry, a Feature, or a FeatureClass. If it is a FeatureClass, -only the first Feature is used for the clip geometry. - -Example: `geometry.geojson` -``` -{ - "geometry": - { - "type": "Polygon", - "coordinates": - [ - [ - [ - -48.4974827, - -1.4967008 - ], - [ - -48.4225714, - -1.4702869 - ], - [ - -48.3998028, - -1.4756259 - ], - [ - -48.4146752, - -1.49898376 - ], - [ - -48.4737304, - -1.5277508 - ], - [ - -48.4974827, - -1.4967008 - ] - ] - ] - } -} -``` - -We’ll work with a geojson that is already saved. You should download the -[geometry](https://raw.githubusercontent.com/planetlabs/planet-client-python/main/docs/cli/request-json/geometry.geojson) -(and you can see it [on github](https://github.com/planetlabs/planet-client-python/blob/main/docs/cli/request-json/geometry.geojson) -or it is also stored in the repo in the [request-json/](request-json/) directory. - -You can move that geometry to your current directory and use the following command, or -tweak the geometry.geojson to refer to where you downloaded it. - -```sh -planet orders request \ - --item-type PSScene \ - --bundle analytic_sr_udm2 \ - --clip geometry.geojson \ - --name clipped-geom \ - 20220605_124027_64_242b \ - | planet orders create - -``` - -### Additional Tools - -Since clip is so heavily used it has its own dedicated command in the CLI. All -the other tools use the `--tools` option, that points to a file. The file should -contain JSON that follows the format for a toolchain, the "tools" section of an order. -The toolchain options and format are given in -[Creating Toolchains](https://developers.planet.com/apis/orders/tools/#creating-toolchains). - -Example: `tools.json` -``` -[ - { - "toar": { - "scale_factor": 10000 - } - }, - { - "reproject": { - "projection": "WGS84", - "kernel": "cubic" - } - }, - { - "tile": { - "tile_size": 1232, - "origin_x": -180, - "origin_y": -90, - "pixel_size": 2.7056277056e-05, - "name_template": "C1232_30_30_{tilex:04d}_{tiley:04d}" - } - } -] -``` - -!!!note Note - Future of the versions of the CLI will likely add `tools` convenience methods, - so composite, harmonize and other tools work like `--clip`. You can follow issue - [#601](https://github.com/planetlabs/planet-client-python/issues/601): - comment there if you'd like to see it prioritized - -### Compositing - -Ordering two scenes is easy, just add another id: - -```sh -planet orders request \ - --item-type PSScene \ - --bundle analytic_sr_udm2 \ - --name 'Two Scenes' \ - 20220605_124027_64_242b,20220605_124025_34_242b \ - | planet orders create - -``` - -And then you can composite them together, using the 'tools' json. You can -use this, just save it into a file called [tools-composite.json](https://raw.githubusercontent.com/planetlabs/planet-client-python/main/docs/cli/request-json/tools-composite.json). - -```json -[ - { - "composite": { - } - } -] -``` - -Once you’ve got it saved you call the `--tools` flag to refer to the JSON file, and you -can pipe that to `orders create`. - -```sh -planet orders request \ - --item-type PSScene \ - --bundle analytic_sr_udm2 \ - --name 'Two Scenes Composited' \ - 20220605_124027_64_242b,20220605_124025_34_242b \ - --no-stac \ - --tools tools-composite.json \ - | planet orders create - -``` - -Note that we add the `--no-stac` option as [STAC Metadata](#stac-metadata) is not yet supported by the composite -operation, but STAC metadata is requested by default with the CLI. - -### Output as COG - -If you'd like to ensure the above order is a Cloud-Optimized Geotiff then you can request it -as COG in the file format tool. - -```json -[ - { - "file_format": { - "format": "COG" - } - } -] -``` - -The following command just shows the output with [tools-cog.json](https://raw.githubusercontent.com/planetlabs/planet-client-python/main/docs/cli/request-json/tools-cog.json): - -```sh -planet orders request \ - --item-type PSScene \ - --bundle analytic_sr_udm2 \ - --name 'COG Order' \ - 20220605_124027_64_242b,20220605_124025_34_242b \ - --tools tools-cog.json -``` - -As shown above you can also pipe that output directly in to `orders create`. - -### Clip & Composite - -To clip and composite you need to specify the clip in the tools (instead of `--clip`), as you can -not use `--clip` and `--tools` in the same call. There is not yet CLI calls to generate the `tools.json`, -so you can just use the [following json](https://raw.githubusercontent.com/planetlabs/planet-client-python/main/docs/cli/request-json/tools-clip-composite.json): - -```json -[ - { - "composite": {} - }, - { - "clip": { - "aoi": { - "type": "Polygon", - "coordinates": [ - [ - [ - -48.492541, - -1.404126 - ], - [ - -48.512879, - -1.504392 - ], - [ - -48.398017, - -1.52127 - ], - [ - -48.380419, - -1.423805 - ], - [ - -48.492541, - -1.404126 - ] - ] - ] - } - } - } -] -``` - -```sh -planet orders request \ - --item-type PSScene \ - --bundle analytic_sr_udm2 \ - --no-stac \ - --name 'Two Scenes Clipped and Composited' \ - 20220605_124027_64_242b,20220605_124025_34_242b \ - --tools tools-clip-composite.json \ - | planet orders create - -``` - -One cool little trick is that you can even stream in the JSON directly with `curl`, piping it into the request: - -```sh -curl -s https://raw.githubusercontent.com/planetlabs/planet-client-python/main/docs/cli/request-json/tools-clip-composite.json \ - | planet orders request \ - --item-type PSScene \ - --bundle analytic_sr_udm2 \ - --name 'Streaming Clip & Composite' \ - --no-stac \ - 20220605_124027_64_242b,20220605_124025_34_242b \ - --tools - \ - | planet orders create - -``` - -### Harmonize - -The harmonize tool allows you to compare data to different generations of satellites by radiometrically harmonizing imagery captured by one satellite instrument type to imagery captured by another. To harmonize your data to a sensor you must define the sensor you wish to harmonize with in your `tools.json`. Currently, only "PS2" (Dove Classic) and "Sentinel-2" are supported as target sensors. The Sentinel-2 target only harmonizes PSScene surface reflectance bundle types (`analytic_8b_sr_udm2`, `analytic_sr_udm2`). The PS2 target only works on analytic bundles from Dove-R (`PS2.SD`). - -```json -[ - { - "harmonize": { - "target_sensor": "Sentinel-2" - } - } -] -``` - -You may create an order request by calling [`tools-harmonize.json`](https://raw.githubusercontent.com/planetlabs/planet-client-python/main/docs/cli/request-json/tools-harmonize.json) with `--tools`. - -```sh -planet orders request --item-type PSScene --bundle analytic_sr_udm2 --name 'Harmonized data' 20200925_161029_69_2223 --tools tools-harmonize.json -``` - -## More options - -### STAC Metadata - -A relatively recent addition to Planet’s orders delivery is the inclusion of [SpatioTemporal Asset Catalog](https://stacspec.org/en) -(STAC) metadata in Orders. STAC metadata provides a more standard set of JSON fields that work with -many GIS and geospatial [STAC-enabled tools](https://stacindex.org/ecosystem). The CLI `orders request` command currently requests -STAC metadata by default, as the STAC files are small and often more useful than the default JSON metadata. -You can easily turn off STAC output request with the `--no-stac` command: - -```sh -planet orders request \ - --item-type PSScene \ - --bundle visual \ - --name 'No STAC' \ - --no-stac \ - 20220605_124027_64_242b -``` - -Currently this needs to be done for any 'composite' operation, as STAC output from composites is not yet -supported (but is coming). You can explicitly add `--stac`, but it is the default, so does not need to -be included. For more information about Planet’s STAC output see the [Orders API documentation](https://developers.planet.com/apis/orders/delivery/#stac-metadata). - -### Cloud Delivery - -Another option is to delivery your orders directly to a cloud bucket, like AWS S3 or Google Cloud Storage. -The file given with the `--cloudconfig` option should contain JSON that follows -the options and format given in -[Delivery to Cloud Storage](https://developers.planet.com/docs/orders/delivery/#delivery-to-cloud-storage). - -An example would be: - -Example: `cloudconfig.json` - -```json -{ - "amazon_s3": { - "aws_access_key_id": "aws_access_key_id", - "aws_secret_access_key": "aws_secret_access_key", - "bucket": "bucket", - "aws_region": "aws_region" - }, - "archive_type": "zip" -} -``` - -### Using Orders output as input - -One useful thing to note is that the order JSON that reports status and location is a valid Orders API request. -It reports all the parameters that were used to make the previous order, but you can also use it directly as a -request. So the following call is a quick way to exactly redo a previous order request: - -```sh -planet orders get | planet orders create - -``` - -Realistically you'd more likely want to get a previous order and then change it in some way (new id’s, different -tools, etc.). You can remove the 'extra' JSON fields that report on status if you'd like, but the Orders -API will just ignore them if they are included in a request. - -There is planned functionality to make it easy to 'update' an existing order, so you can easily grab a past order -and use the CLI to customize it. - -### Basemaps Orders - -One of the newer features in Planet’s Orders API is the ability to [order basemaps](https://developers.planet.com/apis/orders/basemaps/). -The CLI does not yet support a 'convenience' method to easily create the JSON - you unfortunately -can't yet use `planet orders request` to help form an orders request. But all the other CLI functionality -supports ordering basemaps through the Orders API. - -You’ll need to use a full orders request JSON. - -```json -{ - "name": "basemap order with geometry", - "source_type": "basemaps", - "order_type":"partial", - "products": [ - { - "mosaic_name": "global_monthly_2022_01_mosaic", - "geometry":{ - "type": "Polygon", - "coordinates":[ - [ - [4.607406, 52.353994], - [4.680005, 52.353994], - [4.680005, 52.395523], - [4.607406, 52.395523], - [4.607406, 52.353994] - ] - ] - } - } - ], - "tools": [ - {"merge": {}}, - {"clip": {}} - ] -} -``` - -Once you’ve got the JSON, the other commands are all the same. Use create to submit it to the API: - -```sh -planet orders create basemap-order.json -``` - -See the status of the order you just submitted: - -```sh -planet orders list --limit 1 -``` - -Extract the ID: - -```sh -planet orders list --limit 1 | jq -r .id -``` - -Use that ID to wait and download when it’s ready: - -```sh -orderid=605b5472-de61-4563-88ae-d43417d3ed96 -planet orders wait $orderid -planet orders download $orderid -``` - -You can also list only the orders you submitted that are for basemaps, using `jq` to filter client side: - -```sh -planet orders list | jq -s '.[] | select(.source_type == "basemaps")' -``` - -#### Bringing it all together - -The cool thing is you can combine the data and order commands, to make calls -like ordering the most recent skysat image that was published: - -```sh -latest_id=$(planet data filter \ - | planet data search SkySatCollect \ - --sort 'acquired desc' \ - --limit 1 \ - --filter - \ - | jq -r .id) - -planet orders request \ - --item-type SkySatCollect \ - --bundle analytic \ - --name 'SkySat Latest' \ - $latest_id \ - | planet orders create - -``` - -Or get the 5 latest cloud free images in an area and create an order that clips to that area, using -[geometry.geojson](data/geometry.geojson) from above: - -```sh -ids=$(planet data filter --geom geometry.geojson --range clear_percent gt 90 \ - | planet data search PSScene --limit 5 --filter - \ - | jq -r .id \ - | tr '\n' ',' \ - | sed 's/.$//' -) -planet orders request \ - --item-type PSScene \ - --bundle analytic_sr_udm2 \ - --name 'Clipped Scenes' \ - $ids \ - --clip geometry.geojson \ - | planet orders create - -``` - -This one uses some advanced unix capabilities like `sed` and `tr`, along with unix variables, so more -properly belongs in the [CLI Tips & Tricks](cli-tips-tricks.md), but we’ll leave it here to give a taste of what’s possible. diff --git a/docs/python/sdk-subscriptions.md b/docs/python/sdk-subscriptions.md deleted file mode 100644 index 9f5630796..000000000 --- a/docs/python/sdk-subscriptions.md +++ /dev/null @@ -1,445 +0,0 @@ ---- -title: Python SDK for Subscriptions API Tutorial ---- - -TODO: Update narrative and snippets to be SDK instead of CLI. - -## Introduction - -The `SubscriptionsClient` enables interaction with the -[Subscriptions API](https://developers.planet.com/apis/subscriptions/) -that make it possible to set up a recurring search criteria. Using the subscriptions api -you can automatically process and deliver new imagery to a cloud bucket. It also -has a powerful 'backfill' capability to bulk order historical imagery to your area of interest. -This tutorial takes you through the main commands available for subscriptions in the SDK - -## Core Workflows - -### Create a Subscription - -Since there is no UI to easily create subscriptions we’ll start with making a new one. - -```json -{ - "name": "First Subscription", - "source": { - "type": "catalog", - "parameters": { - "asset_types": [ - "ortho_analytic_8b" - ], - "end_time": "2023-11-01T00:00:00Z", - "geometry": { - "coordinates": [ - [ - [ - 139.5648193359375, - 35.42374884923695 - ], - [ - 140.1031494140625, - 35.42374884923695 - ], - [ - 140.1031494140625, - 35.77102915686019 - ], - [ - 139.5648193359375, - 35.77102915686019 - ], - [ - 139.5648193359375, - 35.42374884923695 - ] - ] - ], - "type": "Polygon" - }, - "item_types": [ - "PSScene" - ], - "start_time": "2023-03-17T04:08:00.0Z" - } - }, - "tools": [ - { - "type": "clip", - "parameters": { - "aoi": { - "coordinates": [ - [ - [ - 139.5648193359375, - 35.42374884923695 - ], - [ - 140.1031494140625, - 35.42374884923695 - ], - [ - 140.1031494140625, - 35.77102915686019 - ], - [ - 139.5648193359375, - 35.77102915686019 - ], - [ - 139.5648193359375, - 35.42374884923695 - ] - ] - ], - "type": "Polygon" - } - } - } - ], - "delivery": { - "type": "google_cloud_storage", - "parameters": { - "bucket": "pl-sub-bucket", - "credentials": "" - } - } -} -``` - -This is a full subscriptions JSON request, with the credentials redacted, so you’ll have -to replace your own for it to work. Below we’ll show the convenience methods that will -help create a custom one more easily. If you'd like to get things working for now then -just replace the 'delivery' section with your cloud credentials, see the -[core subscriptions delivery docs](https://developers.planet.com/docs/subscriptions/delivery/) -for more information. - -To create a new subscription with the CLI, use the `create_subscription` method and the json file you just created: - -TODO: Python snippet here: -```sh -planet subscriptions create my-subscription.json -``` - -!!!note "Note" - The above command assumes that you’ve saved the subscriptions JSON as `my-subscription.json` and that you’ve replaced the delivery information with your own bucket and credentials. - -### List Subscriptions - -Now that you’ve got a subscription working you can make use of the other commands. - -TODO: Python snippet here, should probably have it print too: -```sh -planet subscriptions list -``` - -outputs the JSON for your first 100 subscriptions. If you'd like more you can set the `--limit` -parameter higher, or you can set it to 0 and there will be no limit. - -TODO: Update narrative here, maybe example? How do we get python to print json nicely? Or does it do it by default? - -You can get nicer formatting with `--pretty` or pipe it into `jq`, just like the other Planet -CLI’s. - -The `list_subscriptions` method also supports filtering by the status of the subscription: - - -TODO: Python snippet here: -```sh -planet subscriptions list --status running -``` - -gives you just the currently active subscriptions. The other available statuses are: -`cancelled`, `preparing`, `pending`, `completed`, `suspended`, and `failed`. - -### Get Subscription - -To get the full details on a single subscription you can take the id from your list and use the -`get_subscription` method: - -TODO: Python snippet here: -```sh -planet subscriptions get cb817760-1f07-4ee7-bba6-bcac5346343f -``` - -### Subscription Results - -To see what items have been delivered to your cloud bucket you can use the `get_results` method: - -TODO: Python snippet here: -```sh -planet subscriptions results cb817760-1f07-4ee7-bba6-bcac5346343f -``` - -By default this displays the first 100 results. As with other commands, you can use the `--limit` param to -set a higher limit, or set it to 0 to see all results (this can be quite large with subscriptions results). - -You can also filter by status: - -TODO: Python snippet here: -```sh -planet subscriptions results --status processing -``` - -The available statuses are `created`, `queued`, `processing`, `failed`, and `success`. - -### Update Subscription - -You can update a subscription that is running, for example to change the 'tools' it’s using or to alter -its geometry. To do this you must submit the full subscription creation JSON, so the easiest way is to -get it with `get_subscription` and then alter the values. - -TODO: Python snippet here - is there a way to programmatically update the resulting json? Could be nice to show that -like change the asset type from 8 band to 4 band - -```sh -planet subscriptions update cb817760-1f07-4ee7-bba6-bcac5346343f \ - my-updated-subscriptions.json -``` - -### Cancel a subscription - -Cancelling a subscription is simple with the SDK: - -TODO: Python snippet here: -```sh -planet subscriptions cancel cb817760-1f07-4ee7-bba6-bcac5346343f -``` - -That will stop the subscription from producing any more results, but it will stay in the system so you can -continue to list and get it. - -## Subscription Request Conveniences - -There are a couple of commands that can assist in creating the subscription JSON, used for creation and updates. -A subscription request is a pretty complicated command, consisting of a search, a cloud delivery, as well as -tools to process the data plus notifications on the status. - -### Catalog Source - -The first place to start is the `catalog-source` command, which generates all the JSON for the -[catalog source](https://developers.planet.com/docs/subscriptions/source/#catalog-source-type) block. The core -of this is quite similar to a Data API search request, though with more required fields. The minimal -required commands would be a request like: - -TODO: Python snippet here: -```sh -planet subscriptions request-catalog \ - --item-types PSScene \ - --asset-types ortho_analytic_8b \ - --geometry geometry.geojson \ - --start-time 2023-03-17T04:08:00.0Z -``` - -You request which item types you want to deliver, and the asset types for it. Note that the `asset-types` are a bit -different than the `--bundle` command in Orders, a bundle is a set of asset-types. You can see the list of asset types -for [PSScene](https://developers.planet.com/docs/data/psscene/#available-asset-types), [SkySatCollect](https://developers.planet.com/docs/data/skysatcollect/), -and [SkySatScene](https://developers.planet.com/docs/data/skysatscene/#available-asset-types). The other item-types -also have similar listings of their asset types. For the required `start-time` and optional `end-time` you must -use dates formatted as RFC 3339 or ISO 8601 formats. A nice time converter is available at [time.lol](https://time.lol/). -Just select 'ISO 8601' (third one on the list), or 'RFC 3339' (8th on the list). - -#### Geometry - -In this case we are using a locally saved `geometry.geojson`, which would look like the following if you wanted -it to match the subscription creation request at the top of this documentation page: - -```json -{ - "coordinates": - [ - [ - [ - 139.5648193359375, - 35.42374884923695 - ], - [ - 140.1031494140625, - 35.42374884923695 - ], - [ - 140.1031494140625, - 35.77102915686019 - ], - [ - 139.5648193359375, - 35.77102915686019 - ], - [ - 139.5648193359375, - 35.42374884923695 - ] - ] - ], - "type": "Polygon" -} -``` - -Note this is just the coordinates of either a polygon or multipolygon - the operation -is not flexible to input like the orders command. - -#### RRule - -RRule lets you specify a subscription that repeats at various time intervals: - -TODO: Python snippet here: -```sh -planet subscriptions request-catalog \ - --item-types PSScene \ - --asset-types ortho_analytic_8b \ - --geometry geometry.geojson \ - --start-time 2023-03-17T04:08:00.0Z \ - --rrule 'FREQ=MONTHLY;BYMONTH=3,4,5,6,7,8,9,10' -``` - -For more information on the `rrule` parameter see the [recurrence rules](https://developers.planet.com/docs/subscriptions/source/#rrules-recurrence-rules) -documentation. - -#### Filter - -You can pass in a filter from the data API: - -TODO: Python snippet here: -```sh -planet data filter --range clear_percent gt 90 > filter.json -planet subscriptions request-catalog \ - --item-types PSScene \ - --asset-types ortho_analytic_8b \ - --geometry geometry.geojson \ - --start-time 2022-08-24T00:00:00-07:00 \ - --filter filter.json -``` - -Do not bother with geometry or date filters, as they will be ignored in favor of the `--start-time` and `--geometry` values that are required. - -#### Saving the output - -You may want to save the output of your `catalog-source` to disk, so that you can use it in the future to construct the complete subscription -request. - -TODO: Python snippet here: -```sh -planet data filter --range clear_percent gt 90 > filter.json -planet subscriptions request-catalog \ - --item-types PSScene \ - --asset-types ortho_analytic_8b \ - --geometry geometry.geojson \ - --start-time 2022-08-24T00:00:00-07:00 \ - --filter filter.json > request-catalog.json -``` - -### Subscription Tools - -Now we’ll dive into some of the tools options for subscriptions. These are quite similar to the tools for -orders, but unfortunately the syntax is subtly different, and there are less tools supported. Just like -for Orders, future of the versions of the CLI will likely add `tools` convenience methods, you can follow issue -[#601](https://github.com/planetlabs/planet-client-python/issues/601). - -#### Clipping - -The most used tool is the `clip` operation, which lets you pass a geometry to the -Subscriptions API and it creates new images that only have pixels within the geometry you -gave it. We’ll use the same geometry from [above](#geometry), as it is quite -typical to use the same subscription geometry as the clip geometry, so you don't get -any pixels outside of your area of interest (99.9% of all subscriptions use the clip -tool, so it’s strongly recommended to also use clip). - -TODO: Make the JSON just the geometry, and show python snippet for the clip tool - -The proper 'clip' tool for it -would be: - -```json -[ - { - "type": "clip", - "parameters": { - "aoi": { - "type": "Polygon", - "coordinates": [ - [ - [ - -163.828125, - -44.59046718130883 - ], - [ - 181.7578125, - -44.59046718130883 - ], - [ - 181.7578125, - 78.42019327591201 - ], - [ - -163.828125, - 78.42019327591201 - ], - [ - -163.828125, - -44.59046718130883 - ] - ] - ] - } - } - } -] -``` - -You can save this tools as `tools.json` to include in the `subscriptions request` -command. - -#### File Format Tool - -TODO: Narrative on file format -TODO: Python snippet here: - -#### Harmonize Tool - -TODO: Narrative on file format -TODO: Python snippet here: - -#### Reproject Tool - -TODO: Narrative on file format -TODO: Python snippet here: - -#### TOAR Tool - -TODO: Narrative on file format -TODO: Python snippet here: - -#### Band Math Tool - -TODO: Narrative on file format -TODO: Python snippet here: - -### Delivery - -One other essential part of the request is the `delivery` - the cloud delivery. -You can find the full documentation for the delivery options in -the [Subscriptions Delivery documentation](https://developers.planet.com/docs/subscriptions/delivery/). - -#### S3 Delivery - -TODO: Narrative on file format -TODO: Python snippet here: - -#### Azure Delivery - -TODO: Narrative on file format -TODO: Python snippet here: - -#### Google Cloud Delivery - -TODO: Narrative on file format -TODO: Python snippet here: - -#### Oracle Cloud Delivery - -TODO: Narrative on file format -TODO: Python snippet here: - -### Subscriptions Request - -TODO: Narrative on making a request that you've built up with convenience methods -TODO: Python snippet here: \ No newline at end of file From 84a9c1f8ad5cac254973dcde926830c509b2ba02 Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Mon, 1 May 2023 11:16:04 -0700 Subject: [PATCH 27/45] Removed and added to a new branch, for docs, snippets-docs-936. --- setup.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/setup.py b/setup.py index d061efa40..4a175031d 100644 --- a/setup.py +++ b/setup.py @@ -40,10 +40,8 @@ doc_requires = [ 'mkdocs==1.3', 'mkdocs-click==0.7.0', - 'mkdocs-material', - 'mkdocstrings==0.18.1', - 'pymdown-extensions==9.11', - 'Pygments>=2.12' + 'mkdocs-material==8.2.11', + 'mkdocstrings==0.18.1' ] setup( From d18bdc1ee749f2496c3bffc651e77a8512b49238 Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Mon, 1 May 2023 11:16:56 -0700 Subject: [PATCH 28/45] Removed and added to a new branch, for docs, snippets-docs-936. --- mkdocs.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/mkdocs.yml b/mkdocs.yml index 1e7854405..c7b3bdd4e 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -81,10 +81,6 @@ nav: - cli/cli-reference.md - "Python": - python/sdk-guide.md - - python/sdk-intro.md - - python/sdk-data.md - - python/sdk-orders.md - - python/sdk-subscriptions.md - python/sdk-reference.md - "Resources": - resources/index.md @@ -95,6 +91,5 @@ markdown_extensions: - pymdownx.superfences - mkdocs-click - admonition - - pymdownx.snippets - toc: permalink: True From b80cd530f6917df8a8540ee60d49f1981510dc23 Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Mon, 1 May 2023 11:18:18 -0700 Subject: [PATCH 29/45] Removed unneeded readme --- examples/snippets/README.md | 1 - {examples => tests}/snippets/data_api.py | 0 {examples => tests}/snippets/orders_api.py | 0 {examples => tests}/snippets/subscriptions_api.py | 0 4 files changed, 1 deletion(-) delete mode 100644 examples/snippets/README.md rename {examples => tests}/snippets/data_api.py (100%) rename {examples => tests}/snippets/orders_api.py (100%) rename {examples => tests}/snippets/subscriptions_api.py (100%) diff --git a/examples/snippets/README.md b/examples/snippets/README.md deleted file mode 100644 index fd038b65c..000000000 --- a/examples/snippets/README.md +++ /dev/null @@ -1 +0,0 @@ -Code snippets for each function in the SDK diff --git a/examples/snippets/data_api.py b/tests/snippets/data_api.py similarity index 100% rename from examples/snippets/data_api.py rename to tests/snippets/data_api.py diff --git a/examples/snippets/orders_api.py b/tests/snippets/orders_api.py similarity index 100% rename from examples/snippets/orders_api.py rename to tests/snippets/orders_api.py diff --git a/examples/snippets/subscriptions_api.py b/tests/snippets/subscriptions_api.py similarity index 100% rename from examples/snippets/subscriptions_api.py rename to tests/snippets/subscriptions_api.py From 5ea5fb8bf4871489758a9f12a220420bef049990 Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Wed, 3 May 2023 13:56:09 -0700 Subject: [PATCH 30/45] Renamed file for testing. --- ...{data_api.py => test_data_api_snippets.py} | 88 ++++++++++++------- 1 file changed, 57 insertions(+), 31 deletions(-) rename tests/snippets/{data_api.py => test_data_api_snippets.py} (72%) diff --git a/tests/snippets/data_api.py b/tests/snippets/test_data_api_snippets.py similarity index 72% rename from tests/snippets/data_api.py rename to tests/snippets/test_data_api_snippets.py index ce62c12fb..a160b7503 100644 --- a/tests/snippets/data_api.py +++ b/tests/snippets/test_data_api_snippets.py @@ -25,34 +25,60 @@ from planet import data_filter import json from datetime import datetime +import pytest + + +@pytest.fixture +def search_filter(get_test_file_json): + filename = 'data_search_filter_2022-01.json' + return get_test_file_json(filename) + + +@pytest.fixture +def item_descriptions(get_test_file_json): + item_ids = [ + '20220125_075509_67_1061', + '20220125_075511_17_1061', + '20220125_075650_17_1061' + ] + items = [get_test_file_json(f'data_item_{id}.json') for id in item_ids] + return items # search -async def search(item_types, search_filter, name, sort, limit): +@pytest.mark.anyio +async def test_snippet_search(search_filter): '''Code snippet for search.''' + # --8<-- [start:search] async with planet.Session() as sess: client = sess.client('data') - async for item in client.search(item_types=item_types, - search_filter=search_filter, - name=name, - sort=sort, - limit=limit): - return item + items_list = [ + i async for i in client.search(['PSScene'], + search_filter=search_filter, + name="My Search", + sort="acquired asc", + limit=10) + ] + # --8<-- [start:search] + assert len(items_list) == 10 # create_search -async def create_search(item_types, search_filter, name): +async def test_snippet_create_search(item_types, search_filter, name): '''Code snippet for create_search.''' async with planet.Session() as sess: client = sess.client('data') - items = await client.create_search(item_types=item_types, + items = await client.create_search(item_types="PSScene", search_filter=search_filter, name=name) return items # update_search -async def update_search(search_id, item_types, search_filter, name): +async def test_snippet_update_search(search_id, + item_types, + search_filter, + name): '''Code snippet for update_search.''' async with planet.Session() as sess: client = sess.client('data') @@ -64,7 +90,7 @@ async def update_search(search_id, item_types, search_filter, name): # list_searches -async def list_searches(sort, search_type, limit): +async def test_snippet_list_searches(sort, search_type, limit): '''Code snippet for list_searches.''' async with planet.Session() as sess: client = sess.client('data') @@ -75,7 +101,7 @@ async def list_searches(sort, search_type, limit): # delete_search -async def delete_search(search_id): +async def test_snippet_delete_search(search_id): '''Code snippet for delete_search.''' async with planet.Session() as sess: client = sess.client('data') @@ -83,7 +109,7 @@ async def delete_search(search_id): # get_search -async def get_search(search_id): +async def test_snippet_get_search(search_id): '''Code snippet for get_search.''' async with planet.Session() as sess: client = sess.client('data') @@ -92,7 +118,7 @@ async def get_search(search_id): # run_search -async def run_search(search_id): +async def test_snippet_run_search(search_id): '''Code snippet for run_search.''' async with planet.Session() as sess: client = sess.client('data') @@ -101,7 +127,7 @@ async def run_search(search_id): # get_stats -async def get_stats(item_types, search_filter, interval): +async def test_snippet_get_stats(item_types, search_filter, interval): '''Code snippet for get_stats.''' async with planet.Session() as sess: client = sess.client('data') @@ -112,7 +138,7 @@ async def get_stats(item_types, search_filter, interval): # list_item_assets -async def list_item_assets(item_type_id, item_id): +async def test_snippet_list_item_assets(item_type_id, item_id): '''Code snippet for list_item_assets.''' async with planet.Session() as sess: client = sess.client('data') @@ -121,7 +147,7 @@ async def list_item_assets(item_type_id, item_id): # get_asset -async def get_asset(item_type, item_id, asset_type): +async def test_snippet_get_asset(item_type, item_id, asset_type): '''Code snippet for get_asset.''' async with planet.Session() as sess: client = sess.client('data') @@ -130,7 +156,7 @@ async def get_asset(item_type, item_id, asset_type): # activate_asset -async def activate_asset(item_type, item_id, asset_type): +async def test_snippet_activate_asset(item_type, item_id, asset_type): '''Code snippet for activate_asset.''' async with planet.Session() as sess: client = sess.client('data') @@ -139,7 +165,7 @@ async def activate_asset(item_type, item_id, asset_type): # wait_asset -async def wait_asset(item_type, item_id, asset_type): +async def test_snippet_wait_asset(item_type, item_id, asset_type): '''Code snippet for wait_asset.''' async with planet.Session() as sess: client = sess.client('data') @@ -148,12 +174,12 @@ async def wait_asset(item_type, item_id, asset_type): # download_asset w/o checksum -async def download_asset_without_checksum(item_type, - item_id, - asset_type, - filename, - directory, - overwrite): +async def test_snippet_download_asset_without_checksum(item_type, + item_id, + asset_type, + filename, + directory, + overwrite): '''Code snippet for download_asset without a checksum.''' async with planet.Session() as sess: client = sess.client('data') @@ -166,12 +192,12 @@ async def download_asset_without_checksum(item_type, # download_asset w/ checksum -async def download_asset_with_checksum(item_type, - item_id, - asset_type, - filename, - directory, - overwrite): +async def test_snippet_download_asset_with_checksum(item_type, + item_id, + asset_type, + filename, + directory, + overwrite): '''Code snippet for download_asset with a checksum.''' async with planet.Session() as sess: client = sess.client('data') From f1778947ae4b28ce3cdbffbbfb03e19f65b9cbeb Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Thu, 4 May 2023 12:42:57 -0700 Subject: [PATCH 31/45] Updated search test and added tests for create search and update search. --- tests/snippets/test_data_api_snippets.py | 48 ++++++++++++------------ 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/tests/snippets/test_data_api_snippets.py b/tests/snippets/test_data_api_snippets.py index a160b7503..19f5c19fc 100644 --- a/tests/snippets/test_data_api_snippets.py +++ b/tests/snippets/test_data_api_snippets.py @@ -45,7 +45,6 @@ def item_descriptions(get_test_file_json): return items -# search @pytest.mark.anyio async def test_snippet_search(search_filter): '''Code snippet for search.''' @@ -53,40 +52,43 @@ async def test_snippet_search(search_filter): async with planet.Session() as sess: client = sess.client('data') items_list = [ - i async for i in client.search(['PSScene'], - search_filter=search_filter, - name="My Search", - sort="acquired asc", - limit=10) + item async for item in client.search(['PSScene'], + search_filter=search_filter, + name="My Search", + sort="acquired asc", + limit=10) ] - # --8<-- [start:search] + # --8<-- [end:search] assert len(items_list) == 10 -# create_search -async def test_snippet_create_search(item_types, search_filter, name): +@pytest.mark.anyio +async def test_snippet_create_search(search_filter): '''Code snippet for create_search.''' + # --8<-- [start:create_search] async with planet.Session() as sess: client = sess.client('data') - items = await client.create_search(item_types="PSScene", - search_filter=search_filter, - name=name) - return items + response = await client.create_search(item_types=['PSScene'], + search_filter=search_filter, + name="My Search") + # --8<-- [end:create_search] + assert 'PSScene' in response['item_types'] -# update_search -async def test_snippet_update_search(search_id, - item_types, - search_filter, - name): +@pytest.mark.anyio +async def test_snippet_update_search(search_filter): '''Code snippet for update_search.''' + # --8<-- [start:update_search] async with planet.Session() as sess: client = sess.client('data') - items = await client.update_search(search_id=search_id, - item_types=item_types, - search_filter=search_filter, - name=name) - return items + response = await client.update_search( + search_id='66722b2c8d184d4f9fb8b8fcf9d1a08c', + item_types=['PSScene'], + search_filter=search_filter, + name="My Search") + # --8<-- [end:update_search] + assert 'PSScene' not in response['item_types'] + assert '66722b2c8d184d4f9fb8b8fcf9d1a08c' in response['id'] # list_searches From ababdab79d3da446f490ad04eda400494132146b Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Fri, 5 May 2023 12:07:56 -0700 Subject: [PATCH 32/45] Added a few more tests, some work and some dont --- tests/snippets/test_data_api_snippets.py | 113 ++++++++++++++++------- 1 file changed, 78 insertions(+), 35 deletions(-) diff --git a/tests/snippets/test_data_api_snippets.py b/tests/snippets/test_data_api_snippets.py index 19f5c19fc..b55c23edc 100644 --- a/tests/snippets/test_data_api_snippets.py +++ b/tests/snippets/test_data_api_snippets.py @@ -89,90 +89,133 @@ async def test_snippet_update_search(search_filter): # --8<-- [end:update_search] assert 'PSScene' not in response['item_types'] assert '66722b2c8d184d4f9fb8b8fcf9d1a08c' in response['id'] + # TO DO: use a mocked search_id -# list_searches -async def test_snippet_list_searches(sort, search_type, limit): +@pytest.mark.anyio +async def test_snippet_list_searches(): '''Code snippet for list_searches.''' + # --8<-- [start:list_searches] async with planet.Session() as sess: client = sess.client('data') - async for item in client.list_searches(sort=sort, - search_type=search_type, - limit=limit): - return item + search_list = [ + item async for item in client.list_searches( + sort='created asc', search_type="saved", limit=10) + ] + # --8<-- [end:list_searches] + assert len(search_list) + # Verifying sort='created asc' + parsed_search_list = [ + datetime.strptime(search['created'], '%Y-%m-%dT%H:%M:%S.%fZ') + for search in search_list + ] + assert sorted(parsed_search_list) == parsed_search_list -# delete_search +@pytest.mark.anyio async def test_snippet_delete_search(search_id): '''Code snippet for delete_search.''' + # --8<-- [start:delete_search] async with planet.Session() as sess: client = sess.client('data') - await client.delete_search(search_id) + await client.delete_search(search_id='some-id') + # --8<-- [end:delete_search] + # TO DO: assert something -# get_search -async def test_snippet_get_search(search_id): +@pytest.mark.anyio +async def test_snippet_get_search(): '''Code snippet for get_search.''' + # --8<-- [start:get_search] async with planet.Session() as sess: client = sess.client('data') - items = await client.get_search(search_id) - return items + search = await client.get_search( + search_id='66722b2c8d184d4f9fb8b8fcf9d1a08c') + # --8<-- [start:get_search] + assert len(search) == 1 + assert search['id'] == '66722b2c8d184d4f9fb8b8fcf9d1a08c' -# run_search -async def test_snippet_run_search(search_id): +@pytest.mark.anyio +async def test_snippet_run_search(): '''Code snippet for run_search.''' + # --8<-- [start:run_search] async with planet.Session() as sess: client = sess.client('data') - async for item in client.run_search(search_id): - return item + items_list = [ + i async for i in client.run_search( + search_id='66722b2c8d184d4f9fb8b8fcf9d1a08c', limit=10) + ] + # --8<-- [end:run_search] + assert len(items_list) == 10 -# get_stats -async def test_snippet_get_stats(item_types, search_filter, interval): +@pytest.mark.anyio +async def test_snippet_get_stats(search_filter): '''Code snippet for get_stats.''' + # --8<-- [start:get_stats] async with planet.Session() as sess: client = sess.client('data') - items = await client.get_stats(item_types=item_types, + stats = await client.get_stats(item_types=['PSScene'], search_filter=search_filter, - interval=interval) - return items + interval="month") + # --8<-- [end:get_stats] + assert stats['interval'] == 'month' + assert len(stats['buckets']) != 0 -# list_item_assets -async def test_snippet_list_item_assets(item_type_id, item_id): +@pytest.mark.anyio +async def test_snippet_list_item_assets(): '''Code snippet for list_item_assets.''' + # --8<-- [start:list_item_assets] async with planet.Session() as sess: client = sess.client('data') - assets = await client.list_item_assets(item_type_id, item_id) - return assets + assets = await client.list_item_assets( + item_type_id='PSScene', item_id='20221003_002705_38_2461') + # --8<-- [end:list_item_assets] + assert len(assets) == 14 -# get_asset -async def test_snippet_get_asset(item_type, item_id, asset_type): +@pytest.mark.anyio +async def test_snippet_get_asset(): '''Code snippet for get_asset.''' + # --8<-- [start:get_asset] async with planet.Session() as sess: client = sess.client('data') - asset = await client.get_asset(item_type, item_id, asset_type) - return asset + asset = await client.get_asset(item_type_id='PSScene', + item_id='20221003_002705_38_2461', + asset_type_id='basic_udm2') + # --8<-- [end:get_asset] + assert asset['type'] == 'basic_udm2' -# activate_asset -async def test_snippet_activate_asset(item_type, item_id, asset_type): +@pytest.mark.anyio +async def test_snippet_activate_asset(): '''Code snippet for activate_asset.''' + # --8<-- [start:activate_asset] async with planet.Session() as sess: client = sess.client('data') - asset = await client.get_asset(item_type, item_id, asset_type) + asset = await client.get_asset(item_type_id='PSScene', + item_id='20221003_002705_38_2461', + asset_type_id='basic_udm2') await client.activate_asset(asset) + # --8<-- [end:activate_asset] + assert asset['status'] == 'active' -# wait_asset -async def test_snippet_wait_asset(item_type, item_id, asset_type): +@pytest.mark.anyio +async def test_snippet_wait_asset(): '''Code snippet for wait_asset.''' + # --8<-- [start:wait_asset] async with planet.Session() as sess: client = sess.client('data') - asset = await client.get_asset(item_type, item_id, asset_type) + asset = await client.get_asset(item_type_id='PSScene', + item_id='20221003_002705_38_2461', + asset_type_id='basic_udm2') _ = await client.wait_asset(asset, callback=print) + # --8<-- [end:wait_asset] + assert asset['status'] == 'activating' + assert asset == 1 # download_asset w/o checksum From a8d5d491f55ab561a311ee1e5b56d3917f5895d5 Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Fri, 5 May 2023 13:13:05 -0700 Subject: [PATCH 33/45] Added download snippets. --- tests/snippets/test_data_api_snippets.py | 52 ++++++++++-------------- 1 file changed, 21 insertions(+), 31 deletions(-) diff --git a/tests/snippets/test_data_api_snippets.py b/tests/snippets/test_data_api_snippets.py index b55c23edc..4be6c4660 100644 --- a/tests/snippets/test_data_api_snippets.py +++ b/tests/snippets/test_data_api_snippets.py @@ -20,7 +20,6 @@ [Planet Explorer](https://www.planet.com/explorer/) was used to define the AOIs and get the image ids. """ -from pathlib import Path import planet from planet import data_filter import json @@ -214,45 +213,36 @@ async def test_snippet_wait_asset(): asset_type_id='basic_udm2') _ = await client.wait_asset(asset, callback=print) # --8<-- [end:wait_asset] - assert asset['status'] == 'activating' - assert asset == 1 + assert asset['status'] == 'active' -# download_asset w/o checksum -async def test_snippet_download_asset_without_checksum(item_type, - item_id, - asset_type, - filename, - directory, - overwrite): +@pytest.mark.anyio +async def test_snippet_download_asset_without_checksum(): '''Code snippet for download_asset without a checksum.''' + # --8<-- [start:download_asset_without_checksum] async with planet.Session() as sess: client = sess.client('data') - asset = await client.get_asset(item_type, item_id, asset_type) - path = await client.download_asset(asset=asset, - filename=filename, - directory=Path(directory), - overwrite=overwrite) - return path - - -# download_asset w/ checksum -async def test_snippet_download_asset_with_checksum(item_type, - item_id, - asset_type, - filename, - directory, - overwrite): + asset = await client.get_asset(item_type_id='PSScene', + item_id='20221003_002705_38_2461', + asset_type_id='basic_udm2') + path = await client.download_asset(asset=asset) + # --8<-- [end:download_asset_without_checksum] + assert path.exists() + + +@pytest.mark.anyio +async def test_snippet_download_asset_with_checksum(): '''Code snippet for download_asset with a checksum.''' + # --8<-- [start:download_asset_with_checksum] async with planet.Session() as sess: client = sess.client('data') - asset = await client.get_asset(item_type, item_id, asset_type) - path = await client.download_asset(asset=asset, - filename=filename, - directory=Path(directory), - overwrite=overwrite) + asset = await client.get_asset(item_type_id='PSScene', + item_id='20221003_002705_38_2461', + asset_type_id='basic_udm2') + path = await client.download_asset(asset=asset) client.validate_checksum(asset, path) - return path + # --8<-- [end:download_asset_with_checksum] + assert path.exists() # Create search filters From d8e70462a2e2bf9418ea0ab75b0b36ab1a0b6280 Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Tue, 9 May 2023 10:26:18 -0700 Subject: [PATCH 34/45] Renamed file for testing. --- tests/snippets/{orders_api.py => test_orders_api_snippets.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/snippets/{orders_api.py => test_orders_api_snippets.py} (100%) diff --git a/tests/snippets/orders_api.py b/tests/snippets/test_orders_api_snippets.py similarity index 100% rename from tests/snippets/orders_api.py rename to tests/snippets/test_orders_api_snippets.py From 3e769b0e3112a1bd1787fe02b4d1214313c8fa92 Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Tue, 9 May 2023 10:28:10 -0700 Subject: [PATCH 35/45] Removed unused pytest fixture. --- tests/snippets/test_data_api_snippets.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/tests/snippets/test_data_api_snippets.py b/tests/snippets/test_data_api_snippets.py index 4be6c4660..e8e62ca66 100644 --- a/tests/snippets/test_data_api_snippets.py +++ b/tests/snippets/test_data_api_snippets.py @@ -33,17 +33,6 @@ def search_filter(get_test_file_json): return get_test_file_json(filename) -@pytest.fixture -def item_descriptions(get_test_file_json): - item_ids = [ - '20220125_075509_67_1061', - '20220125_075511_17_1061', - '20220125_075650_17_1061' - ] - items = [get_test_file_json(f'data_item_{id}.json') for id in item_ids] - return items - - @pytest.mark.anyio async def test_snippet_search(search_filter): '''Code snippet for search.''' From 307cd994d6850ca208c380422723547b91c02e85 Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Wed, 10 May 2023 10:47:15 -0700 Subject: [PATCH 36/45] Added a bunch of orders snippets with clever tricks to get order ids. cancel orders is broken. --- tests/snippets/test_orders_api_snippets.py | 117 +++++++++++++-------- 1 file changed, 74 insertions(+), 43 deletions(-) diff --git a/tests/snippets/test_orders_api_snippets.py b/tests/snippets/test_orders_api_snippets.py index ef4cf5740..a986697b2 100644 --- a/tests/snippets/test_orders_api_snippets.py +++ b/tests/snippets/test_orders_api_snippets.py @@ -23,43 +23,103 @@ import json from pathlib import Path import planet +import pytest -# create_order() -async def create_order(request): +@pytest.fixture +def create_request(): + '''Create an order request.''' + + # The Orders API will be asked to mask, or clip, results to + # this area of interest. + aoi = { + "type": + "Polygon", + "coordinates": [[[-91.198465, 42.893071], [-91.121931, 42.893071], + [-91.121931, 42.946205], [-91.198465, 42.946205], + [-91.198465, 42.893071]]] + } + + # In practice, you will use a Data API search to find items, but + # for this example take them as given. + items = ['20200925_161029_69_2223', '20200925_161027_48_2223'] + + order = planet.order_request.build_request( + name='iowa_order', + products=[ + planet.order_request.product(item_ids=items, + product_bundle='analytic_udm2', + item_type='PSScene') + ], + tools=[planet.order_request.clip_tool(aoi=aoi)]) + + return order + + +@pytest.mark.anyio +async def test_snippet_create_order(): '''Code snippet for create_order.''' + order_request = { + "name": + "test", + "products": [{ + "item_ids": ['20230508_155304_44_2480'], + "item_type": "PSScene", + "product_bundle": "analytic_udm2" + }], + } + # --8<-- [start:create_order] async with planet.Session() as sess: client = sess.client('orders') - order = await client.create_order(request=request) + order = await client.create_order(request=order_request) + # --8<-- [end:create_order] return order + assert len(order['id']) > 0 -# get_order() -async def get_order(order_id): +@pytest.mark.anyio +async def test_snippet_get_order(): '''Code snippet for get_order.''' + order = await test_snippet_create_order() + order_id = order['id'] + # --8<-- [start:get_order] async with planet.Session() as sess: client = sess.client('orders') order = await client.get_order(order_id=order_id) - return order + # --8<-- [end:get_order] + assert len(order['id']) > 0 + # TO DO: get order ID some other way -# cancel_order() -async def cancel_order(order_id): +@pytest.mark.anyio +async def test_snippet_cancel_order(): '''Code snippet for cancel_order.''' + order = await test_snippet_create_order() + order_id = order['id'] + # --8<-- [start:cancel_order] async with planet.Session() as sess: client = sess.client('orders') - json_resp = await client.cancel_order(order_id=order_id) - return json.dumps(json_resp) + order = await client.cancel_order(order_id=order_id) + # --8<-- [end:cancel_order] + # TO DO: get order ID some other way + assert order['state'] == 'cancelled' # cancel_orders() -async def cancel_orders(order_id1, order_id2): +@pytest.mark.anyio +async def test_snippets_cancel_multiple_orders(): '''Code snippet for cancel_order.''' - order_ids = [order_id1, order_id2] + order1 = await test_snippet_create_order() + order2 = await test_snippet_create_order() + order_id1 = order1['id'] + order_id2 = order2['id'] + # --8<-- [start:cancel_orders] async with planet.Session() as sess: client = sess.client('orders') - json_resp = await client.cancel_order(order_ids=order_ids) - return json.dumps(json_resp) + orders = await client.cancel_orders(order_ids=[order_id1, order_id2]) + # --8<-- [end:cancel_orders] + assert order1['state'] == 'cancelled' + assert order2['state'] == 'cancelled' # aggregated_order_stats() @@ -123,35 +183,6 @@ async def list_orders(): return order -def create_request(): - '''Create an order request.''' - - # The Orders API will be asked to mask, or clip, results to - # this area of interest. - aoi = { - "type": - "Polygon", - "coordinates": [[[-91.198465, 42.893071], [-91.121931, 42.893071], - [-91.121931, 42.946205], [-91.198465, 42.946205], - [-91.198465, 42.893071]]] - } - - # In practice, you will use a Data API search to find items, but - # for this example take them as given. - items = ['20200925_161029_69_2223', '20200925_161027_48_2223'] - - order = planet.order_request.build_request( - name='iowa_order', - products=[ - planet.order_request.product(item_ids=items, - product_bundle='analytic_udm2', - item_type='PSScene') - ], - tools=[planet.order_request.clip_tool(aoi=aoi)]) - - return order - - async def order_example(): # Create an order request request = create_request() From a06abfc3a058ab5bf0dab2746b8a8b94bfefd98b Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Wed, 10 May 2023 12:56:33 -0700 Subject: [PATCH 37/45] Remove downloaded files. --- tests/snippets/test_data_api_snippets.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/snippets/test_data_api_snippets.py b/tests/snippets/test_data_api_snippets.py index e8e62ca66..e7ebd28dd 100644 --- a/tests/snippets/test_data_api_snippets.py +++ b/tests/snippets/test_data_api_snippets.py @@ -25,6 +25,7 @@ import json from datetime import datetime import pytest +import os @pytest.fixture @@ -206,7 +207,7 @@ async def test_snippet_wait_asset(): @pytest.mark.anyio -async def test_snippet_download_asset_without_checksum(): +async def test_snippet_download_asset_data_api_without_checksum(): '''Code snippet for download_asset without a checksum.''' # --8<-- [start:download_asset_without_checksum] async with planet.Session() as sess: @@ -217,10 +218,11 @@ async def test_snippet_download_asset_without_checksum(): path = await client.download_asset(asset=asset) # --8<-- [end:download_asset_without_checksum] assert path.exists() + os.remove(path) @pytest.mark.anyio -async def test_snippet_download_asset_with_checksum(): +async def test_snippet_download_asset_data_api_with_checksum(): '''Code snippet for download_asset with a checksum.''' # --8<-- [start:download_asset_with_checksum] async with planet.Session() as sess: @@ -232,6 +234,7 @@ async def test_snippet_download_asset_with_checksum(): client.validate_checksum(asset, path) # --8<-- [end:download_asset_with_checksum] assert path.exists() + os.remove(path) # Create search filters From a0eb08557c94532458364f989aee6f46895adb5b Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Wed, 10 May 2023 12:57:01 -0700 Subject: [PATCH 38/45] Download asset added. --- tests/snippets/test_orders_api_snippets.py | 56 ++++++++++++++-------- 1 file changed, 37 insertions(+), 19 deletions(-) diff --git a/tests/snippets/test_orders_api_snippets.py b/tests/snippets/test_orders_api_snippets.py index a986697b2..55fc60ac0 100644 --- a/tests/snippets/test_orders_api_snippets.py +++ b/tests/snippets/test_orders_api_snippets.py @@ -21,6 +21,7 @@ the AOIs and get the image ids. """ import json +import os from pathlib import Path import planet import pytest @@ -105,7 +106,6 @@ async def test_snippet_cancel_order(): assert order['state'] == 'cancelled' -# cancel_orders() @pytest.mark.anyio async def test_snippets_cancel_multiple_orders(): '''Code snippet for cancel_order.''' @@ -118,42 +118,60 @@ async def test_snippets_cancel_multiple_orders(): client = sess.client('orders') orders = await client.cancel_orders(order_ids=[order_id1, order_id2]) # --8<-- [end:cancel_orders] - assert order1['state'] == 'cancelled' - assert order2['state'] == 'cancelled' + assert orders['result']['succeeded']['count'] == 2 -# aggregated_order_stats() -async def aggregated_order_stats(): +@pytest.mark.anyio +async def test_snippet_aggregated_order_stats(): '''Code snippet for aggregated_order_stats.''' + # --8<-- [start:aggregated_order_stats] async with planet.Session() as sess: client = sess.client('orders') json_resp = await client.aggregated_order_stats() - return json.dumps(json_resp) + # --8<-- [start:aggregated_order_stats] + assert 'organization' and 'user' in [key for key in json_resp.keys()] -# download_asset() -async def download_asset(dl_url, directory): +@pytest.mark.anyio +async def test_snippet_download_asset_orders_api_checksum(): '''Code snippet for download_asset.''' + # order = await test_snippet_create_order() + # order_id = order['id'] + order_id = "decde86f-a57a-45bd-89f9-2af49a661e25" + # --8<-- [start:download_asset] async with planet.Session() as sess: client = sess.client('orders') - filename = await client.download_asset(location=dl_url, - directory=directory) - dl_path = Path(directory, filename) - return dl_path - - -# download_order() w/o checksum -async def download_order_without_checksum(order_id, directory): - '''Code snippet for download_order without checksum.''' + order = await client.get_order(order_id=order_id) + # Find order info + info = order['_links']['results'] + # Find and download the the composite.tif file + for i in info: + if 'composite.tif' in i['name']: + location = i['location'] + filename = await client.download_asset(location=location) + # --8<-- [end:download_asset] + assert filename.exists() + os.remove(filename) + else: + pass + + +# download_order() w.0 checksum +async def download_order_without_checksum(): + '''Code snippet for download_order with checksum.''' + # Options: 'MD5' or 'SHA256' + checksum = 'MD5' async with planet.Session() as sess: client = sess.client('orders') - filenames = await client.download_order(order_id, directory=directory) + filenames = await client.download_order(order_id=order_id, + directory=directory) + client.validate_checksum(Path(directory, order_id), checksum) dl_path = Path(directory, filenames) return dl_path # download_order() w checksum -async def download_order_with_checksum(order_id, directory): +async def download_order_with_checksum(): '''Code snippet for download_order with checksum.''' # Options: 'MD5' or 'SHA256' checksum = 'MD5' From 92bc2eb6732a07dcc184f2593cde6dc49cac1d9d Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Thu, 11 May 2023 10:27:58 -0700 Subject: [PATCH 39/45] Added all passing Orders tests. --- tests/snippets/test_orders_api_snippets.py | 106 ++++++++++----------- 1 file changed, 52 insertions(+), 54 deletions(-) diff --git a/tests/snippets/test_orders_api_snippets.py b/tests/snippets/test_orders_api_snippets.py index 55fc60ac0..0b4d01894 100644 --- a/tests/snippets/test_orders_api_snippets.py +++ b/tests/snippets/test_orders_api_snippets.py @@ -20,7 +20,7 @@ [Planet Explorer](https://www.planet.com/explorer/) was used to define the AOIs and get the image ids. """ -import json +import shutil import os from pathlib import Path import planet @@ -58,7 +58,7 @@ def create_request(): @pytest.mark.anyio -async def test_snippet_create_order(): +async def test_snippet_orders_create_order(): '''Code snippet for create_order.''' order_request = { "name": @@ -79,9 +79,9 @@ async def test_snippet_create_order(): @pytest.mark.anyio -async def test_snippet_get_order(): +async def test_snippet_orders_get_order(): '''Code snippet for get_order.''' - order = await test_snippet_create_order() + order = await test_snippet_orders_create_order() order_id = order['id'] # --8<-- [start:get_order] async with planet.Session() as sess: @@ -93,9 +93,9 @@ async def test_snippet_get_order(): @pytest.mark.anyio -async def test_snippet_cancel_order(): +async def test_snippet_orders_cancel_order(): '''Code snippet for cancel_order.''' - order = await test_snippet_create_order() + order = await test_snippet_orders_create_order() order_id = order['id'] # --8<-- [start:cancel_order] async with planet.Session() as sess: @@ -109,8 +109,8 @@ async def test_snippet_cancel_order(): @pytest.mark.anyio async def test_snippets_cancel_multiple_orders(): '''Code snippet for cancel_order.''' - order1 = await test_snippet_create_order() - order2 = await test_snippet_create_order() + order1 = await test_snippet_orders_create_order() + order2 = await test_snippet_orders_create_order() order_id1 = order1['id'] order_id2 = order2['id'] # --8<-- [start:cancel_orders] @@ -122,7 +122,7 @@ async def test_snippets_cancel_multiple_orders(): @pytest.mark.anyio -async def test_snippet_aggregated_order_stats(): +async def test_snippet_orders_aggregated_order_stats(): '''Code snippet for aggregated_order_stats.''' # --8<-- [start:aggregated_order_stats] async with planet.Session() as sess: @@ -133,9 +133,9 @@ async def test_snippet_aggregated_order_stats(): @pytest.mark.anyio -async def test_snippet_download_asset_orders_api_checksum(): +async def test_snippet_orders_download_asset(): '''Code snippet for download_asset.''' - # order = await test_snippet_create_order() + # order = await test_snippet_orders_create_order() # order_id = order['id'] order_id = "decde86f-a57a-45bd-89f9-2af49a661e25" # --8<-- [start:download_asset] @@ -156,63 +156,61 @@ async def test_snippet_download_asset_orders_api_checksum(): pass -# download_order() w.0 checksum -async def download_order_without_checksum(): - '''Code snippet for download_order with checksum.''' - # Options: 'MD5' or 'SHA256' - checksum = 'MD5' +@pytest.mark.anyio +async def test_snippet_orders_download_order_without_checksum(): + '''Code snippet for download_order without checksum.''' + order_id = "decde86f-a57a-45bd-89f9-2af49a661e25" + # --8<-- [start:download_order_without_checksum] async with planet.Session() as sess: client = sess.client('orders') - filenames = await client.download_order(order_id=order_id, - directory=directory) - client.validate_checksum(Path(directory, order_id), checksum) - dl_path = Path(directory, filenames) - return dl_path + filenames = await client.download_order(order_id=order_id) + # --8<-- [end:download_order_without_checksum] + assert all([filename.exists() for filename in filenames]) + shutil.rmtree(filenames[0].parent) -# download_order() w checksum -async def download_order_with_checksum(): +@pytest.mark.anyio +async def test_snippet_orders_download_order_with_checksum(): '''Code snippet for download_order with checksum.''' - # Options: 'MD5' or 'SHA256' - checksum = 'MD5' + order_id = "decde86f-a57a-45bd-89f9-2af49a661e25" + # --8<-- [start:download_order_without_checksum] async with planet.Session() as sess: client = sess.client('orders') - filenames = await client.download_order(order_id=order_id, - directory=directory) - client.validate_checksum(Path(directory, order_id), checksum) - dl_path = Path(directory, filenames) - return dl_path + filenames = await client.download_order(order_id=order_id) + client.validate_checksum(directory=Path(order_id), checksum="MD5") + # --8<-- [end:download_order_without_checksum] + assert all([filename.exists() for filename in filenames]) + shutil.rmtree(filenames[0].parent) -# wait() -async def wait(order_id): +@pytest.mark.anyio +async def test_snippet_orders_wait(): '''Code snippet for wait.''' + order_id = "decde86f-a57a-45bd-89f9-2af49a661e25" + # --8<-- [start:wait] async with planet.Session() as sess: client = sess.client('orders') - _ = await client.wait(order_id=order_id, callback=print) + state = await client.wait(order_id=order_id) + # --8<-- [end:wait] + assert state == 'success' -# list_orders() -async def list_orders(): +@pytest.mark.anyio +async def test_snippet_orders_list_orders(): '''Code snippet for list_orders.''' + # --8<-- [start:list_orders] async with planet.Session() as sess: client = sess.client('orders') - async for order in client.list_orders(): - return order - - -async def order_example(): - # Create an order request - request = create_request() - - # Create order - order = await create_order(request) - - # Get order ID - order_id = order['id'] - - # Wait for download to be ready - await wait(order_id) - - # Download order - _ = await download_order_with_checksum(order_id, './') + order_descriptions = [order async for order in client.list_orders()] + # --8<-- [start:list_orders] + assert order_descriptions[0].keys() == { + '_links', + 'created_on', + 'error_hints', + 'id', + 'last_message', + 'last_modified', + 'name', + 'products', + 'state' + } From e718771ce737e1e0909abcb28d1085fc9e8caa80 Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Thu, 11 May 2023 10:42:17 -0700 Subject: [PATCH 40/45] Fixed all broken tests. --- tests/snippets/test_data_api_snippets.py | 45 ++++++++++++++---------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/tests/snippets/test_data_api_snippets.py b/tests/snippets/test_data_api_snippets.py index e7ebd28dd..af3a77109 100644 --- a/tests/snippets/test_data_api_snippets.py +++ b/tests/snippets/test_data_api_snippets.py @@ -35,7 +35,7 @@ def search_filter(get_test_file_json): @pytest.mark.anyio -async def test_snippet_search(search_filter): +async def test_snippet_data_search(search_filter): '''Code snippet for search.''' # --8<-- [start:search] async with planet.Session() as sess: @@ -52,7 +52,7 @@ async def test_snippet_search(search_filter): @pytest.mark.anyio -async def test_snippet_create_search(search_filter): +async def test_snippet_data_create_search(search_filter): '''Code snippet for create_search.''' # --8<-- [start:create_search] async with planet.Session() as sess: @@ -62,10 +62,11 @@ async def test_snippet_create_search(search_filter): name="My Search") # --8<-- [end:create_search] assert 'PSScene' in response['item_types'] + return response @pytest.mark.anyio -async def test_snippet_update_search(search_filter): +async def test_snippet_data_update_search(search_filter): '''Code snippet for update_search.''' # --8<-- [start:update_search] async with planet.Session() as sess: @@ -76,13 +77,13 @@ async def test_snippet_update_search(search_filter): search_filter=search_filter, name="My Search") # --8<-- [end:update_search] - assert 'PSScene' not in response['item_types'] + assert ['PSScene'] not in response['item_types'] assert '66722b2c8d184d4f9fb8b8fcf9d1a08c' in response['id'] # TO DO: use a mocked search_id @pytest.mark.anyio -async def test_snippet_list_searches(): +async def test_snippet_data_list_searches(): '''Code snippet for list_searches.''' # --8<-- [start:list_searches] async with planet.Session() as sess: @@ -92,7 +93,7 @@ async def test_snippet_list_searches(): sort='created asc', search_type="saved", limit=10) ] # --8<-- [end:list_searches] - assert len(search_list) + assert len(search_list) == 10 # Verifying sort='created asc' parsed_search_list = [ datetime.strptime(search['created'], '%Y-%m-%dT%H:%M:%S.%fZ') @@ -102,18 +103,24 @@ async def test_snippet_list_searches(): @pytest.mark.anyio -async def test_snippet_delete_search(search_id): +async def test_snippet_data_delete_search(search_filter): '''Code snippet for delete_search.''' + new_search = await test_snippet_data_create_search(search_filter) + search_id = new_search['id'] # --8<-- [start:delete_search] async with planet.Session() as sess: client = sess.client('data') - await client.delete_search(search_id='some-id') + await client.delete_search(search_id=search_id) # --8<-- [end:delete_search] - # TO DO: assert something + search_list = [ + item async for item in client.list_searches( + sort='created asc', search_type="saved", limit=10) + ] + assert search_id not in [search['id'] for search in search_list] @pytest.mark.anyio -async def test_snippet_get_search(): +async def test_snippet_data_get_search(): '''Code snippet for get_search.''' # --8<-- [start:get_search] async with planet.Session() as sess: @@ -121,12 +128,12 @@ async def test_snippet_get_search(): search = await client.get_search( search_id='66722b2c8d184d4f9fb8b8fcf9d1a08c') # --8<-- [start:get_search] - assert len(search) == 1 + assert len(search) == 10 assert search['id'] == '66722b2c8d184d4f9fb8b8fcf9d1a08c' @pytest.mark.anyio -async def test_snippet_run_search(): +async def test_snippet_data_run_search(): '''Code snippet for run_search.''' # --8<-- [start:run_search] async with planet.Session() as sess: @@ -140,7 +147,7 @@ async def test_snippet_run_search(): @pytest.mark.anyio -async def test_snippet_get_stats(search_filter): +async def test_snippet_data_get_stats(search_filter): '''Code snippet for get_stats.''' # --8<-- [start:get_stats] async with planet.Session() as sess: @@ -154,7 +161,7 @@ async def test_snippet_get_stats(search_filter): @pytest.mark.anyio -async def test_snippet_list_item_assets(): +async def test_snippet_data_list_item_assets(): '''Code snippet for list_item_assets.''' # --8<-- [start:list_item_assets] async with planet.Session() as sess: @@ -166,7 +173,7 @@ async def test_snippet_list_item_assets(): @pytest.mark.anyio -async def test_snippet_get_asset(): +async def test_snippet_data_get_asset(): '''Code snippet for get_asset.''' # --8<-- [start:get_asset] async with planet.Session() as sess: @@ -179,7 +186,7 @@ async def test_snippet_get_asset(): @pytest.mark.anyio -async def test_snippet_activate_asset(): +async def test_snippet_data_activate_asset(): '''Code snippet for activate_asset.''' # --8<-- [start:activate_asset] async with planet.Session() as sess: @@ -193,7 +200,7 @@ async def test_snippet_activate_asset(): @pytest.mark.anyio -async def test_snippet_wait_asset(): +async def test_snippet_data_wait_asset(): '''Code snippet for wait_asset.''' # --8<-- [start:wait_asset] async with planet.Session() as sess: @@ -207,7 +214,7 @@ async def test_snippet_wait_asset(): @pytest.mark.anyio -async def test_snippet_download_asset_data_api_without_checksum(): +async def test_snippet_data_download_asset_without_checksum(): '''Code snippet for download_asset without a checksum.''' # --8<-- [start:download_asset_without_checksum] async with planet.Session() as sess: @@ -222,7 +229,7 @@ async def test_snippet_download_asset_data_api_without_checksum(): @pytest.mark.anyio -async def test_snippet_download_asset_data_api_with_checksum(): +async def test_snippet_data_download_asset_with_checksum(): '''Code snippet for download_asset with a checksum.''' # --8<-- [start:download_asset_with_checksum] async with planet.Session() as sess: From cd0cae9574a34124e4759711f4b8a968c38572e2 Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Thu, 11 May 2023 10:42:40 -0700 Subject: [PATCH 41/45] Fixed unused test --- tests/snippets/test_orders_api_snippets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/snippets/test_orders_api_snippets.py b/tests/snippets/test_orders_api_snippets.py index 0b4d01894..66e75af92 100644 --- a/tests/snippets/test_orders_api_snippets.py +++ b/tests/snippets/test_orders_api_snippets.py @@ -74,8 +74,8 @@ async def test_snippet_orders_create_order(): client = sess.client('orders') order = await client.create_order(request=order_request) # --8<-- [end:create_order] - return order assert len(order['id']) > 0 + return order @pytest.mark.anyio From cfbf44da10dbdbdfea1ef781e77c59fc8adc8756 Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Thu, 11 May 2023 11:10:28 -0700 Subject: [PATCH 42/45] test --- tests/snippets/test_orders_api_snippets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/snippets/test_orders_api_snippets.py b/tests/snippets/test_orders_api_snippets.py index 66e75af92..a3f8d6825 100644 --- a/tests/snippets/test_orders_api_snippets.py +++ b/tests/snippets/test_orders_api_snippets.py @@ -80,7 +80,7 @@ async def test_snippet_orders_create_order(): @pytest.mark.anyio async def test_snippet_orders_get_order(): - '''Code snippet for get_order.''' + '''Code snippet for get_orders.''' order = await test_snippet_orders_create_order() order_id = order['id'] # --8<-- [start:get_order] From 008bb5553ad709443998db0b07d6719aa2c1c698 Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Thu, 11 May 2023 11:13:57 -0700 Subject: [PATCH 43/45] linting --- tests/snippets/test_data_api_snippets.py | 8 ++++---- tests/snippets/test_orders_api_snippets.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/snippets/test_data_api_snippets.py b/tests/snippets/test_data_api_snippets.py index af3a77109..8770f3629 100644 --- a/tests/snippets/test_data_api_snippets.py +++ b/tests/snippets/test_data_api_snippets.py @@ -111,11 +111,11 @@ async def test_snippet_data_delete_search(search_filter): async with planet.Session() as sess: client = sess.client('data') await client.delete_search(search_id=search_id) - # --8<-- [end:delete_search] + # --8<-- [end:delete_search] search_list = [ - item async for item in client.list_searches( - sort='created asc', search_type="saved", limit=10) - ] + item async for item in client.list_searches( + sort='created asc', search_type="saved", limit=10) + ] assert search_id not in [search['id'] for search in search_list] diff --git a/tests/snippets/test_orders_api_snippets.py b/tests/snippets/test_orders_api_snippets.py index a3f8d6825..66e75af92 100644 --- a/tests/snippets/test_orders_api_snippets.py +++ b/tests/snippets/test_orders_api_snippets.py @@ -80,7 +80,7 @@ async def test_snippet_orders_create_order(): @pytest.mark.anyio async def test_snippet_orders_get_order(): - '''Code snippet for get_orders.''' + '''Code snippet for get_order.''' order = await test_snippet_orders_create_order() order_id = order['id'] # --8<-- [start:get_order] From 84b3edec428d5397a711753357531f27123e14ad Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Mon, 10 Jul 2023 13:49:56 -0700 Subject: [PATCH 44/45] Have tests create their own search id; limit to 2 items. --- tests/snippets/test_data_api_snippets.py | 28 +++++++++++++----------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/tests/snippets/test_data_api_snippets.py b/tests/snippets/test_data_api_snippets.py index 8770f3629..5012888df 100644 --- a/tests/snippets/test_data_api_snippets.py +++ b/tests/snippets/test_data_api_snippets.py @@ -45,10 +45,10 @@ async def test_snippet_data_search(search_filter): search_filter=search_filter, name="My Search", sort="acquired asc", - limit=10) + limit=2) ] # --8<-- [end:search] - assert len(items_list) == 10 + assert len(items_list) == 2 @pytest.mark.anyio @@ -90,10 +90,10 @@ async def test_snippet_data_list_searches(): client = sess.client('data') search_list = [ item async for item in client.list_searches( - sort='created asc', search_type="saved", limit=10) + sort='created asc', search_type="saved", limit=2) ] # --8<-- [end:list_searches] - assert len(search_list) == 10 + assert len(search_list) == 2 # Verifying sort='created asc' parsed_search_list = [ datetime.strptime(search['created'], '%Y-%m-%dT%H:%M:%S.%fZ') @@ -114,36 +114,38 @@ async def test_snippet_data_delete_search(search_filter): # --8<-- [end:delete_search] search_list = [ item async for item in client.list_searches( - sort='created asc', search_type="saved", limit=10) + sort='created asc', search_type="saved", limit=2) ] assert search_id not in [search['id'] for search in search_list] @pytest.mark.anyio -async def test_snippet_data_get_search(): +async def test_snippet_data_get_search(search_filter): '''Code snippet for get_search.''' + new_search = await test_snippet_data_create_search(search_filter) + search_id = new_search['id'] # --8<-- [start:get_search] async with planet.Session() as sess: client = sess.client('data') - search = await client.get_search( - search_id='66722b2c8d184d4f9fb8b8fcf9d1a08c') + search = await client.get_search(search_id=search_id) # --8<-- [start:get_search] assert len(search) == 10 - assert search['id'] == '66722b2c8d184d4f9fb8b8fcf9d1a08c' + assert search['id'] == search_id @pytest.mark.anyio -async def test_snippet_data_run_search(): +async def test_snippet_data_run_search(search_filter): '''Code snippet for run_search.''' + new_search = await test_snippet_data_create_search(search_filter) + search_id = new_search['id'] # --8<-- [start:run_search] async with planet.Session() as sess: client = sess.client('data') items_list = [ - i async for i in client.run_search( - search_id='66722b2c8d184d4f9fb8b8fcf9d1a08c', limit=10) + i async for i in client.run_search(search_id=search_id, limit=2) ] # --8<-- [end:run_search] - assert len(items_list) == 10 + assert len(items_list) == 2 @pytest.mark.anyio From a38c0c1bdff78da5678121e7ddb0fc1c41710151 Mon Sep 17 00:00:00 2001 From: Kevin Lacaille Date: Tue, 11 Jul 2023 16:06:35 -0700 Subject: [PATCH 45/45] Added succesful order to download. Temp. solution. --- tests/snippets/test_orders_api_snippets.py | 101 +++++++++++++++++++-- 1 file changed, 92 insertions(+), 9 deletions(-) diff --git a/tests/snippets/test_orders_api_snippets.py b/tests/snippets/test_orders_api_snippets.py index 66e75af92..4e6553ede 100644 --- a/tests/snippets/test_orders_api_snippets.py +++ b/tests/snippets/test_orders_api_snippets.py @@ -57,6 +57,86 @@ def create_request(): return order +@pytest.mark.anyio +def create_succesful_order(): + '''Code snippet for create_order.''' + order_details = { + "_links": { + "_self": + "https://api.planet.com/compute/ops/orders/v2/785185e1-8d02-469d-840e-475ec9888a17", + "results": + [{ + "delivery": "success", + "expires_at": "2023-07-12T22:58:47.877Z", + "location": + "https://api.planet.com/compute/ops/download/?token=eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2ODkyMDI3MjcsInN1YiI6IkdIWSszZHZhQ2VnUWYza2grVzZjbDllQmkzOG85VWdQMjhXL2lNY0tTYUxjblk1ZGR5d2phS05Jb0V1SFpUL2dOd1ErMFBDUlRtVWpRNTRCcWo2Wld3PT0iLCJ0b2tlbl90eXBlIjoiZG93bmxvYWQtYXNzZXQtc3RhY2siLCJhb2kiOiIiLCJhc3NldHMiOlt7Iml0ZW1fdHlwZSI6IiIsImFzc2V0X3R5cGUiOiIiLCJpdGVtX2lkIjoiIn1dLCJ1cmwiOiJodHRwczovL3N0b3JhZ2UuZ29vZ2xlYXBpcy5jb20vY29tcHV0ZS1vcmRlcnMtbGl2ZS83ODUxODVlMS04ZDAyLTQ2OWQtODQwZS00NzVlYzk4ODhhMTcvY29tcG9zaXRlLnRpZj9YLUdvb2ctQWxnb3JpdGhtPUdPT0c0LVJTQS1TSEEyNTZcdTAwMjZYLUdvb2ctQ3JlZGVudGlhbD1jb21wdXRlLWdjcy1zdmNhY2MlNDBwbGFuZXQtY29tcHV0ZS1wcm9kLmlhbS5nc2VydmljZWFjY291bnQuY29tJTJGMjAyMzA3MTElMkZhdXRvJTJGc3RvcmFnZSUyRmdvb2c0X3JlcXVlc3RcdTAwMjZYLUdvb2ctRGF0ZT0yMDIzMDcxMVQyMjU4NDdaXHUwMDI2WC1Hb29nLUV4cGlyZXM9ODYzOTlcdTAwMjZYLUdvb2ctU2lnbmF0dXJlPTA1NmI0MzAxYWI3MzUxNjU3MDU2NDQ0NTllYmU4OTJjZjRkNWM3YzE1ODAzNWQ0NmQwYzM0ODIyNjk0NjIyNDE3NmUwYTI2NWI3MGM1NTFkNzI1ZGM3MDI4NTk2MmI1NDY2MzljZGFjYzFiZWFlNDU5NTdlNzBmNzgwZmI5ODM4NGYyODE1NWQ2ZjhlMjQyZmNjZTNhOWRjMTA5MTQ2NmI0YmI3MDJmMGUyMjM5NzdiMmYxMDI0MDEzMzI2MDJlY2FkZTM5OThmMzZhYjZiYWNkYmI0ZmMyMTkxZjBkYmNhMTJkNmEyYmFiMTE2ZGQwMmI1YzdkYjQ3YWRjY2YwOWU3Y2FhNmI2MzNmY2M4MDExZDg1ZTI5YzA1NzI5OWI3MjA4YzdhZjQ5YjU0YThkYjkzMTk2MDA0MDkzMzM2NGUzZTRhOGUyODIwMGMxODVhNzlkZjU4NjQ2NGMxMTJjYWZmYmZmMDk5MThiY2E0ZTgxNTllYjk2Y2Y1MTQ2M2YyOTdmM2FhMjQ4NGY3ZDIyNjE0YzBmMjU5MWI5OTM4YjAwNzRjNmI3NWRmZDg2MDVlODliNjM2Njg5YmVlYWE0ZjBiYTcwOGI5OTdhYmU1MWI2NGYzM2QzMTRhMzlmM2E2ZjlhZjNlMzgwZGU4YmVjYzRiMzIwZTNiOTI5YTVlYzgzXHUwMDI2WC1Hb29nLVNpZ25lZEhlYWRlcnM9aG9zdCIsInNvdXJjZSI6Ik9yZGVycyBTZXJ2aWNlIn0.YJ2N1KwRg8YmiW2E3HRlSEyVlVMRK8LIsbdQfCeXWP32e9sYQKOshGCGNRMblmyYqARAq5YWfWyk99h7igT38w", + "name": "785185e1-8d02-469d-840e-475ec9888a17/composite.tif" + }, + { + "delivery": + "success", + "expires_at": + "2023-07-12T22:58:47.880Z", + "location": + "https://api.planet.com/compute/ops/download/?token=eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2ODkyMDI3MjcsInN1YiI6InNwdmpvY3NTd3Fsd2dMYTZUSndHdWlaM2NFNS9lbThta3pDNzdHRmNQamZkdDhSZHdOdEJFUU9YcjdUcDFMQWZKOFBvUTdQL2NkZVF4bXZpOW81TE1RPT0iLCJ0b2tlbl90eXBlIjoiZG93bmxvYWQtYXNzZXQtc3RhY2siLCJhb2kiOiIiLCJhc3NldHMiOlt7Iml0ZW1fdHlwZSI6IiIsImFzc2V0X3R5cGUiOiIiLCJpdGVtX2lkIjoiIn1dLCJ1cmwiOiJodHRwczovL3N0b3JhZ2UuZ29vZ2xlYXBpcy5jb20vY29tcHV0ZS1vcmRlcnMtbGl2ZS83ODUxODVlMS04ZDAyLTQ2OWQtODQwZS00NzVlYzk4ODhhMTcvY29tcG9zaXRlX21ldGFkYXRhLmpzb24_WC1Hb29nLUFsZ29yaXRobT1HT09HNC1SU0EtU0hBMjU2XHUwMDI2WC1Hb29nLUNyZWRlbnRpYWw9Y29tcHV0ZS1nY3Mtc3ZjYWNjJTQwcGxhbmV0LWNvbXB1dGUtcHJvZC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSUyRjIwMjMwNzExJTJGYXV0byUyRnN0b3JhZ2UlMkZnb29nNF9yZXF1ZXN0XHUwMDI2WC1Hb29nLURhdGU9MjAyMzA3MTFUMjI1ODQ3Wlx1MDAyNlgtR29vZy1FeHBpcmVzPTg2Mzk5XHUwMDI2WC1Hb29nLVNpZ25hdHVyZT00YmFiMGZiZjlmMTFjYzlhMjZiNDc4MDJkMzE2NzI2YTcyMjEwYWNhYzQ5OGY5NTE2YjU2NmY0MjMxZTllNTMxN2NjODY0OWY1Mzc3ODhkMzQwMThjMDlhNDc3MWUzMjczYTQyM2NlMGUwYzE2MTAxNTU0Zjg2ZDJiMTE0ZWNlMGQ3Nzk4YzVlZjA3YjY5ZjQ0ZGIxZjY5NTU5ZGEzMmJjM2Q4MDg3MDFlZjRkNmY0ZTVmYTE2M2UyNmJiODMxYjgwMGJiMTE4ZDI1ZjYzZTVmNTQxM2ZkZTBkMjU1ZDFhMGNhMjI4YzI1N2MwZmU3MDEzMTdkNTNlZjdmYWE5NmU0ZGIwZjkwMjQyNjc5M2ZkOWFmNzMyYjNkM2Q1ZWU1YzMzYWUwYjAyM2U0NDhlNDE4ZDhmZjA1YTdmNmFiZGE0Mjc3YzE0OWFjMmY3ZmNkYzZkMzZhMDNjNTJkNmU5NWE4MTA5MjlmYjFiYzBkMmNmYmIyMjc4OTM2YTQ3MWRkMmEyM2U4YjczZmE2ZmVkNTc3ZWUyNDE5OGE5YWUwNTMxZGY4MmE0ZDMzMjU0YWI5NDRmNjcxMTNjMmZkMzNlYzE4MzNlNjRmZTRhMmJjZTc1N2RiMzVhOTE5NTU2NWIzMGQ4MjYxZGYyN2VmMWVmZTVjYTYzYzlhYzU1ODRiY2QzYVx1MDAyNlgtR29vZy1TaWduZWRIZWFkZXJzPWhvc3QiLCJzb3VyY2UiOiJPcmRlcnMgU2VydmljZSJ9.66549P4DkJOlQ1SjTljrZMQQyeANoPNdVQRF4OMOiq0atiU9RX7iL7p-Ji2m6AWy7EKfZQm4Hn5F-Mn4-gL19Q", + "name": + "785185e1-8d02-469d-840e-475ec9888a17/composite_metadata.json" + }, + { + "delivery": + "success", + "expires_at": + "2023-07-12T22:58:47.883Z", + "location": + "https://api.planet.com/compute/ops/download/?token=eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2ODkyMDI3MjcsInN1YiI6IkhvejBKZTZDWm5jd1FFcVFpMWpadzdGREV3UzNoeE94Q1AyT0syUGxsZUV1cGZ3RXNmMFZwWjNobHV2R3ZWdkdsOXc1T2RpR25jRWNRN1NnZ29jWDZBPT0iLCJ0b2tlbl90eXBlIjoiZG93bmxvYWQtYXNzZXQtc3RhY2siLCJhb2kiOiIiLCJhc3NldHMiOlt7Iml0ZW1fdHlwZSI6IiIsImFzc2V0X3R5cGUiOiIiLCJpdGVtX2lkIjoiIn1dLCJ1cmwiOiJodHRwczovL3N0b3JhZ2UuZ29vZ2xlYXBpcy5jb20vY29tcHV0ZS1vcmRlcnMtbGl2ZS83ODUxODVlMS04ZDAyLTQ2OWQtODQwZS00NzVlYzk4ODhhMTcvMjAyMzA2MDNfMTgwMzI2XzU4XzI0YzVfbWV0YWRhdGEuanNvbj9YLUdvb2ctQWxnb3JpdGhtPUdPT0c0LVJTQS1TSEEyNTZcdTAwMjZYLUdvb2ctQ3JlZGVudGlhbD1jb21wdXRlLWdjcy1zdmNhY2MlNDBwbGFuZXQtY29tcHV0ZS1wcm9kLmlhbS5nc2VydmljZWFjY291bnQuY29tJTJGMjAyMzA3MTElMkZhdXRvJTJGc3RvcmFnZSUyRmdvb2c0X3JlcXVlc3RcdTAwMjZYLUdvb2ctRGF0ZT0yMDIzMDcxMVQyMjU4NDdaXHUwMDI2WC1Hb29nLUV4cGlyZXM9ODYzOTlcdTAwMjZYLUdvb2ctU2lnbmF0dXJlPTg0M2Q0NzlmNjc4OGMyYTJhZjM4ODYyZDc3MzE2NDhhNGIzODliNjI3YWQzZWU0ZGQxM2I5YzlmZjhmMzI0N2UwYmIyNmEzMDYwMzdkNzk0MDBjNzdlOGYxZGVmMzgzOTkzYjQ1ZGQwNzU0OTU0ZmYxMTg3ZTdkOWFhOTRhYzczY2YyZjZlZTk4YTZiMzc1YTk0MDU4NGE3YzdmNDY2YzE3MDhmMmQ5ZGY1YjgyY2ZiNmYyYzQ5N2ZhNDUyNzVmYmFlYmE0OWU0NjNhNWQ0ODRhZjYyYzZhMjJjNjE1YTQ4OTA3YTI4NjliMDdiYjE4NWY5NzUxODZhZThiMzBkMDg4ZjNmMjkxODViNjI0YzFiYzFiNDBhZWQxZDE0NmMwYmVlYWZiY2MyYWZjMzNlZDE3ZGRlNTJiNWVhYzMyZGRlYzcxNmIwY2IyYWY3OGRjZDRhYjNjZDM4YWIzYjU5ODM2MTcyYTVkZTcxNTExYjVlMGJkYTBiNjA4MTU3OTgzYmRjNGU1M2E1ODM4ODg0ZDM1MTZlYThlZWVjZWY4NDUzNjkzMWVmODZhMWU4NjYzZDU2NmM3OWYzZGNkN2FlYTQ5NmQ0OGY4YjFmZGZhNjFkNGViZGJmYTQ0NDU3NWRkZDlmOTQ1YmIyMzNlZjk1NDkxMDhiZTA3MWZkZmRjMDI1XHUwMDI2WC1Hb29nLVNpZ25lZEhlYWRlcnM9aG9zdCIsInNvdXJjZSI6Ik9yZGVycyBTZXJ2aWNlIn0.xhUXOMazIqybHKfI-Fyx6PshfwpzZGGheVuwyc38NmM8yKMVIOwF0vQ1_iCH920sBYuhWmF-_wlsfL5AnqJ-dA", + "name": + "785185e1-8d02-469d-840e-475ec9888a17/20230603_180326_58_24c5_metadata.json" + }, + { + "delivery": + "success", + "expires_at": + "2023-07-12T22:58:47.871Z", + "location": + "https://api.planet.com/compute/ops/download/?token=eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2ODkyMDI3MjcsInN1YiI6IkJTNTZOcCt4Z3JHek12U2FoU0N0Q0QrWnQ1Q2VySUVTVnY2YXFoQm1PNmRucFpPRlcrNWVvMEFZZldVQmlHVzI1OUdBV3U3SEp5Znhtb05yRWVVUW9nPT0iLCJ0b2tlbl90eXBlIjoiZG93bmxvYWQtYXNzZXQtc3RhY2siLCJhb2kiOiIiLCJhc3NldHMiOlt7Iml0ZW1fdHlwZSI6IiIsImFzc2V0X3R5cGUiOiIiLCJpdGVtX2lkIjoiIn1dLCJ1cmwiOiJodHRwczovL3N0b3JhZ2UuZ29vZ2xlYXBpcy5jb20vY29tcHV0ZS1vcmRlcnMtbGl2ZS83ODUxODVlMS04ZDAyLTQ2OWQtODQwZS00NzVlYzk4ODhhMTcvMjAyMzA2MDNfMTgwMzI4XzkxXzI0YzVfbWV0YWRhdGEuanNvbj9YLUdvb2ctQWxnb3JpdGhtPUdPT0c0LVJTQS1TSEEyNTZcdTAwMjZYLUdvb2ctQ3JlZGVudGlhbD1jb21wdXRlLWdjcy1zdmNhY2MlNDBwbGFuZXQtY29tcHV0ZS1wcm9kLmlhbS5nc2VydmljZWFjY291bnQuY29tJTJGMjAyMzA3MTElMkZhdXRvJTJGc3RvcmFnZSUyRmdvb2c0X3JlcXVlc3RcdTAwMjZYLUdvb2ctRGF0ZT0yMDIzMDcxMVQyMjU4NDdaXHUwMDI2WC1Hb29nLUV4cGlyZXM9ODYzOTlcdTAwMjZYLUdvb2ctU2lnbmF0dXJlPTJiYzI2ODZkYjVmY2ZkZTUxNzRkNzVlY2M2N2RhOTExMmRmMzkzNDI5NmVjNTM4ODg3YTUwZDRjZWNmNGQ5NDJkMWE2MTIxMzllNGU1ZWZmMTRjYzk4NWNmZDk0MzczZjhiY2YyYTRmM2RhMzdkYzBmNzdkY2M5MjQ2MTZlZmIyMDc2ZGUxNjVlM2JhZDE1MTUxMDNkNjM1OGRhZDY4M2M5MDBiMmM4NzRjYmNhYTAyN2Y2MmMzOWQ0Y2Y0ZTBlOTZjNTdhOGY4M2RhN2JmMjhiZTNmNzc2ZWNhMzcxZWYwYjQyMTYyOGJhNDIxMGExZTg5Zjk2YTI3ZTUxNWNkNzJiMmYxM2MyMGU3NWE5MWRjZjlkNDVhMjM0NjhjNzAzY2Q1NzdjZjJiZTc3ZTNmOWVlMDkyY2RiY2FjOTMxYzRmZjlhODFmMDczOWYwNDQ2YzMyMWNjMDBiYzY2NDc4MzE5Zjg5YWJhNTg0ZDI2NjMwZWVlMGFjYTA4YmY2NzA1MmQ0MDFhYzdlMzA5Njc3ZjE0YWYzYzk3YTA1NjMzMDdlYjhjOGIxZGM3Njc3NTFjMWQ5M2MwOGQ5NzFmNWFlZjFkMDZiNjNkZjIxOTc3MmQ3NWQ2ZGZkNmRiNjJlYTMxZjA5MjQ4YzEwNWRlNWVhODhiNzExYThmM2U4NWRkMGM0XHUwMDI2WC1Hb29nLVNpZ25lZEhlYWRlcnM9aG9zdCIsInNvdXJjZSI6Ik9yZGVycyBTZXJ2aWNlIn0.rAjq4q87lEfqp0qzMdW668yYRqrqI8bNRLkKMsDr851-c9xWdcB0BQ89M8ythVIpxJKAlhjnseRo_C1bK6tfnA", + "name": + "785185e1-8d02-469d-840e-475ec9888a17/20230603_180328_91_24c5_metadata.json" + }, + { + "delivery": "success", + "expires_at": "2023-07-12T22:58:47.874Z", + "location": + "https://api.planet.com/compute/ops/download/?token=eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2ODkyMDI3MjcsInN1YiI6IisvMktSQXBuM0tiWjY4dDh1cEx5c2hvTzB1VlhPZ2UwamNNZFA0Mnc4V3JEaUN0azZjaDBXakIrTkVwdUZGdzAxWFpKZnNqQ1BjcUtudGF2YnFZc0R3PT0iLCJ0b2tlbl90eXBlIjoiZG93bmxvYWQtYXNzZXQtc3RhY2siLCJhb2kiOiIiLCJhc3NldHMiOlt7Iml0ZW1fdHlwZSI6IiIsImFzc2V0X3R5cGUiOiIiLCJpdGVtX2lkIjoiIn1dLCJ1cmwiOiJodHRwczovL3N0b3JhZ2UuZ29vZ2xlYXBpcy5jb20vY29tcHV0ZS1vcmRlcnMtbGl2ZS83ODUxODVlMS04ZDAyLTQ2OWQtODQwZS00NzVlYzk4ODhhMTcvbWFuaWZlc3QuanNvbj9YLUdvb2ctQWxnb3JpdGhtPUdPT0c0LVJTQS1TSEEyNTZcdTAwMjZYLUdvb2ctQ3JlZGVudGlhbD1jb21wdXRlLWdjcy1zdmNhY2MlNDBwbGFuZXQtY29tcHV0ZS1wcm9kLmlhbS5nc2VydmljZWFjY291bnQuY29tJTJGMjAyMzA3MTElMkZhdXRvJTJGc3RvcmFnZSUyRmdvb2c0X3JlcXVlc3RcdTAwMjZYLUdvb2ctRGF0ZT0yMDIzMDcxMVQyMjU4NDdaXHUwMDI2WC1Hb29nLUV4cGlyZXM9ODYzOTlcdTAwMjZYLUdvb2ctU2lnbmF0dXJlPTc3NDUzYjFlYzAxMTVhMWQyODEzNWM0ZGRjZGVjOWE3ZmJjMDM0N2YwZTAzMDFkMWM4ZTgyNmVlMzA1YzUxMmRkNjBiMTMyMmZiOTE2ZmI2MzM3ZWJjZjFiYTBiNzkzNzY5MTRkNjI1ODEyYjE3YmYwNzljOTM4NTcxOTQ1YmRkNmVkMzZiMDVkOGMzMzk1NDgxZTliNDY1MDg3NmJjMzQwM2Y0Y2EwZDgxYTkxYjQwYjQxZDI1ODBmYmRjZDgyNmEyZTU2Y2ZiNWQ0ZGU4NDg0MmE3N2FjMzI4MThkYzA5MjQ3ZDc3YjU4MDg5ZjU2Y2MxNmNjMDQxOTc5NzYzZjQ5ZDU0YTY5MDgwZTEzZTM3ZWY5ZWU5NmU5NTIzMThmMDI2YjIwOWY2YTI5M2UyOGIxNDAyYTk4YmJmMzZiZDQxZmM1NjI0OWI1ODFjZjVkM2ZlZjJlMzYxOGMxYjY0NTVhOTJlZmJlODMyOWYyMGI4OGFmNmU3Y2YyYmM5NTRhNmQyZmNiNzg1NDY3ZGFlM2QwNDM4ZjQ0YTQzYzg3MmRiOWU0NWIzM2ZhMWUzZGZjMWVlNWNmZTE5ODk0ODJiYjNmNzQxMDhkNzlhZmFlMGZiNDIyNDVkYWM0MjJjNWRhZDg1MGVmODkxYmFiNGNjZTk3YTEzOTZkNDM3M2RiZDY0XHUwMDI2WC1Hb29nLVNpZ25lZEhlYWRlcnM9aG9zdCIsInNvdXJjZSI6Ik9yZGVycyBTZXJ2aWNlIn0.yc1ZrJeMuaqmsCJiSOhe14h1DJi5eB6SKPnMcN_kFTEPVg2lJCaMZE0cX9I8aL9LrWAcPgO_1Ui6aEAROPUl3A", + "name": "785185e1-8d02-469d-840e-475ec9888a17/manifest.json" + }] + }, + "created_on": + "2023-06-15T19:32:42.945Z", + "error_hints": [], + "id": + "785185e1-8d02-469d-840e-475ec9888a17", + "last_message": + "Manifest delivery completed", + "last_modified": + "2023-06-15T19:38:13.677Z", + "name": + "Composite CA Strip Visual Short", + "products": [{ + "item_ids": ["20230603_180326_58_24c5", "20230603_180328_91_24c5"], + "item_type": + "PSScene", + "product_bundle": + "visual" + }], + "state": + "success", + "tools": [{ + "composite": {} + }] + } + return order_details + + @pytest.mark.anyio async def test_snippet_orders_create_order(): '''Code snippet for create_order.''' @@ -135,17 +215,16 @@ async def test_snippet_orders_aggregated_order_stats(): @pytest.mark.anyio async def test_snippet_orders_download_asset(): '''Code snippet for download_asset.''' - # order = await test_snippet_orders_create_order() - # order_id = order['id'] - order_id = "decde86f-a57a-45bd-89f9-2af49a661e25" + order = create_succesful_order() + order_id = order['id'] # --8<-- [start:download_asset] async with planet.Session() as sess: client = sess.client('orders') order = await client.get_order(order_id=order_id) - # Find order info info = order['_links']['results'] - # Find and download the the composite.tif file + # Find and download the data for i in info: + # This works to download spesifically a composite.tif if 'composite.tif' in i['name']: location = i['location'] filename = await client.download_asset(location=location) @@ -159,7 +238,8 @@ async def test_snippet_orders_download_asset(): @pytest.mark.anyio async def test_snippet_orders_download_order_without_checksum(): '''Code snippet for download_order without checksum.''' - order_id = "decde86f-a57a-45bd-89f9-2af49a661e25" + order = create_succesful_order() + order_id = order['id'] # --8<-- [start:download_order_without_checksum] async with planet.Session() as sess: client = sess.client('orders') @@ -172,7 +252,8 @@ async def test_snippet_orders_download_order_without_checksum(): @pytest.mark.anyio async def test_snippet_orders_download_order_with_checksum(): '''Code snippet for download_order with checksum.''' - order_id = "decde86f-a57a-45bd-89f9-2af49a661e25" + order = create_succesful_order() + order_id = order['id'] # --8<-- [start:download_order_without_checksum] async with planet.Session() as sess: client = sess.client('orders') @@ -186,12 +267,14 @@ async def test_snippet_orders_download_order_with_checksum(): @pytest.mark.anyio async def test_snippet_orders_wait(): '''Code snippet for wait.''' - order_id = "decde86f-a57a-45bd-89f9-2af49a661e25" + order = create_succesful_order() + order_id = order['id'] # --8<-- [start:wait] async with planet.Session() as sess: client = sess.client('orders') state = await client.wait(order_id=order_id) - # --8<-- [end:wait] + + # --8<-- [end:wait] assert state == 'success'