Skip to content

Commit 56566a7

Browse files
authored
Merge pull request #212 from descarteslabs/export
v0.8.0 Candidate
2 parents 274897f + bfceb0f commit 56566a7

26 files changed

+482
-2171
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ before_install:
99
- pip install --upgrade pip setuptools
1010
install:
1111
- pip install --upgrade -r requirements.txt
12-
- pip install .
1312
- pip install flake8 coverage nose mock
1413
script:
1514
- if [[ $TRAVIS_PYTHON_VERSION == "3.5" ]]; then nosetests --with-coverage --cover-package=descarteslabs
1615
--with-doctest --doctest-options=+ELLIPSIS,+NORMALIZE_WHITESPACE && flake8; fi
1716
- if [[ $TRAVIS_PYTHON_VERSION != "3.5" ]]; then nosetests --with-coverage --cover-package=descarteslabs;
1817
fi
18+
- pip install .
1919
notifications:
2020
slack:
2121
on_success: change

README.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,21 @@ $ export CLIENT_SECRET=...
3030

3131
Documentation
3232
-------------
33-
The documentation for the latest release can be found on [readthedocs](http://descartes-labs-python.readthedocs.io/)
33+
The documentation for the latest release can be found at [https://docs.descarteslabs.com](https://docs.descarteslabs.com)
3434

3535
Changelog
3636
=========
3737

3838
## [Unreleased]
39-
## [0.8.0] - 2018-02-08
39+
## [0.8.0] - 2018-03-29
4040
### Changed
41-
- Removed deprecated searching by const_id
41+
- Removed deprecated searching by `const_id`
4242
- Removed deprecated raster band methods
43+
- Deprecated `sat_id` parameter for metadata searches
44+
- Changed documentation from readthedocs to https://docs.descarteslabs.com
45+
46+
### Added
47+
- Dot notation access to dictionaries returned by services
4348

4449
## [0.7.0] - 2018-01-24
4550
### Changed

descarteslabs/client/auth/cli.py

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
from six.moves import input
2222

2323
from descarteslabs.client.auth.auth import Auth, base64url_decode, makedirs_if_not_exists, DEFAULT_TOKEN_INFO_PATH
24-
from descarteslabs.client.services.metadata import Metadata
2524
from descarteslabs.client.version import __version__
2625

2726

@@ -53,20 +52,10 @@ def auth_handler(args):
5352

5453
# Get a fresh Auth token
5554
auth = Auth()
56-
keys = Metadata(auth=auth).keys()
5755

5856
name = auth.payload['name']
59-
groups = ', '.join(auth.payload['groups'])
6057

61-
if len(keys):
62-
63-
print('Welcome, %s!' % name)
64-
65-
else:
66-
67-
print('Welcome, %s! Your %s role(s) do not permit access to any imagery at this time.' % (name, groups))
68-
print(
69-
'Contact [email protected] if you believe you received this message in error or have any questions.') # NOQA
58+
print('Welcome, %s!' % name)
7059

7160
if args.command == 'token':
7261
print(auth.token)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.. `_descarteslabs_client_auth`
2+
3+
Authentication
4+
--------------
5+
.. automodule:: descarteslabs.client.auth
6+
:members:
7+
:undoc-members:

descarteslabs/client/readme.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Exceptions
2+
----------
3+
.. automodule:: descarteslabs.client.exceptions
4+
:members:
5+
:undoc-members:

descarteslabs/client/services/metadata/__init__.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,8 @@
1313
# limitations under the License.
1414

1515
from .metadata import Metadata
16-
from .metadata_filtering import Properties
16+
from .metadata_filtering import GLOBAL_PROPERTIES
1717

18-
properties = Properties("absolute_orbit", "acquired", "archived", "area", "azimuth_angle",
19-
"bright_fraction", "cirrus_fraction", "cloud_fraction", "cloud_fraction_0",
20-
"cloud_fraction_1", "descartes_version", "earth_sun_distance",
21-
"fill_fraction", "geolocation_accuracy", "opaque_fraction", "product", "processed",
22-
"published", "relative_orbit", "roll_angle", "sat_id", "solar_azimuth_angle",
23-
"solar_azimuth_angle_0", "solar_elevation_angle", "solar_elevation_angle_0",
24-
"sw_version", "terrain_correction", "tile_id", "view_angle", "view_angle_0",
25-
"view_angle_1")
18+
properties = GLOBAL_PROPERTIES
2619

2720
__all__ = ["Metadata", "properties"]

descarteslabs/client/services/metadata/metadata.py

Lines changed: 60 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,27 @@
2020
from descarteslabs.client.services.places import Places
2121
from descarteslabs.client.auth import Auth
2222
from descarteslabs.client.services.raster import Raster
23-
from descarteslabs.client.services.metadata.metadata_filtering import AndExpression
23+
from descarteslabs.client.services.metadata.metadata_filtering import \
24+
AndExpression, GLOBAL_PROPERTIES
25+
from descarteslabs.common.dotdict import DotDict, DotList
2426

2527

2628
OFFSET_DEPRECATION_MESSAGE = (
2729
"Keyword arg `offset` has been deprecated and will be removed in "
2830
"future versions of the library. "
2931
)
3032

33+
SAT_ID_DEPRECATION_MESSAGE = (
34+
"Keyword arg `sat_id` has been deprecated and will be removed in "
35+
"future versions of the library. "
36+
)
37+
38+
SOURCES_DEPRECATION_MESSAGE = (
39+
"Metadata.sources() has been deprecated and will be removed in "
40+
"future versions of the library. Please use "
41+
"Metadata.available_products() or Metadata.products() instead. "
42+
)
43+
3144

3245
class Metadata(Service):
3346
"""
@@ -41,32 +54,29 @@ class Metadata(Service):
4154

4255
TIMEOUT = (9.5, 120)
4356

44-
def __init__(self, url=None, token=None, auth=Auth()):
57+
properties = GLOBAL_PROPERTIES
58+
59+
def __init__(self, url=None, auth=None):
4560
"""The parent Service class implements authentication and exponential
4661
backoff/retry. Override the url parameter to use a different instance
4762
of the backing service.
4863
"""
64+
if auth is None:
65+
auth = Auth()
66+
4967
simplefilter('always', DeprecationWarning)
5068
if url is None:
5169
url = os.environ.get("DESCARTESLABS_METADATA_URL",
5270
"https://platform.descarteslabs.com/metadata/v1")
5371

54-
Service.__init__(self, url, token, auth)
72+
super(Metadata, self).__init__(url, auth)
5573
self._raster = Raster(auth=self.auth)
5674

5775
def sources(self):
58-
"""Get a list of image sources.
76+
warn(SOURCES_DEPRECATION_MESSAGE, DeprecationWarning)
5977

60-
Example::
61-
>>> from descarteslabs.client.services import Metadata
62-
>>> from pprint import pprint
63-
>>> sources = Metadata().sources()
64-
>>> pprint(sources)
65-
[{'product': 'landsat:LC08:PRE:TOAR', 'sat_id': 'LANDSAT_8'}]
66-
67-
"""
6878
r = self.session.get('/sources')
69-
return r.json()
79+
return DotList(r.json())
7080

7181
def bands(
7282
self,
@@ -101,7 +111,7 @@ def bands(
101111
})
102112

103113
r = self.session.post('/bands/search', json=kwargs)
104-
return r.json()
114+
return DotList(r.json())
105115

106116
def derived_bands(self, bands=None, require_bands=None, limit=None, offset=None, **kwargs):
107117
"""Search for predefined derived bands that you have access to.
@@ -125,7 +135,7 @@ def derived_bands(self, bands=None, require_bands=None, limit=None, offset=None,
125135
})
126136

127137
r = self.session.post('/bands/derived/search', json=kwargs)
128-
return r.json()
138+
return DotList(r.json())
129139

130140
def get_bands_by_key(self, key):
131141
"""
@@ -137,7 +147,7 @@ def get_bands_by_key(self, key):
137147
"""
138148
r = self.session.get('/bands/key/%s' % key)
139149

140-
return r.json()
150+
return DotDict(r.json())
141151

142152
def products(self, bands=None, limit=None, offset=None, owner=None, text=None, **kwargs):
143153
"""Search products that are available on the platform.
@@ -161,22 +171,21 @@ def products(self, bands=None, limit=None, offset=None, owner=None, text=None, *
161171

162172
r = self.session.post('/products/search', json=kwargs)
163173

164-
return r.json()
174+
return DotList(r.json())
165175

166176
def available_products(self):
167177
"""Get the list of product identifiers you have access to.
168178
169179
Example::
170180
>>> from descarteslabs.client.services import Metadata
171-
>>> from pprint import pprint
172181
>>> products = Metadata().available_products()
173-
>>> pprint(products)
182+
>>> products
174183
['landsat:LC08:PRE:TOAR']
175184
176185
"""
177186
r = self.session.get('/products')
178187

179-
return r.json()
188+
return DotList(r.json())
180189

181190
def summary(self, products=None, sat_id=None, date='acquired', part=None,
182191
place=None, geom=None, start_time=None, end_time=None, cloud_fraction=None,
@@ -185,7 +194,7 @@ def summary(self, products=None, sat_id=None, date='acquired', part=None,
185194
"""Get a summary of the results for the specified spatio-temporal query.
186195
187196
:param list(str) products: Product identifier(s).
188-
:param list(str) sat_id: Satellite identifier(s).
197+
:param list(str) sat_id: Satellite identifier(s). *Deprecated*
189198
:param str date: The date field to use for search (e.g. `acquired`).
190199
:param str part: Part of the date to aggregate over (e.g. `day`).
191200
:param str place: A slug identifier to be used as a region of interest.
@@ -202,19 +211,24 @@ def summary(self, products=None, sat_id=None, date='acquired', part=None,
202211
Example usage::
203212
204213
>>> from descarteslabs.client.services import Metadata
205-
>>> from pprint import pprint
206-
>>> pprint(Metadata().summary(place='north-america_united-states_iowa', \
214+
>>> Metadata().summary(place='north-america_united-states_iowa', \
207215
products=['landsat:LC08:PRE:TOAR'], start_time='2016-07-06', \
208-
end_time='2016-07-07', part='hour', pixels=True))
209-
{'bytes': 93298309,
210-
'count': 1,
211-
'items': [{'bytes': 93298309,
212-
'count': 1,
213-
'date': '2016-07-06T16:00:00',
214-
'pixels': 250508160,
215-
'timestamp': 1467820800}],
216-
'pixels': 250508160,
217-
'products': ['landsat:LC08:PRE:TOAR']}
216+
end_time='2016-07-07', part='hour', pixels=True)
217+
{
218+
'bytes': 93298309,
219+
'count': 1,
220+
'items': [
221+
{
222+
'bytes': 93298309,
223+
'count': 1,
224+
'date': '2016-07-06T16:00:00',
225+
'pixels': 250508160,
226+
'timestamp': 1467820800
227+
}
228+
],
229+
'pixels': 250508160,
230+
'products': ['landsat:LC08:PRE:TOAR']
231+
}
218232
"""
219233
if place:
220234
places = Places()
@@ -234,6 +248,8 @@ def summary(self, products=None, sat_id=None, date='acquired', part=None,
234248
kwargs = {}
235249

236250
if sat_id:
251+
warn(SAT_ID_DEPRECATION_MESSAGE, DeprecationWarning)
252+
237253
if isinstance(sat_id, string_types):
238254
sat_id = [sat_id]
239255

@@ -278,7 +294,7 @@ def summary(self, products=None, sat_id=None, date='acquired', part=None,
278294
kwargs['pixels'] = pixels
279295

280296
r = self.session.post('/summary', json=kwargs)
281-
return r.json()
297+
return DotDict(r.json())
282298

283299
def search(self, products=None, sat_id=None, date='acquired', place=None,
284300
geom=None, start_time=None, end_time=None, cloud_fraction=None,
@@ -341,6 +357,8 @@ def search(self, products=None, sat_id=None, date='acquired', place=None,
341357
kwargs['offset'] = offset
342358

343359
if sat_id:
360+
warn(SAT_ID_DEPRECATION_MESSAGE, DeprecationWarning)
361+
344362
if isinstance(sat_id, string_types):
345363
sat_id = [sat_id]
346364

@@ -398,7 +416,7 @@ def search(self, products=None, sat_id=None, date='acquired', place=None,
398416
fc['properties'] = {
399417
'continuation_token': r.headers['x-continuation-token']}
400418

401-
return fc
419+
return DotDict(fc)
402420

403421
def ids(self, products=None, sat_id=None, date='acquired', place=None,
404422
geom=None, start_time=None, end_time=None, cloud_fraction=None,
@@ -448,7 +466,7 @@ def ids(self, products=None, sat_id=None, date='acquired', place=None,
448466
q=q, limit=limit, offset=offset, fields=[], dltile=dltile,
449467
sort_field=sort_field, sort_order=sort_order, randomize=randomize)
450468

451-
return [feature['id'] for feature in result['features']]
469+
return DotList(feature['id'] for feature in result['features'])
452470

453471
def keys(self, products=None, sat_id=None, date='acquired', place=None,
454472
geom=None, start_time=None, end_time=None, cloud_fraction=None,
@@ -499,7 +517,7 @@ def keys(self, products=None, sat_id=None, date='acquired', place=None,
499517
dltile=dltile, sort_field=sort_field,
500518
sort_order=sort_order, randomize=randomize)
501519

502-
return [feature['key'] for feature in result['features']]
520+
return DotList(feature['key'] for feature in result['features'])
503521

504522
def features(self, products=None, sat_id=None, date='acquired', place=None,
505523
geom=None, start_time=None, end_time=None, cloud_fraction=None,
@@ -569,7 +587,7 @@ def get(self, key):
569587
'tile_id']
570588
"""
571589
r = self.session.get('/get/%s' % key)
572-
return r.json()
590+
return DotDict(r.json())
573591

574592
def get_by_ids(self, ids):
575593
"""Get metadata for multiple images by id. The response contains found images in the
@@ -579,7 +597,7 @@ def get_by_ids(self, ids):
579597
:return: List of image metadata.
580598
"""
581599
r = self.session.post('/batch/images', json={'ids': ids})
582-
return r.json()
600+
return DotList(r.json())
583601

584602
def get_product(self, product_id):
585603
"""Get information about a single product.
@@ -588,7 +606,7 @@ def get_product(self, product_id):
588606
589607
"""
590608
r = self.session.get('/products/%s' % product_id)
591-
return r.json()
609+
return DotDict(r.json())
592610

593611
def get_band(self, band_id):
594612
"""Get information about a single product.
@@ -597,7 +615,7 @@ def get_band(self, band_id):
597615
598616
"""
599617
r = self.session.get('/bands/%s' % band_id)
600-
return r.json()
618+
return DotDict(r.json())
601619

602620
def get_derived_band(self, derived_band_id):
603621
"""Get information about a single product.
@@ -606,4 +624,4 @@ def get_derived_band(self, derived_band_id):
606624
607625
"""
608626
r = self.session.get('/bands/derived/%s' % derived_band_id)
609-
return r.json()
627+
return DotDict(r.json())

descarteslabs/client/services/metadata/metadata_filtering.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,3 +139,15 @@ def __getattr__(self, attr):
139139

140140
raise AttributeError(
141141
"'Properties' object has no attribute '{}'".format(attr))
142+
143+
144+
GLOBAL_PROPERTIES = Properties(
145+
"absolute_orbit", "acquired", "archived", "area", "azimuth_angle",
146+
"bright_fraction", "cirrus_fraction", "cloud_fraction", "cloud_fraction_0",
147+
"cloud_fraction_1", "descartes_version", "earth_sun_distance",
148+
"fill_fraction", "geolocation_accuracy", "opaque_fraction", "product", "processed",
149+
"published", "relative_orbit", "roll_angle", "sat_id", "solar_azimuth_angle",
150+
"solar_azimuth_angle_0", "solar_elevation_angle", "solar_elevation_angle_0",
151+
"sw_version", "terrain_correction", "tile_id", "view_angle", "view_angle_0",
152+
"view_angle_1"
153+
)

0 commit comments

Comments
 (0)