Skip to content

Commit a314d93

Browse files
authored
Merge pull request #1043 from planetlabs/orders-hosting
Add hosting parameter support for Orders API
2 parents 162cc04 + ef53d61 commit a314d93

File tree

8 files changed

+177
-40
lines changed

8 files changed

+177
-40
lines changed

docs/cli/cli-orders.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,26 @@ planet orders request \
176176

177177
*New in version 2.1*
178178

179+
#### Sentinel Hub Hosting
180+
181+
You can deliver your orders directly to Sentinel Hub using the hosting options.
182+
183+
```
184+
planet orders request \
185+
--item-type PSScene \
186+
--bundle analytic_sr_udm2 \
187+
--name 'My First Order' \
188+
20220605_124027_64_242b \
189+
--hosting sentinel_hub \
190+
--collection_id ba8f7274-aacc-425e-8a38-e21517bfbeff
191+
```
192+
193+
- The --hosting option is optional and currently supports sentinel_hub as its only value.
194+
- The --collection_id is also optional. If you decide to use this, ensure that the order request and the collection have matching bands. If you're unsure, allow the system to create a new collection for you by omitting the --collection_id option. This will ensure the newly set-up collection is configured correctly, and you can subsequently add items to this collection as needed.
195+
196+
For more information on Sentinel Hub hosting, see the [Orders API documentation](https://developers.planet.com/apis/orders/delivery/#delivery-to-sentinel-hub-collection) and the [Linking Planet User to Sentinel Hub User
197+
](https://support.planet.com/hc/en-us/articles/16550358397469-Linking-Planet-User-to-Sentinel-Hub-User) support post.
198+
179199
### Save an Order Request
180200

181201
The above command just prints out the necessary JSON to create an order. To actually use it you can
@@ -236,6 +256,16 @@ Note the default output will be a bit more 'flat' - if you'd like the above form
236256
command-line just use `jq` as above: `planet orders create request-1.json | jq` (but remember
237257
if you run that command again it will create a second order).
238258

259+
#### Sentinel Hub Hosting
260+
261+
For convenience, `planet orders create` accepts the same `--hosting` and `--collection_id` options that [`planet orders request`](#sentinel-hub-hosting) does.
262+
263+
```sh
264+
planet orders create request-1.json \
265+
--hosting sentinel_hub \
266+
--collection_id ba8f7274-aacc-425e-8a38-e21517bfbeff
267+
```
268+
239269
### Create Request and Order in One Call
240270

241271
Using a unix command called a 'pipe', which looks like `|`, you can skip the step of saving to disk,

docs/cli/cli-subscriptions.md

Lines changed: 15 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -120,17 +120,6 @@ planet subscriptions create my-subscription.json
120120
!!!note "Note"
121121
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.
122122

123-
#### Create a Subscription with Hosting and Collection ID
124-
125-
In addition to the basic subscription creation process, you can now specify hosting options and a collection ID directly in the create command.
126-
127-
```sh
128-
planet subscriptions create my-subscription.json --hosting sentinel_hub --collection_id ba8f7274-aacc-425e-8a38-e21517bfbeff
129-
```
130-
131-
- The --hosting option is optional and currently supports sentinel_hub as its only value.
132-
- The --collection_id is also optional. If you decide to use this, ensure that the subscription request and the collection have matching bands. If you're unsure, allow the system to create a new collection for you by omitting the --collection_id option. This will ensure the newly set-up collection is configured correctly, and you can subsequently add items to this collection as needed.
133-
134123
### List Subscriptions
135124

136125
Now that you’ve got a subscription working you can make use of the other commands.
@@ -487,42 +476,36 @@ The main documentation page also has the parameters for Google Cloud, AWS and Or
487476

488477
### Subscriptions Request
489478

490-
When creating a new subscription, you can include hosting options directly using the --hosting and --collection-id flags.
491-
492-
- The --hosting option is optional and currently supports sentinel_hub as its only value.
493-
- The --collection_id is also optional. If you decide to use this, ensure that the subscription request and the collection have matching bands. If you're unsure, allow the system to create a new collection for you by omitting the --collection_id option. This will ensure the newly set-up collection is configured correctly, and you can subsequently add items to this collection as needed.
494-
- You may also input --hosting as a JSON file. The file should be formatted:
495-
496-
```json
497-
"hosting": {
498-
"parameters": {
499-
"collection_id": "4bdef85c-3f50-4006-a713-2350da665f80"
500-
},
501-
"type": "sentinel_hub"
502-
},
503-
```
504-
505479
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:
506480

481+
The above will print it nicely out so you can see the full request. You can write it out
482+
as a file, or pipe it directly into `subscriptions create` or `subscriptions update`:
483+
507484
```sh
508485
planet subscriptions request \
509486
--name 'First Subscription' \
510487
--source request-catalog.json \
511488
--tools tools.json \
512489
--delivery cloud-delivery.json \
513-
--hosting sentinel_hub \
514-
-- collection_id 4bdef85c-3f50-4006-a713-2350da665f80 \
515-
--pretty
490+
| planet subscriptions create -
516491
```
517492

518-
The above will print it nicely out so you can see the full request. You can write it out
519-
as a file, or pipe it directly into `subscriptions create` or `subscriptions update`:
493+
#### Sentinel Hub Hosting
494+
495+
When creating a new subscription, you can include hosting options directly using the --hosting and --collection-id flags.
496+
497+
- The --hosting option is optional and currently supports sentinel_hub as its only value.
498+
- The --collection_id is also optional. If you decide to use this, ensure that the subscription request and the collection have matching bands. If you're unsure, allow the system to create a new collection for you by omitting the --collection_id option. This will ensure the newly set-up collection is configured correctly, and you can subsequently add items to this collection as needed.
499+
- You may also input --hosting as a JSON file. The file should be formatted:
520500

521501
```sh
522502
planet subscriptions request \
523503
--name 'First Subscription' \
524504
--source request-catalog.json \
525505
--tools tools.json \
526-
--delivery cloud-delivery.json \
506+
--hosting sentinel_hub \
527507
| planet subscriptions create -
528508
```
509+
510+
For more information on Sentinel Hub hosting, see the [Subscriptions API documentation](https://developers.planet.com/docs/subscriptions/delivery/#delivery-to-sentinel-hub-collection) and the [Linking Planet User to Sentinel Hub User
511+
](https://support.planet.com/hc/en-us/articles/16550358397469-Linking-Planet-User-to-Sentinel-Hub-User) support post.

planet/cli/orders.py

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from planet import OrdersClient # allow mocking
2323
from . import types
2424
from .cmds import coro, translate_exceptions
25+
from ..order_request import sentinel_hub
2526
from .io import echo_json
2627
from .options import limit, pretty
2728
from .session import CliSession
@@ -205,16 +206,40 @@ async def download(ctx, order_id, overwrite, directory, checksum):
205206
@translate_exceptions
206207
@coro
207208
@click.argument("request", type=types.JSON())
209+
@click.option(
210+
"--hosting",
211+
type=click.Choice([
212+
"sentinel_hub",
213+
]),
214+
default=None,
215+
help='Hosting type. Currently, only "sentinel_hub" is supported.',
216+
)
217+
@click.option("--collection-id",
218+
default=None,
219+
help='Collection ID for Sentinel Hub hosting. '
220+
'If omitted, a new collection will be created.')
208221
@pretty
209-
async def create(ctx, request: str, pretty):
222+
async def create(ctx, request, pretty, **kwargs):
210223
"""Create an order.
211224
212225
This command outputs the created order description, optionally
213226
pretty-printed.
214227
215228
REQUEST is the full description of the order to be created. It must be JSON
216229
and can be specified a json string, filename, or '-' for stdin.
230+
231+
Other flag options are hosting and collection_id. The hosting flag
232+
specifies the hosting type, and the collection_id flag specifies the
233+
collection ID for Sentinel Hub. If the collection_id is omitted, a new
234+
collection will be created.
217235
"""
236+
237+
hosting = kwargs.get('hosting')
238+
collection_id = kwargs.get('collection_id')
239+
240+
if hosting == "sentinel_hub":
241+
request["hosting"] = sentinel_hub(collection_id)
242+
218243
async with orders_client(ctx) as cl:
219244
order = await cl.create_order(request)
220245

@@ -281,6 +306,13 @@ async def create(ctx, request: str, pretty):
281306
help="""Include or exclude metadata in SpatioTemporal Asset Catalog (STAC)
282307
format. Not specifying either defaults to including it (--stac), except
283308
for orders with google_earth_engine delivery""")
309+
@click.option('--hosting',
310+
type=click.Choice(['sentinel_hub']),
311+
help='Hosting for data delivery. '
312+
'Currently, only "sentinel_hub" is supported.')
313+
@click.option('--collection_id',
314+
help='Collection ID for Sentinel Hub hosting. '
315+
'If omitted, a new collection will be created.')
284316
@pretty
285317
async def request(ctx,
286318
item_type,
@@ -295,6 +327,8 @@ async def request(ctx,
295327
single_archive,
296328
delivery,
297329
stac,
330+
hosting,
331+
collection_id,
298332
pretty):
299333
"""Generate an order request.
300334
@@ -337,6 +371,8 @@ async def request(ctx,
337371
delivery=delivery,
338372
notifications=notifications,
339373
tools=tools,
340-
stac=stac_json)
374+
stac=stac_json,
375+
hosting=hosting,
376+
collection_id=collection_id)
341377

342378
echo_json(request, pretty)

planet/cli/subscriptions.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ async def list_subscriptions_cmd(ctx, status, limit, pretty):
101101
)
102102
@click.option("--collection-id",
103103
default=None,
104-
help='Collection ID for Sentinel Hub.'
104+
help='Collection ID for Sentinel Hub hosting. '
105105
'If omitted, a new collection will be created.')
106106
@pretty
107107
@click.pass_context
@@ -302,7 +302,7 @@ async def list_subscription_results_cmd(ctx,
302302
help="Clip to the source geometry without specifying a clip tool.")
303303
@click.option("--collection-id",
304304
default=None,
305-
help='Collection ID for Sentinel Hub.'
305+
help='Collection ID for Sentinel Hub hosting. '
306306
'If omitted, a new collection will be created.')
307307
@pretty
308308
def request(name,

planet/order_request.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ def build_request(name: str,
3030
notifications: Optional[dict] = None,
3131
order_type: Optional[str] = None,
3232
tools: Optional[List[dict]] = None,
33-
stac: Optional[dict] = None) -> dict:
33+
stac: Optional[dict] = None,
34+
hosting: Optional[str] = None,
35+
collection_id: Optional[str] = None) -> dict:
3436
"""Prepare an order request.
3537
3638
```python
@@ -65,6 +67,9 @@ def build_request(name: str,
6567
order_type: Accept a partial order, indicated by 'partial'.
6668
tools: Tools to apply to the products. Order defines
6769
the toolchain order of operatations.
70+
stac: Include STAC metadata.
71+
hosting: A hosting destination (e.g. Sentinel Hub).
72+
collection_id: A Sentinel Hub collection ID.
6873
6974
Raises:
7075
planet.specs.SpecificationException: If order_type is not a valid
@@ -91,6 +96,9 @@ def build_request(name: str,
9196
if stac:
9297
details['metadata'] = stac
9398

99+
if hosting == 'sentinel_hub':
100+
details['hosting'] = sentinel_hub(collection_id)
101+
94102
return details
95103

96104

@@ -534,3 +542,11 @@ def band_math_tool(b1: str,
534542
# e.g. {"b1": "b1", "b2":"arctan(b1)"} if b1 and b2 are specified
535543
parameters = dict((k, v) for k, v in locals().items() if v)
536544
return _tool('bandmath', parameters)
545+
546+
547+
def sentinel_hub(collection_id: Optional[str] = None) -> dict:
548+
"""Specify a Sentinel Hub hosting destination."""
549+
params = {}
550+
if collection_id:
551+
params['collection_id'] = collection_id
552+
return {'sentinel_hub': params}

planet/subscription_request.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,8 @@ def build_request(name: str,
8686
ClientError: when a valid Subscriptions API request can't be
8787
constructed.
8888
89-
Examples:
89+
Example::
9090
91-
```python
9291
from datetime import datetime
9392
from planet.subscription_request import build_request, catalog_source, amazon_s3
9493
@@ -114,7 +113,6 @@ def build_request(name: str,
114113
subscription_request = build_request(
115114
"test_subscription", source=source, delivery=delivery, hosting=hosting
116115
)
117-
```
118116
"""
119117
# Because source is a Mapping we must make copies for
120118
# the function's return value. dict() shallow copies a Mapping

tests/integration/test_orders_cli.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -768,3 +768,65 @@ def test_cli_orders_request_no_stac(invoke):
768768
}]
769769
}
770770
assert order_request == json.loads(result.output)
771+
772+
773+
@respx.mock
774+
def test_cli_orders_request_hosting_sentinel_hub(invoke, stac_json):
775+
776+
result = invoke([
777+
'request',
778+
'--item-type=PSScene',
779+
'--bundle=visual',
780+
'--name=test',
781+
'20220325_131639_20_2402',
782+
'--hosting=sentinel_hub',
783+
])
784+
785+
order_request = {
786+
"name":
787+
"test",
788+
"products": [{
789+
"item_ids": ["20220325_131639_20_2402"],
790+
"item_type": "PSScene",
791+
"product_bundle": "visual",
792+
}],
793+
"metadata":
794+
stac_json,
795+
"hosting": {
796+
"sentinel_hub": {}
797+
}
798+
}
799+
assert order_request == json.loads(result.output)
800+
801+
802+
@respx.mock
803+
def test_cli_orders_request_hosting_sentinel_hub_collection_id(
804+
invoke, stac_json):
805+
806+
result = invoke([
807+
'request',
808+
'--item-type=PSScene',
809+
'--bundle=visual',
810+
'--name=test',
811+
'20220325_131639_20_2402',
812+
'--hosting=sentinel_hub',
813+
'--collection_id=1234'
814+
])
815+
816+
order_request = {
817+
"name":
818+
"test",
819+
"products": [{
820+
"item_ids": ["20220325_131639_20_2402"],
821+
"item_type": "PSScene",
822+
"product_bundle": "visual",
823+
}],
824+
"metadata":
825+
stac_json,
826+
"hosting": {
827+
"sentinel_hub": {
828+
"collection_id": "1234"
829+
}
830+
}
831+
}
832+
assert order_request == json.loads(result.output)

tests/unit/test_order_request.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,3 +329,15 @@ def test_no_archive_items_without_type():
329329
assert "archive_type" not in delivery_config
330330
assert "archive_filename" not in delivery_config
331331
assert "single_archive" not in delivery_config
332+
333+
334+
def test_sentinel_hub():
335+
sh_config = order_request.sentinel_hub()
336+
expected = {'sentinel_hub': {}}
337+
assert sh_config == expected
338+
339+
340+
def test_sentinel_hub_collection_id():
341+
sh_config = order_request.sentinel_hub("1234")
342+
expected = {'sentinel_hub': {'collection_id': "1234"}}
343+
assert sh_config == expected

0 commit comments

Comments
 (0)