Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add hosting parameter support for Orders API #1043

Merged
merged 6 commits into from
Jun 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions docs/cli/cli-orders.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,26 @@ planet orders request \

*New in version 2.1*

#### Sentinel Hub Hosting

You can deliver your orders directly to Sentinel Hub using the hosting options.

```
planet orders request \
--item-type PSScene \
--bundle analytic_sr_udm2 \
--name 'My First Order' \
20220605_124027_64_242b \
--hosting sentinel_hub \
--collection_id ba8f7274-aacc-425e-8a38-e21517bfbeff
```

- The --hosting option is optional and currently supports sentinel_hub as its only value.
- 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.

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
](https://support.planet.com/hc/en-us/articles/16550358397469-Linking-Planet-User-to-Sentinel-Hub-User) support post.

### Save an Order Request

The above command just prints out the necessary JSON to create an order. To actually use it you can
Expand Down Expand Up @@ -236,6 +256,16 @@ Note the default output will be a bit more 'flat' - if you'd like the above form
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).

#### Sentinel Hub Hosting

For convenience, `planet orders create` accepts the same `--hosting` and `--collection_id` options that [`planet orders request`](#sentinel-hub-hosting) does.

```sh
planet orders create request-1.json \
--hosting sentinel_hub \
--collection_id ba8f7274-aacc-425e-8a38-e21517bfbeff
```

### 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,
Expand Down
47 changes: 15 additions & 32 deletions docs/cli/cli-subscriptions.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,17 +120,6 @@ 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.

#### Create a Subscription with Hosting and Collection ID

In addition to the basic subscription creation process, you can now specify hosting options and a collection ID directly in the create command.

```sh
planet subscriptions create my-subscription.json --hosting sentinel_hub --collection_id ba8f7274-aacc-425e-8a38-e21517bfbeff
```

- The --hosting option is optional and currently supports sentinel_hub as its only value.
- 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.

### List Subscriptions

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

### Subscriptions Request

When creating a new subscription, you can include hosting options directly using the --hosting and --collection-id flags.

- The --hosting option is optional and currently supports sentinel_hub as its only value.
- 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.
- You may also input --hosting as a JSON file. The file should be formatted:

```json
"hosting": {
"parameters": {
"collection_id": "4bdef85c-3f50-4006-a713-2350da665f80"
},
"type": "sentinel_hub"
},
```

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:

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 \
--hosting sentinel_hub \
-- collection_id 4bdef85c-3f50-4006-a713-2350da665f80 \
--pretty
| planet subscriptions create -
```

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`:
#### Sentinel Hub Hosting

When creating a new subscription, you can include hosting options directly using the --hosting and --collection-id flags.

- The --hosting option is optional and currently supports sentinel_hub as its only value.
- 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.
- You may also input --hosting as a JSON file. The file should be formatted:

```sh
planet subscriptions request \
--name 'First Subscription' \
--source request-catalog.json \
--tools tools.json \
--delivery cloud-delivery.json \
--hosting sentinel_hub \
| planet subscriptions create -
```

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
](https://support.planet.com/hc/en-us/articles/16550358397469-Linking-Planet-User-to-Sentinel-Hub-User) support post.
40 changes: 38 additions & 2 deletions planet/cli/orders.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from planet import OrdersClient # allow mocking
from . import types
from .cmds import coro, translate_exceptions
from ..order_request import sentinel_hub
from .io import echo_json
from .options import limit, pretty
from .session import CliSession
Expand Down Expand Up @@ -205,16 +206,40 @@ async def download(ctx, order_id, overwrite, directory, checksum):
@translate_exceptions
@coro
@click.argument("request", type=types.JSON())
@click.option(
"--hosting",
type=click.Choice([
"sentinel_hub",
]),
default=None,
help='Hosting type. Currently, only "sentinel_hub" is supported.',
)
@click.option("--collection-id",
default=None,
help='Collection ID for Sentinel Hub hosting. '
'If omitted, a new collection will be created.')
@pretty
async def create(ctx, request: str, pretty):
async def create(ctx, request, pretty, **kwargs):
"""Create an order.

This command outputs the created order description, optionally
pretty-printed.

REQUEST is the full description of the order to be created. It must be JSON
and can be specified a json string, filename, or '-' for stdin.

Other flag options are hosting and collection_id. The hosting flag
specifies the hosting type, and the collection_id flag specifies the
collection ID for Sentinel Hub. If the collection_id is omitted, a new
collection will be created.
"""

hosting = kwargs.get('hosting')
collection_id = kwargs.get('collection_id')

if hosting == "sentinel_hub":
request["hosting"] = sentinel_hub(collection_id)

async with orders_client(ctx) as cl:
order = await cl.create_order(request)

Expand Down Expand Up @@ -281,6 +306,13 @@ async def create(ctx, request: str, pretty):
help="""Include or exclude metadata in SpatioTemporal Asset Catalog (STAC)
format. Not specifying either defaults to including it (--stac), except
for orders with google_earth_engine delivery""")
@click.option('--hosting',
type=click.Choice(['sentinel_hub']),
help='Hosting for data delivery. '
'Currently, only "sentinel_hub" is supported.')
@click.option('--collection_id',
help='Collection ID for Sentinel Hub hosting. '
'If omitted, a new collection will be created.')
@pretty
async def request(ctx,
item_type,
Expand All @@ -295,6 +327,8 @@ async def request(ctx,
single_archive,
delivery,
stac,
hosting,
collection_id,
pretty):
"""Generate an order request.

Expand Down Expand Up @@ -337,6 +371,8 @@ async def request(ctx,
delivery=delivery,
notifications=notifications,
tools=tools,
stac=stac_json)
stac=stac_json,
hosting=hosting,
collection_id=collection_id)

echo_json(request, pretty)
4 changes: 2 additions & 2 deletions planet/cli/subscriptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ async def list_subscriptions_cmd(ctx, status, limit, pretty):
)
@click.option("--collection-id",
default=None,
help='Collection ID for Sentinel Hub.'
help='Collection ID for Sentinel Hub hosting. '
pl-gideon marked this conversation as resolved.
Show resolved Hide resolved
'If omitted, a new collection will be created.')
@pretty
@click.pass_context
Expand Down Expand Up @@ -302,7 +302,7 @@ async def list_subscription_results_cmd(ctx,
help="Clip to the source geometry without specifying a clip tool.")
@click.option("--collection-id",
default=None,
help='Collection ID for Sentinel Hub.'
help='Collection ID for Sentinel Hub hosting. '
'If omitted, a new collection will be created.')
@pretty
def request(name,
Expand Down
18 changes: 17 additions & 1 deletion planet/order_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ def build_request(name: str,
notifications: Optional[dict] = None,
order_type: Optional[str] = None,
tools: Optional[List[dict]] = None,
stac: Optional[dict] = None) -> dict:
stac: Optional[dict] = None,
hosting: Optional[str] = None,
collection_id: Optional[str] = None) -> dict:
"""Prepare an order request.

```python
Expand Down Expand Up @@ -65,6 +67,9 @@ def build_request(name: str,
order_type: Accept a partial order, indicated by 'partial'.
tools: Tools to apply to the products. Order defines
the toolchain order of operatations.
stac: Include STAC metadata.
hosting: A hosting destination (e.g. Sentinel Hub).
collection_id: A Sentinel Hub collection ID.

Raises:
planet.specs.SpecificationException: If order_type is not a valid
Expand All @@ -91,6 +96,9 @@ def build_request(name: str,
if stac:
details['metadata'] = stac

if hosting == 'sentinel_hub':
details['hosting'] = sentinel_hub(collection_id)

return details


Expand Down Expand Up @@ -534,3 +542,11 @@ def band_math_tool(b1: str,
# e.g. {"b1": "b1", "b2":"arctan(b1)"} if b1 and b2 are specified
parameters = dict((k, v) for k, v in locals().items() if v)
return _tool('bandmath', parameters)


def sentinel_hub(collection_id: Optional[str] = None) -> dict:
"""Specify a Sentinel Hub hosting destination."""
params = {}
if collection_id:
params['collection_id'] = collection_id
return {'sentinel_hub': params}
4 changes: 1 addition & 3 deletions planet/subscription_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,8 @@ def build_request(name: str,
ClientError: when a valid Subscriptions API request can't be
constructed.

Examples:
Example::

```python
from datetime import datetime
from planet.subscription_request import build_request, catalog_source, amazon_s3

Expand All @@ -114,7 +113,6 @@ def build_request(name: str,
subscription_request = build_request(
"test_subscription", source=source, delivery=delivery, hosting=hosting
)
```
"""
# Because source is a Mapping we must make copies for
# the function's return value. dict() shallow copies a Mapping
Expand Down
62 changes: 62 additions & 0 deletions tests/integration/test_orders_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -768,3 +768,65 @@ def test_cli_orders_request_no_stac(invoke):
}]
}
assert order_request == json.loads(result.output)


@respx.mock
def test_cli_orders_request_hosting_sentinel_hub(invoke, stac_json):

result = invoke([
'request',
'--item-type=PSScene',
'--bundle=visual',
'--name=test',
'20220325_131639_20_2402',
'--hosting=sentinel_hub',
])

order_request = {
"name":
"test",
"products": [{
"item_ids": ["20220325_131639_20_2402"],
"item_type": "PSScene",
"product_bundle": "visual",
}],
"metadata":
stac_json,
"hosting": {
"sentinel_hub": {}
}
}
assert order_request == json.loads(result.output)


@respx.mock
def test_cli_orders_request_hosting_sentinel_hub_collection_id(
invoke, stac_json):

result = invoke([
'request',
'--item-type=PSScene',
'--bundle=visual',
'--name=test',
'20220325_131639_20_2402',
'--hosting=sentinel_hub',
'--collection_id=1234'
])

order_request = {
"name":
"test",
"products": [{
"item_ids": ["20220325_131639_20_2402"],
"item_type": "PSScene",
"product_bundle": "visual",
}],
"metadata":
stac_json,
"hosting": {
"sentinel_hub": {
"collection_id": "1234"
}
}
}
assert order_request == json.loads(result.output)
12 changes: 12 additions & 0 deletions tests/unit/test_order_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -329,3 +329,15 @@ def test_no_archive_items_without_type():
assert "archive_type" not in delivery_config
assert "archive_filename" not in delivery_config
assert "single_archive" not in delivery_config


def test_sentinel_hub():
sh_config = order_request.sentinel_hub()
expected = {'sentinel_hub': {}}
assert sh_config == expected


def test_sentinel_hub_collection_id():
sh_config = order_request.sentinel_hub("1234")
expected = {'sentinel_hub': {'collection_id': "1234"}}
assert sh_config == expected
Loading