-
Notifications
You must be signed in to change notification settings - Fork 98
Add a clip_to_source kwarg to subscript_request.build_request #971
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
Changes from all commits
bcd3e86
b928580
e8fa079
2f082ec
37f195c
1ddab42
3308fa6
6019e4b
c93e074
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,7 +13,7 @@ | |
| # the License. | ||
| """Functionality for preparing subscription requests.""" | ||
| from datetime import datetime | ||
| from typing import Any, Dict, Optional, List | ||
| from typing import Any, Dict, Optional, List, Mapping | ||
|
|
||
| from . import geojson, specs | ||
| from .exceptions import ClientError | ||
|
|
@@ -45,13 +45,42 @@ | |
|
|
||
|
|
||
| def build_request(name: str, | ||
| source: dict, | ||
| delivery: dict, | ||
| notifications: Optional[dict] = None, | ||
| tools: Optional[List[dict]] = None) -> dict: | ||
| """Prepare a subscriptions request. | ||
| source: Mapping, | ||
| delivery: Mapping, | ||
| notifications: Optional[Mapping] = None, | ||
| tools: Optional[List[Mapping]] = None, | ||
| clip_to_source=False) -> dict: | ||
| """Construct a Subscriptions API request. | ||
|
|
||
| The return value can be passed to | ||
| [planet.clients.subscriptions.SubscriptionsClient.create_subscription][]. | ||
|
|
||
| Parameters: | ||
| name: Name of the subscription. | ||
| source: A source for the subscription, i.e. catalog. | ||
| delivery: A delivery mechanism e.g. GCS, AWS, Azure, or OCS. | ||
| notifications: Specify notifications via email/webhook. | ||
| tools: Tools to apply to the products. The order of operation | ||
| is determined by the service. | ||
| clip_to_source: whether to clip to the source geometry or not | ||
| (the default). If True a clip configuration will be added to | ||
| the list of requested tools unless an existing clip tool | ||
| exists. NOTE: Not all data layers support clipping, please | ||
| consult the Product reference before using this option. | ||
| NOTE: the next version of the Subscription API will remove | ||
| the clip tool option and always clip to the source geometry. | ||
| Thus this is a preview of the next API version's default | ||
| behavior. | ||
|
|
||
| Returns: | ||
| A Python dict representation of a Subscriptions API request for | ||
| a new subscription. | ||
|
|
||
| Raises: | ||
| ClientError when a valid Subscriptions API request can't be | ||
| constructed. | ||
|
|
||
| Examples: | ||
| ```python | ||
| >>> from datetime import datetime | ||
| >>> from planet.subscription_request import ( | ||
|
|
@@ -72,36 +101,54 @@ def build_request(name: str, | |
| ... ACCESS_KEY_ID, SECRET_ACCESS_KEY, "test", "us-east-1") | ||
| ... | ||
| >>> subscription_request = build_request( | ||
| ... 'test_subscription', source, delivery) | ||
| ... 'test_subscription', source=source, delivery=delivery) | ||
| ... | ||
|
|
||
| ``` | ||
|
|
||
| Parameters: | ||
| name: Name of the subscription. | ||
| source: A source for the subscription, i.e. catalog. | ||
| delivery: A delivery mechanism e.g. GCS, AWS, Azure, or OCS. | ||
| notifications: Specify notifications via email/webhook. | ||
| tools: Tools to apply to the products. Order defines | ||
| the toolchain order of operatations. | ||
| """ | ||
| details = {"name": name, "source": source, "delivery": delivery} | ||
| # Because source and delivery are Mappings we must make copies for | ||
| # the function's return value. dict() shallow copies a Mapping | ||
| # and returns a new dict. | ||
| details = { | ||
| "name": name, "source": dict(source), "delivery": dict(delivery) | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here is the consequence of accepting mappings: we need to explicitly convert them to dicts here. The upside is that we will never modify dicts that users pass in to this function, which can cause subtle bugs.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We copy information now, which has some overhead, but makes calling code more reliable. And building a subscriptions request doesn't need to be super optimized. |
||
| } | ||
|
|
||
| if notifications: | ||
| details['notifications'] = notifications | ||
| details['notifications'] = dict(notifications) | ||
|
|
||
| if tools: | ||
| details['tools'] = tools | ||
| tool_list = [dict(tool) for tool in tools] | ||
|
|
||
| # If clip_to_source is True a clip configuration will be added | ||
| # to the list of requested tools unless an existing clip tool | ||
| # exists. In that case an exception is raised. NOTE: the next | ||
| # version of the Subscription API will remove the clip tool | ||
| # option and always clip to the source geometry. Thus this is a | ||
| # preview of the next API version's default behavior. | ||
| if clip_to_source: | ||
| if any(tool.get('type', None) == 'clip' for tool in tool_list): | ||
| raise ClientError( | ||
| "clip_to_source option conflicts with a configured clip tool." | ||
| ) | ||
| else: | ||
| tool_list.append({ | ||
| 'type': 'clip', | ||
| 'parameters': { | ||
| 'aoi': source['parameters']['geometry'] | ||
| } | ||
| }) | ||
|
|
||
| details['tools'] = tool_list | ||
|
|
||
| return details | ||
|
|
||
|
|
||
| def catalog_source( | ||
| item_types: List[str], | ||
| asset_types: List[str], | ||
| geometry: dict, | ||
| geometry: Mapping, | ||
| start_time: datetime, | ||
| filter: Optional[dict] = None, | ||
| filter: Optional[Mapping] = None, | ||
| end_time: Optional[datetime] = None, | ||
| rrule: Optional[str] = None, | ||
| ) -> dict: | ||
|
|
@@ -142,7 +189,7 @@ def catalog_source( | |
| parameters = { | ||
| "item_types": item_types, | ||
| "asset_types": asset_types, | ||
| "geometry": geojson.as_geom(geometry), | ||
| "geometry": geojson.as_geom(dict(geometry)), | ||
| } | ||
|
|
||
| try: | ||
|
|
@@ -151,7 +198,7 @@ def catalog_source( | |
| raise ClientError('Could not convert start_time to an iso string') | ||
|
|
||
| if filter: | ||
| parameters['filter'] = filter | ||
| parameters['filter'] = dict(filter) | ||
|
|
||
| if end_time: | ||
| try: | ||
|
|
@@ -348,7 +395,7 @@ def band_math_tool(b1: str, | |
| return _tool('bandmath', parameters) | ||
|
|
||
|
|
||
| def clip_tool(aoi: dict) -> dict: | ||
| def clip_tool(aoi: Mapping) -> dict: | ||
| """Specify a subscriptions API clip tool. | ||
|
|
||
| Imagery and udm files will be clipped to your area of interest. nodata | ||
|
|
@@ -370,12 +417,12 @@ def clip_tool(aoi: dict) -> dict: | |
| """ | ||
| valid_types = ['Polygon', 'MultiPolygon'] | ||
|
|
||
| geom = geojson.as_geom(aoi) | ||
| geom = geojson.as_geom(dict(aoi)) | ||
| if geom['type'].lower() not in [v.lower() for v in valid_types]: | ||
| raise ClientError( | ||
| f'Invalid geometry type: {geom["type"]} is not in {valid_types}.') | ||
|
|
||
| return _tool('clip', {'aoi': aoi}) | ||
| return _tool('clip', {'aoi': geom}) | ||
|
|
||
|
|
||
| def file_format_tool(file_format: str) -> dict: | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typing best practices (https://typing.readthedocs.io/en/latest/source/best_practices.html) is to accept mappings (most general) and return dicts (most specific). This follows Postel's Law.