diff --git a/descarteslabs/services/places.py b/descarteslabs/services/places.py index 3560bbcd..655134f2 100644 --- a/descarteslabs/services/places.py +++ b/descarteslabs/services/places.py @@ -18,10 +18,11 @@ from cachetools import TTLCache, cachedmethod from cachetools.keys import hashkey from .service import Service +from six import string_types class Places(Service): - TIMEOUT = (9.5, 120) + TIMEOUT = (9.5, 360) """Places and statistics service https://iam.descarteslabs.com/service/waldo""" def __init__(self, url=None, token=None, maxsize=10, ttl=600): @@ -47,6 +48,29 @@ def placetypes(self): r = self.session.get('/placetypes') return r.json() + def random(self, geom='low', placetype=None): + """Get a random location + + geom: string + Resolution for the shape [low (default), medium, high] + + return: geojson + """ + params = {} + + if geom: + params['geom'] = geom + + if placetype: + params['placetype'] = placetype + + r = self.session.get('%s/random' % self.url, params=params) + + if r.status_code != 200: + raise RuntimeError("%s: %s" % (r.status_code, r.text)) + + return r.json() + @cachedmethod(operator.attrgetter('cache'), key=partial(hashkey, 'find')) def find(self, path, **kwargs): """Find candidate slugs based on full or partial path. @@ -70,6 +94,45 @@ def find(self, path, **kwargs): r = self.session.get('/find/%s' % path, params=kwargs) return r.json() + def search(self, q, country=None, region=None, placetype=None): + """Search for shapes + + :param q: A query string. + :param str country: Restrict search to a specific country + :param str region: Restrict search to a specific region + :param str placetype: Restrict search to a specific placetype + + :return: list of candidates + + Example:: + >>> import descarteslabs as dl + >>> from pprint import pprint + >>> results = dl.places.search('texas') + >>> pprint(results[0]) + {'bbox': [-106.645584, 25.837395, -93.508039, 36.50035], + 'id': 85688753, + 'name': 'Texas', + 'placetype': 'region', + 'slug': 'north-america_united-states_texas'} + """ + params = {} + + if q: + params['q'] = q + + if country: + params['country'] = country + + if region: + params['region'] = region + + if placetype: + params['placetype'] = placetype + + r = self.session.get('/search', params=params, timeout=self.TIMEOUT) + + return r.json() + @cachedmethod(operator.attrgetter('cache'), key=partial(hashkey, 'shape')) def shape(self, slug, output='geojson', geom='low'): """Get the geometry for a specific slug @@ -126,3 +189,123 @@ def prefix(self, slug, output='geojson', placetype=None, geom='low'): r = self.session.get('/prefix/%s.%s' % (slug, output), params=params) return r.json() + + def sources(self): + """Get a list of sources + """ + r = self.session.get('/sources', timeout=self.TIMEOUT) + + return r.json() + + def categories(self): + """Get a list of categories + """ + r = self.session.get('/categories', timeout=self.TIMEOUT) + + return r.json() + + def metrics(self): + """Get a list of metrics + """ + r = self.session.get('/metrics', timeout=self.TIMEOUT) + + return r.json() + + def data(self, slug, source=None, category=None, metric=None, date=None, placetype='county'): + """Get all values for a prefix search and point in time + + :param str slug: Slug identifier (or shape id). + :param str source: Source + :param str category: Category + :param str metric: Metric + :param str date: Date + :param str placetype: Restrict results to a particular place type. + + """ + params = {} + + if source: + params['source'] = source + + if category: + params['category'] = category + + if metric: + params['metric'] = metric + + if date: + params['date'] = date + + if placetype: + params['placetype'] = placetype + + r = self.session.get('/data/%s' % (slug), + params=params, timeout=self.TIMEOUT) + + return r.json() + + def statistics(self, slug, source=None, category=None, metric=None): + """Get a time series for a specific place + + :param str slug: Slug identifier (or shape id). + :param str slug: Slug identifier (or shape id). + :param str source: Source + :param str category: Category + :param str metric: Metric + + """ + params = {} + + if source: + params['source'] = source + + if category: + params['category'] = category + + if metric: + params['metric'] = metric + + r = self.session.get('/statistics/%s' % (slug), + params=params, timeout=self.TIMEOUT) + + return r.json() + + def value(self, slug, source=None, category=None, metric=None, date=None): + """Get point values for a specific place + + :param str slug: Slug identifier (or shape id). + :param list(str) source: Source(s) + :param list(str) category: Category(s) + :param list(str) metric: Metric(s) + :param str date: Date + """ + params = {} + + if source: + + if isinstance(source, string_types): + source = [source] + + params['source'] = source + + if category: + + if isinstance(category, string_types): + category = [category] + + params['category'] = category + + if metric: + + if isinstance(metric, string_types): + metric = [metric] + + params['metric'] = metric + + if date: + params['date'] = date + + r = self.session.get('/value/%s' % (slug), + params=params, timeout=self.TIMEOUT) + + return r.json() diff --git a/descarteslabs/tests/test_places.py b/descarteslabs/tests/test_places.py index 2dd8fe1a..f7c97981 100644 --- a/descarteslabs/tests/test_places.py +++ b/descarteslabs/tests/test_places.py @@ -32,6 +32,19 @@ def test_find(self): r = self.instance.find('united-states_iowa') self.assertEqual(1, len(r)) + def test_search(self): + r = self.instance.search('texas') + self.assertEqual(8, len(r)) + + r = self.instance.search('texas', country='united-states') + self.assertEqual(7, len(r)) + + r = self.instance.search('texas', country='united-states', placetype='county') + self.assertEqual(2, len(r)) + + r = self.instance.search('texas', country='united-states', region='oklahoma', placetype='county') + self.assertEqual(1, len(r)) + def test_shape(self): r = self.instance.shape('north-america_united-states_iowa') self.assertEqual(85688713, r['id']) @@ -44,6 +57,31 @@ def test_prefix(self): r = self.instance.prefix('north-america_united-states_iowa', placetype='district') self.assertEqual(9, len(r['features'])) + def test_sources(self): + r = self.instance.sources() + self.assertIn('nass', r) + + def test_categories(self): + r = self.instance.categories() + self.assertIn('corn', r) + + def test_metrics(self): + r = self.instance.metrics() + self.assertIn('yield', r) + + def test_value(self): + r = self.instance.value('north-america_united-states', source='nass', category='corn', metric='yield') + self.assertEqual(1, len(r)) + + def test_statistics(self): + r = self.instance.statistics('north-america_united-states', source='nass', category='corn', metric='yield') + self.assertEqual(36, len(r)) + + def test_data(self): + r = self.instance.data('north-america_united-states', source='nass', category='corn', metric='yield', + date='2015-01-01') + self.assertEqual(1439, len(r)) + if __name__ == '__main__': unittest.main()