Skip to content

Commit 487c9e4

Browse files
authored
Merge pull request planetlabs#206 from planetlabs/add-ids_from_search-to-orders
create orders additions ids_from_search, --clip
2 parents 4f2037d + c1f2ffd commit 487c9e4

File tree

4 files changed

+247
-58
lines changed

4 files changed

+247
-58
lines changed

docs/source/cli/examples.rst

Lines changed: 143 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ meant to be easily interoperable with other tools, e.g. `jq
6161
<https://stedolan.github.io/jq/>`_. For example, we could output just the name
6262
and date range of each mosaic with::
6363

64-
planet mosaics list | jq -r '.mosaics[] | [.name, .first_acquired, .last_acquired] | @tsv'
64+
planet mosaics list | jq -r '.mosaics[] | [.name, .first_acquired, .last_acquired] | @tsv'
6565

6666
Get basic information for a specific mosaic::
6767

@@ -73,7 +73,7 @@ list all quads. Keep in mind that there may be millions for a global mosaic.)::
7373
planet mosaics search global_monthly_2018_09_mosaic --limit=10
7474

7575
Find all quads inside a particular area of interest::
76-
76+
7777
planet mosaics search global_monthly_2018_09_mosaic --bbox=-95.5,29.6,-95.3,29.8
7878

7979
Note that the format of ``--bbox`` is "xmin,ymin,xmax,ymax", so longitude comes
@@ -193,7 +193,7 @@ Orders Examples
193193
-----------------
194194

195195
List all recent orders for the authenticated user::
196-
196+
197197
planet orders list
198198

199199
Get the status of a single order by Order ID::
@@ -203,17 +203,17 @@ Get the status of a single order by Order ID::
203203
Note that you may want to parse the JSON that's output into a more human
204204
readable format. The cli does not directly provide options for this, but is
205205
meant to be easily interoperable with other tools, e.g. `jq
206-
<https://stedolan.github.io/jq/>`_.
206+
<https://stedolan.github.io/jq/>`_.
207207

208208
To cancel a running order by given order ID::
209209

210210
planet orders cancel <order ID>
211211

212-
To download an order to your local machine::
212+
To download an order to your local machine::
213213

214-
planet orders download <order ID>
214+
planet orders download <order ID>
215215

216-
Optionally, a `--dest <path to destination>` flag may be specified too.
216+
Optionally, a `--dest <path to destination>` flag may be specified too.
217217

218218
Creating an Order
219219
..................
@@ -227,19 +227,148 @@ The minimal command to create a simple order looks something like::
227227
If no toolchain or delivery details are specified, a basic order with download
228228
delivery will be placed for the requested bundle including the item id(s) specified.
229229

230-
Additionally, optional toolchain & delivery details can be provided on the
231-
command line, e.g.:::
230+
In the place of `--id`, you can insert a Data search string. This will populate
231+
the list of IDs from a search. For example::
232+
233+
planet orders create --name "my order" \
234+
--ids_from_search $'--item-type PSScene3Band --date acquired gt 2017-02-14 --date acquired lt 2017-03-14 --limit 6 --geom \'{
235+
"type": "FeatureCollection",
236+
"features": [
237+
{
238+
"type": "Feature",
239+
"properties": {},
240+
"geometry": {
241+
"type": "Polygon",
242+
"coordinates": [
243+
[
244+
[
245+
-116.40701293945311,
246+
43.061363052307875
247+
],
248+
[
249+
-116.4451217651367,
250+
43.05032512283074
251+
],
252+
[
253+
-116.4320755004883,
254+
43.017450433440814
255+
],
256+
[
257+
-116.37508392333984,
258+
43.01092359150748
259+
],
260+
[
261+
-116.3393783569336,
262+
43.03677585761058
263+
],
264+
[
265+
-116.35894775390624,
266+
43.06186472916744
267+
],
268+
[
269+
-116.40701293945311,
270+
43.061363052307875
271+
]
272+
]
273+
]
274+
}
275+
}
276+
]
277+
}\'' \
278+
--bundle visual \
279+
--item-type psscene3band \
280+
--zip bundle --email \
281+
--clip '{
282+
"type": "Polygon",
283+
"coordinates": [
284+
[
285+
[
286+
-116.40701293945311,
287+
43.061363052307875
288+
],
289+
[
290+
-116.4451217651367,
291+
43.05032512283074
292+
],
293+
[
294+
-116.4320755004883,
295+
43.017450433440814
296+
],
297+
[
298+
-116.37508392333984,
299+
43.01092359150748
300+
],
301+
[
302+
-116.3393783569336,
303+
43.03677585761058
304+
],
305+
[
306+
-116.35894775390624,
307+
43.06186472916744
308+
],
309+
[
310+
-116.40701293945311,
311+
43.061363052307875
312+
]
313+
]
314+
]
315+
}'
316+
317+
Note that `--ids_from_search` is passed as a string value.
318+
319+
Additionally, optional toolchain & delivery details can be provided on the command line, e.g.::
232320

233321
planet orders create --name "my order" \
234322
--id 20151119_025740_0c74,20151119_025741_0c74 \
235323
--bundle visual --item-type psscene3band --zip order --email
236324

237325
This places the same order as above, and will also provide a .zip archive
238-
download link for the full order, as well as email notification.
326+
download link for the full order, as well as email notification. If you change
327+
`--zip order` to `--zip bundle`, the individual bundles will be zipped rather
328+
than the full order.
329+
330+
You can also clip the items in an order by providing a GeoJSON AOI Geometry
331+
with the `--clip` parameter::
332+
333+
planet orders create --name "my order" ... \
334+
--clip '{
335+
"type": "Polygon",
336+
"coordinates": [
337+
[
338+
[
339+
-163.828125,
340+
-44.59046718130883
341+
],
342+
[
343+
181.7578125,
344+
-44.59046718130883
345+
],
346+
[
347+
181.7578125,
348+
78.42019327591201
349+
],
350+
[
351+
-163.828125,
352+
78.42019327591201
353+
],
354+
[
355+
-163.828125,
356+
-44.59046718130883
357+
]
358+
]
359+
]
360+
}'
361+
362+
Alternatively, you can specify a file that contains your GeoJSON AOI using the
363+
`@` notation, e.g. `--clip @path/to/aoi.json`.
364+
365+
It should be noted that if the clip AOI you specify does not intersect with the
366+
items in `--id` or `--ids_from_search` you may end up with a zero result order.
367+
If some of the items intersect, you will receive those items.
239368

240369
The Orders API allows you to specify a toolchain of operations to be performed
241370
on your order prior to download. To read more about tools & toolchains, visit
242-
`the docs <https://developers.planet.com/docs/orders/tools-toolchains/>`_ .
371+
`the docs <https://developers.planet.com/docs/orders/tools-toolchains/>`_ .
243372

244373
To add tool operations to your order, use the `--tools` option to specify a
245374
json-formatted file containing an array (list) of the desired tools an their
@@ -271,16 +400,16 @@ order, you would create a `.json` file similar to the following::
271400
"name_template": "C1232_30_30_{tilex:04d}_{tiley:04d}"
272401
}
273402
}
274-
]
403+
]
275404

276405

277406
Similarly, you can also specify cloud delivery options on an order create
278407
command with the `--cloudconfig <path to json file>` option. In this case, the
279408
json file should contain the required credentials for your desired cloud
280409
storage destination, for example::
281410

282-
{
283-
"amazon_s3":{
411+
{
412+
"amazon_s3":{
284413
"bucket":"foo-bucket",
285414
"aws_region":"us-east-2",
286415
"aws_access_key_id":"",

planet/scripts/types.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,3 +309,28 @@ def convert(self, val, param, ctx):
309309
for date in dates:
310310
if date != '..' and strp_lenient(date) is None:
311311
raise click.BadParameter('Invalid date: {}'.format(date))
312+
313+
314+
class ClipAOI(click.ParamType):
315+
name = 'clip'
316+
317+
def convert(self, val, param, ctx):
318+
val = read(val)
319+
if not val:
320+
return []
321+
try:
322+
json.loads(val)
323+
except ValueError:
324+
raise click.BadParameter('invalid GeoJSON')
325+
return val
326+
327+
328+
class RequiredUnless(click.Option):
329+
def __init__(self, *args, **kwargs):
330+
self.this_opt_exists = kwargs.pop('this_opt_exists')
331+
super(RequiredUnless, self).__init__(*args, **kwargs)
332+
333+
def handle_parse_result(self, ctx, opts, args):
334+
if self.name not in opts and self.this_opt_exists not in opts:
335+
raise click.UsageError('{} is required.'.format(self.name))
336+
return super(RequiredUnless, self).handle_parse_result(ctx, opts, args)

planet/scripts/util.py

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ def create_order_request(**kwargs):
100100
email = kwargs.get('email')
101101
archive = kwargs.get('zip')
102102
config = kwargs.get('cloudconfig')
103+
clip = kwargs.get('clip')
103104
tools = kwargs.get('tools')
104105

105106
request = {'name': kwargs.get('name'),
@@ -108,30 +109,35 @@ def create_order_request(**kwargs):
108109
'product_bundle': bundle}
109110
],
110111
'tools': [
111-
],
112-
'delivery': {
113-
},
114-
'notifications': {
112+
],
113+
'delivery': {
114+
},
115+
'notifications': {
115116
'email': email
116-
},
117-
}
117+
},
118+
}
118119

119120
if archive is not None:
120121
request["delivery"]["archive_filename"] = "{{name}}_{{order_id}}.zip"
121122
request["delivery"]["archive_type"] = "zip"
122123

123-
# TODO verify this is correct req format for order vs bundle zip
124-
if archive == "bundle":
124+
# If single_archive is not set, each bundle will be zipped, as opposed
125+
# to the entire order.
126+
if archive == "order":
125127
request["delivery"]["single_archive"] = True
126128

127129
if config:
128130
with open(config, 'r') as f:
129131
conf = json.load(f)
130132
request["delivery"].update(conf)
131133

132-
# TODO determine reasonable interfaces for SOME tools via CLI;
133-
# e.g., clip via provided geojson AOI
134-
# for now we can punt by pointing users to doc examples for copy-pasting
134+
# NOTE clip is the only tool that currently can be specified via CLI param.
135+
# A full tool chain can be specified via JSON file, so that will overwrite
136+
# clip if both are present. TODO add other common tools as params.
137+
if clip and not tools:
138+
toolchain = [{'clip': {'aoi': json.loads(clip)}}]
139+
request['tools'].extend(toolchain)
140+
135141
if tools:
136142
with open(tools, 'r') as f:
137143
toolchain = json.load(f)
@@ -346,3 +352,11 @@ def downloader_output(dl, disable_ansi=False):
346352
if termui.WIN and not disable_ansi:
347353
logging.getLogger('').setLevel(logging.INFO)
348354
return Output(thread, dl)
355+
356+
357+
def ids_from_search_response(resp):
358+
ret = []
359+
r = json.loads(resp)
360+
for feature in r['features']:
361+
ret.append(feature['id'])
362+
return ','.join(ret)

0 commit comments

Comments
 (0)