24
24
25
25
CONST_ID_DEPRECATION_MESSAGE = (
26
26
"Keyword arg `const_id' has been deprecated and will be removed in "
27
- "future versions of this software . Use the `products` "
27
+ "future versions of the library . Use the `products` "
28
28
"argument instead. Product identifiers can be found with the "
29
29
" products() method."
30
30
)
31
31
32
+ OFFSET_DEPRECATION_MESSAGE = (
33
+ "Keyword arg `offset` has been deprecated and will be removed in "
34
+ "future versions of the library. "
35
+ )
36
+
32
37
33
38
class Metadata (Service ):
34
39
"""Image Metadata Service"""
@@ -304,10 +309,10 @@ def summary(self, products=None, const_id=None, sat_id=None, date='acquired', pa
304
309
def search (self , products = None , const_id = None , sat_id = None , date = 'acquired' , place = None ,
305
310
geom = None , start_time = None , end_time = None , cloud_fraction = None ,
306
311
cloud_fraction_0 = None , fill_fraction = None , q = None , limit = 100 , offset = 0 ,
307
- fields = None , dltile = None , sort_field = None , sort_order = "asc" , randomize = None ):
312
+ fields = None , dltile = None , sort_field = None , sort_order = "asc" , randomize = None ,
313
+ continuation_token = None ):
308
314
"""Search metadata given a spatio-temporal query. All parameters are
309
- optional. Results are paged using limit and offset. Please note offset
310
- plus limit cannot exceed 10000.
315
+ optional. For accessing more than 10000 results, see :py:func:`features`.
311
316
312
317
:param list(str) products: Product Identifier(s).
313
318
:param list(str) const_id: Constellation Identifier(s).
@@ -321,7 +326,7 @@ def search(self, products=None, const_id=None, sat_id=None, date='acquired', pla
321
326
:param float cloud_fraction_0: Maximum cloud fraction, calculated by cloud mask pixels.
322
327
:param float fill_fraction: Minimum scene fill fraction, calculated as valid/total pixels.
323
328
:param expr q: Expression for filtering the results. See :py:attr:`descarteslabs.utilities.properties`.
324
- :param int limit: Number of items to return. (max of 10000)
329
+ :param int limit: Number of items to return up to the maximum of 10000.
325
330
:param int offset: Number of items to skip.
326
331
:param list(str) fields: Properties to return.
327
332
:param str dltile: a dltile key used to specify the resolution, bounds, and srs.
@@ -356,7 +361,11 @@ def search(self, products=None, const_id=None, sat_id=None, date='acquired', pla
356
361
if isinstance (geom , dict ):
357
362
geom = json .dumps (geom )
358
363
359
- kwargs = {'date' : date , 'limit' : limit , 'offset' : offset }
364
+ kwargs = {'date' : date , 'limit' : limit }
365
+
366
+ if offset :
367
+ warn (OFFSET_DEPRECATION_MESSAGE , DeprecationWarning )
368
+ kwargs ['offset' ] = offset
360
369
361
370
if sat_id :
362
371
if isinstance (sat_id , string_types ):
@@ -413,16 +422,24 @@ def search(self, products=None, const_id=None, sat_id=None, date='acquired', pla
413
422
if randomize is not None :
414
423
kwargs ['random_seed' ] = randomize
415
424
425
+ if continuation_token is not None :
426
+ kwargs ['continuation_token' ] = continuation_token
427
+
416
428
r = self .session .post ('/search' , json = kwargs )
417
429
418
- return {'type' : 'FeatureCollection' , "features" : r .json ()}
430
+ fc = {'type' : 'FeatureCollection' , "features" : r .json ()}
431
+
432
+ if 'x-continuation-token' in r .headers :
433
+ fc ['properties' ] = {'continuation_token' : r .headers ['x-continuation-token' ]}
434
+
435
+ return fc
419
436
420
437
def ids (self , products = None , const_id = None , sat_id = None , date = 'acquired' , place = None ,
421
438
geom = None , start_time = None , end_time = None , cloud_fraction = None ,
422
439
cloud_fraction_0 = None , fill_fraction = None , q = None , limit = 100 , offset = None ,
423
440
dltile = None , sort_field = None , sort_order = None , randomize = None ):
424
441
"""Search metadata given a spatio-temporal query. All parameters are
425
- optional. Results are paged using limit/offset.
442
+ optional.
426
443
427
444
:param list(str) products: Products identifier(s).
428
445
:param list(str) const_id: Constellation identifier(s).
@@ -522,40 +539,52 @@ def keys(self, products=None, const_id=None, sat_id=None, date='acquired', place
522
539
523
540
def features (self , products = None , const_id = None , sat_id = None , date = 'acquired' , place = None ,
524
541
geom = None , start_time = None , end_time = None , cloud_fraction = None ,
525
- cloud_fraction_0 = None , fill_fraction = None , q = None ,
526
- limit = 100 , dltile = None , sort_field = None , sort_order = 'asc' ):
542
+ cloud_fraction_0 = None , fill_fraction = None , q = None , fields = None ,
543
+ batch_size = 1000 , dltile = None , sort_field = None , sort_order = 'asc' ,
544
+ randomize = None ):
545
+ """Generator that efficiently scrolls through the search results.
527
546
528
- """Generator that combines summary and search to page through results.
529
-
530
- :param int limit: Number of features to fetch per request.
547
+ :param int batch_size: Number of features to fetch per request.
531
548
532
549
:return: Generator of GeoJSON ``Feature`` objects.
550
+
551
+ Example::
552
+
553
+ >>> import descarteslabs as dl
554
+ >>> features = dl.metadata.features("landsat:LC08:PRE:TOAR", \
555
+ start_time='2016-01-01', \
556
+ end_time="2016-03-01")
557
+ >>> total = 0
558
+ >>> for f in features: \
559
+ total += 1
560
+
561
+ >>> total # doctest: +SKIP
562
+ 31898
533
563
"""
534
- summary = self .summary (sat_id = sat_id , products = products , const_id = None , date = date ,
535
- place = place , geom = geom , start_time = start_time ,
536
- end_time = end_time , cloud_fraction = cloud_fraction ,
537
- cloud_fraction_0 = cloud_fraction_0 ,
538
- fill_fraction = fill_fraction , q = q , dltile = dltile )
539
-
540
- offset = 0
541
- count = summary ['count' ]
542
-
543
- while offset < count :
544
- features = self .search (sat_id = sat_id , products = products , const_id = None ,
545
- date = date , place = place , geom = geom ,
546
- start_time = start_time , end_time = end_time ,
547
- cloud_fraction = cloud_fraction ,
548
- cloud_fraction_0 = cloud_fraction_0 ,
549
- fill_fraction = fill_fraction , q = q ,
550
- limit = limit , offset = offset ,
551
- dltile = dltile , sort_field = sort_field ,
552
- sort_order = sort_order )
553
-
554
- offset = limit + offset
555
-
556
- for feature in features ['features' ]:
564
+
565
+ continuation_token = None
566
+
567
+ while True :
568
+ result = self .search (sat_id = sat_id , products = products , const_id = None ,
569
+ date = date , place = place , geom = geom ,
570
+ start_time = start_time , end_time = end_time ,
571
+ cloud_fraction = cloud_fraction ,
572
+ cloud_fraction_0 = cloud_fraction_0 ,
573
+ fill_fraction = fill_fraction , q = q ,
574
+ fields = fields , limit = batch_size , dltile = dltile ,
575
+ sort_field = sort_field , sort_order = sort_order ,
576
+ randomize = randomize , continuation_token = continuation_token )
577
+
578
+ if not result ['features' ]:
579
+ break
580
+
581
+ for feature in result ['features' ]:
557
582
yield feature
558
583
584
+ continuation_token = result ['properties' ].get ('continuation_token' )
585
+ if not continuation_token :
586
+ break
587
+
559
588
def get (self , key ):
560
589
"""Get metadata of a single image.
561
590
0 commit comments