Repository: planetlabs/planet-client-python
Pull request #194 (2019-10-21 19:15:51)

Simplify analytics configuration


Patch:
diff --git a/CHANGES.txt b/CHANGES.txt
index 2c7f379..fcde4d8 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,3 +1,7 @@
+1.4.3 (2019-10-21)
+
+- Simplified configuration of analytics client to be consistent
+
 1.4.2 (2019-10-04)
 
 - added new asset type
diff --git a/planet/api/__version__.py b/planet/api/__version__.py
index 98d186b..4e7c72a 100644
--- a/planet/api/__version__.py
+++ b/planet/api/__version__.py
@@ -1,1 +1,1 @@
-__version__ = '1.4.2'
+__version__ = '1.4.3'
diff --git a/planet/api/client.py b/planet/api/client.py
index e3ef818..e3df1cf 100644
--- a/planet/api/client.py
+++ b/planet/api/client.py
@@ -34,6 +34,8 @@ class _Base(object):
         api_key = api_key or auth.find_api_key()
         self.auth = api_key and auth.APIKey(api_key)
         self.base_url = base_url
+        if not self.base_url.endswith('/'):
+            self.base_url += '/'
         self.dispatcher = RequestsDispatcher(workers)
 
     def shutdown(self):
@@ -369,14 +371,14 @@ class ClientV1(_Base):
         to test environments.
         :returns: :py:Class:`planet.api.models.JSON`
         '''
-        return self._get(self._url('health')).get_body()
+        return self._get(self._url('analytics/health')).get_body()
 
     def wfs_conformance(self):
         '''
         Details about WFS3 conformance
         :returns: :py:Class:`planet.api.models.JSON`
         '''
-        return self._get(self._url('conformance')).get_body()
+        return self._get(self._url('analytics/conformance')).get_body()
 
     def list_analytic_subscriptions(self, feed_id):
         '''
@@ -387,7 +389,7 @@ class ClientV1(_Base):
         :returns: :py:Class:`planet.api.models.Subscriptions`
         '''
         params = {'feedID': feed_id}
-        url = self._url('subscriptions')
+        url = self._url('analytics/subscriptions')
         return self._get(url, models.Subscriptions, params=params).get_body()
 
     def get_subscription_info(self, subscription_id):
@@ -397,7 +399,7 @@ class ClientV1(_Base):
         :raises planet.api.exceptions.APIException: On API error.
         :returns: :py:Class:`planet.api.models.JSON`
         '''
-        url = self._url('subscriptions/{}'.format(subscription_id))
+        url = self._url('analytics/subscriptions/{}'.format(subscription_id))
         return self._get(url, models.JSON).get_body()
 
     def list_analytic_feeds(self, stats):
@@ -407,7 +409,7 @@ class ClientV1(_Base):
         :returns: :py:Class:`planet.api.models.Feeds`
         '''
         params = {'stats': stats}
-        url = self._url('feeds')
+        url = self._url('analytics/feeds')
         return self._get(url, models.Feeds, params=params).get_body()
 
     def get_feed_info(self, feed_id):
@@ -417,7 +419,7 @@ class ClientV1(_Base):
         :raises planet.api.exceptions.APIException: On API error.
         :returns: :py:Class:`planet.api.models.JSON`
         '''
-        url = self._url('feeds/{}'.format(feed_id))
+        url = self._url('analytics/feeds/{}'.format(feed_id))
         return self._get(url, models.JSON).get_body()
 
     def list_analytic_collections(self):
@@ -427,7 +429,7 @@ class ClientV1(_Base):
         :returns: :py:Class:`planet.api.models.WFS3Collections`
         '''
         params = {}
-        url = self._url('collections')
+        url = self._url('analytics/collections')
         return self._get(url, models.WFS3Collections,
                          params=params).get_body()
 
@@ -438,7 +440,7 @@ class ClientV1(_Base):
         :raises planet.api.exceptions.APIException: On API error.
         :returns: :py:Class:`planet.api.models.JSON`
         '''
-        url = 'collections/{}'.format(subscription_id)
+        url = 'analytics/collections/{}'.format(subscription_id)
         return self._get(self._url(url), models.JSON).get_body()
 
     def list_collection_features(self,
@@ -469,7 +471,8 @@ class ClientV1(_Base):
         if after:
             params['after'] = after
 
-        url = self._url('collections/{}/items'.format(subscription_id))
+        url = self._url('analytics/collections/{}/items'.format(
+            subscription_id))
         return self._get(url, models.WFS3Features, params=params).get_body()
 
     def get_associated_resource_for_analytic_feature(self,
@@ -490,9 +493,8 @@ class ClientV1(_Base):
         :py:Class:`planet.api.models.Body` of the resource.
         '''
         url = self._url(
-            'collections/{}/items/{}/resources/{}'.format(subscription_id,
-                                                          feature_id,
-                                                          resource_type))
+            'analytics/collections/{}/items/{}/resources/{}'.format(
+                subscription_id, feature_id, resource_type))
         response = self._get(url).get_body()
         return response
 
diff --git a/planet/scripts/cli.py b/planet/scripts/cli.py
index 7b2991d..89d187e 100644
--- a/planet/scripts/cli.py
+++ b/planet/scripts/cli.py
@@ -25,22 +25,9 @@ client_params = {}
 
 
 def clientv1():
-    client_params.pop('analytics_base_url', None)
     return api.ClientV1(**client_params)
 
 
-def analytics_client_v1():
-    # Non-default analytics base URL doesn't have the analytics postfix
-    params = dict(**client_params)
-    if client_params.get('analytics_base_url') is not None:
-        params['base_url'] = params.pop('analytics_base_url')
-    else:
-        params['base_url'] = 'https://api.planet.com/analytics/'
-
-    client = api.ClientV1(**params)
-    return client
-
-
 def configure_logging(verbosity):
     '''configure logging via verbosity level of between 0 and 2 corresponding
     to log levels warning, info and debug respectfully.'''
@@ -75,13 +62,8 @@ def configure_logging(verbosity):
 @click.option('-u', '--base-url', envvar='PL_API_BASE_URL',
               help='Change the base Planet API URL or ENV PL_API_BASE_URL'
                    ' - Default https://api.planet.com/')
-@click.option('-au', '--analytics-base-url',
-              envvar='PL_ANALYTICS_API_BASE_URL',
-              help=('Change the base Planet API URL or ENV '
-                    'PL_ANALYTICS_API_BASE_URL'
-                    ' - Default https://api.planet.com/analytics'))
 @click.version_option(version=__version__, message='%(version)s')
-def cli(context, verbose, api_key, base_url, analytics_base_url, workers):
+def cli(context, verbose, api_key, base_url, workers):
     '''Planet API Client'''
 
     configure_logging(verbose)
@@ -91,8 +73,6 @@ def cli(context, verbose, api_key, base_url, analytics_base_url, workers):
     client_params['workers'] = workers
     if base_url:
         client_params['base_url'] = base_url
-    if analytics_base_url:
-        client_params['analytics_base_url'] = analytics_base_url
 
 
 @cli.command('help')
diff --git a/planet/scripts/v1.py b/planet/scripts/v1.py
index 0c939c3..1670a8d 100644
--- a/planet/scripts/v1.py
+++ b/planet/scripts/v1.py
@@ -18,7 +18,6 @@ import json
 from .cli import (
     cli,
     clientv1,
-    analytics_client_v1
 )
 from .opts import (
     asset_type_option,
@@ -364,7 +363,7 @@ def analytics():
 @pretty
 def health(pretty):
     '''Check that we can connect to the API'''
-    cl = analytics_client_v1()
+    cl = clientv1()
     click.echo('Using base URL: {}'.format(cl.base_url))
     response = cl.check_analytics_connection()
     echo_json_response(response, pretty)
@@ -378,7 +377,7 @@ def conformance(pretty):
     :param pretty:
     :return:
     '''
-    cl = analytics_client_v1()
+    cl = clientv1()
     response = cl.wfs_conformance()
     echo_json_response(response, pretty)
 
@@ -396,7 +395,7 @@ def feeds():
 @pretty
 def list_feeds(pretty, limit, stats):
     '''List all subscriptions user has access to.'''
-    cl = analytics_client_v1()
+    cl = clientv1()
     response = cl.list_analytic_feeds(stats)
     echo_json_response(response, pretty, limit)
 
@@ -405,8 +404,8 @@ def list_feeds(pretty, limit, stats):
 @click.argument('feed_id')
 def get_mosaic_list_for_feed(feed_id):
     '''List mosaics linked to feed'''
-    analytics_client = analytics_client_v1()
-    feed_info = analytics_client.get_feed_info(feed_id).get()
+    cl = clientv1()
+    feed_info = cl.get_feed_info(feed_id).get()
 
     for type_ in ['target', 'source']:
         feed_image_conf = feed_info.get(type_)
@@ -418,8 +417,7 @@ def get_mosaic_list_for_feed(feed_id):
 
         mosaic_series = feed_image_conf['config']['series_id']
 
-        client = clientv1()
-        mosaics = client.get_mosaics_for_series(mosaic_series)
+        mosaics = cl.get_mosaics_for_series(mosaic_series)
 
         click.echo('{} mosaics:'.format(type_))
         for mosaic in mosaics.get()['mosaics']:
@@ -431,7 +429,7 @@ def get_mosaic_list_for_feed(feed_id):
 @pretty
 def get_feed_info(feed_id, pretty):
     '''Get metadata for specific feed.'''
-    cl = analytics_client_v1()
+    cl = clientv1()
     feed_info = cl.get_feed_info(feed_id)
     echo_json_response(feed_info, pretty)
 
@@ -450,7 +448,7 @@ def subscriptions():
 @pretty
 def list_subscriptions(pretty, limit, feed_id):
     '''List all subscriptions user has access to.'''
-    cl = analytics_client_v1()
+    cl = clientv1()
     response = cl.list_analytic_subscriptions(feed_id)
     echo_json_response(response, pretty, limit)
 
@@ -459,9 +457,9 @@ def list_subscriptions(pretty, limit, feed_id):
 @click.argument('subscription_id')
 def get_mosaic_list_for_subscription(subscription_id):
     '''List mosaics linked to feed'''
-    analytics_client = analytics_client_v1()
-    sub_info = analytics_client.get_subscription_info(subscription_id).get()
-    feed_info = analytics_client.get_feed_info(sub_info['feedID']).get()
+    cl = clientv1()
+    sub_info = cl.get_subscription_info(subscription_id).get()
+    feed_info = cl.get_feed_info(sub_info['feedID']).get()
 
     for type_ in ['target', 'source']:
         feed_image_conf = feed_info.get(type_)
@@ -473,8 +471,7 @@ def get_mosaic_list_for_subscription(subscription_id):
 
         mosaic_series = feed_image_conf['config']['series_id']
 
-        client = clientv1()
-        mosaics = client.get_mosaics_for_series(mosaic_series)
+        mosaics = cl.get_mosaics_for_series(mosaic_series)
 
         click.echo('{} mosaics:'.format(type_))
         for mosaic in mosaics.get()['mosaics']:
@@ -486,7 +483,7 @@ def get_mosaic_list_for_subscription(subscription_id):
 @pretty
 def get_subscription_info(subscription_id, pretty):
     '''Get metadata for specific subscription.'''
-    cl = analytics_client_v1()
+    cl = clientv1()
     sub_info = cl.get_subscription_info(subscription_id)
     echo_json_response(sub_info, pretty)
 
@@ -502,7 +499,7 @@ def collections():
 @pretty
 def list_collections(pretty, limit):
     '''List all collections user has access to.'''
-    cl = analytics_client_v1()
+    cl = clientv1()
     response = cl.list_analytic_collections()
     echo_json_response(response, pretty, limit)
 
@@ -511,9 +508,9 @@ def list_collections(pretty, limit):
 @click.argument('subscription_id')
 def get_mosaic_list_for_collection(subscription_id):
     '''List mosaics linked to feed'''
-    analytics_client = analytics_client_v1()
-    sub_info = analytics_client.get_subscription_info(subscription_id).get()
-    feed_info = analytics_client.get_feed_info(sub_info['feedID']).get()
+    cl = clientv1()
+    sub_info = cl.get_subscription_info(subscription_id).get()
+    feed_info = cl.get_feed_info(sub_info['feedID']).get()
 
     for type_ in ['target', 'source']:
         feed_image_conf = feed_info.get(type_)
@@ -525,8 +522,7 @@ def get_mosaic_list_for_collection(subscription_id):
 
         mosaic_series = feed_image_conf['config']['series_id']
 
-        client = clientv1()
-        mosaics = client.get_mosaics_for_series(mosaic_series)
+        mosaics = cl.get_mosaics_for_series(mosaic_series)
 
         click.echo('{} mosaics:'.format(type_))
         for mosaic in mosaics.get()['mosaics']:
@@ -538,7 +534,7 @@ def get_mosaic_list_for_collection(subscription_id):
 @pretty
 def get_collection_info(subscription_id, pretty):
     '''Get metadata for specific collection.'''
-    cl = analytics_client_v1()
+    cl = clientv1()
     sub_info = cl.get_collection_info(subscription_id)
     echo_json_response(sub_info, pretty)
 
@@ -548,7 +544,7 @@ def get_collection_info(subscription_id, pretty):
 @pretty
 def get_resource_types(subscription_id, pretty):
     '''Get available resource types.'''
-    cl = analytics_client_v1()
+    cl = clientv1()
     # Assumes that all features in a collection have the same list of
     # associated resource types
     features = cl.list_collection_features(subscription_id,
@@ -601,7 +597,7 @@ def features():
 def list_features(subscription_id, pretty, limit, rbox, bbox, time_range,
                   before, after):
     '''Request feature list for a particular subscription, 100 at a time.'''
-    cl = analytics_client_v1()
+    cl = clientv1()
     bbox = bbox or rbox
     features = cl.list_collection_features(subscription_id, bbox, time_range,
                                            before, after)
@@ -633,7 +629,7 @@ def list_features(subscription_id, pretty, limit, rbox, bbox, time_range,
 def list_features_all(subscription_id, pretty, rbox, bbox, time_range, before,
                       after):
     '''Return every available feature for a particular subscription'''
-    cl = analytics_client_v1()
+    cl = clientv1()
     bbox = bbox or rbox
     features = cl.list_collection_features(subscription_id, bbox, time_range,
                                            before, after)
@@ -653,10 +649,7 @@ def list_features_all(subscription_id, pretty, rbox, bbox, time_range, before,
 def get_associated_resource(subscription_id, feature_id, resource_type, pretty,
                             dest):
     '''Request resources for a particular subscription/feature combination.'''
-    # Note that this command will not work for a custom analytics URL, as the
-    # underlying API call is a redirect to the Data API and Mosaics API.
-    # See https://github.com/kennethreitz/requests/issues/2949 for more info.
-    cl = analytics_client_v1()
+    cl = clientv1()
     if resource_type in ['target-quad', 'source-quad']:
         msg_format = 'Requesting {} for {}/{}, destination directory is: {}'
         click.echo(msg_format.format(


Test patch:
diff --git a/tests/test_client.py b/tests/test_client.py
index 25a3f49..5c4449b 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -199,14 +199,14 @@ def test_stats(client):
 
 
 def test_list_analytic_feeds(client):
-    url = client.base_url + 'feeds'
+    url = client.base_url + 'analytics/feeds'
     assert_simple_request(url,
                           client.list_analytic_feeds,
                           (False,))
 
 
 def test_get_feed_info(client):
-    url = client.base_url + 'feeds/feed-id'
+    url = client.base_url + 'analytics/feeds/feed-id'
     assert_simple_request(url,
                           client.get_feed_info,
                           ('feed-id',))
@@ -214,35 +214,35 @@ def test_get_feed_info(client):
 
 @pytest.mark.parametrize('feed_id', [None, 'feed-id'])
 def test_list_analytic_subscriptions(client, feed_id):
-    url = client.base_url + 'subscriptions'
+    url = client.base_url + 'analytics/subscriptions'
     assert_simple_request(url,
                           client.list_analytic_subscriptions,
                           (feed_id,))
 
 
 def test_get_subscription_info(client):
-    url = client.base_url + 'subscriptions/sub-id'
+    url = client.base_url + 'analytics/subscriptions/sub-id'
     assert_simple_request(url,
                           client.get_subscription_info,
                           ('sub-id',))
 
 
 def test_list_collections(client):
-    url = client.base_url + 'collections'
+    url = client.base_url + 'analytics/collections'
     assert_simple_request(url,
                           client.list_analytic_collections,
                           ())
 
 
 def test_get_collection_info(client):
-    url = client.base_url + 'collections/sub-id'
+    url = client.base_url + 'analytics/collections/sub-id'
     assert_simple_request(url,
                           client.get_collection_info,
                           ('sub-id',))
 
 
 def test_list_features(client):
-    url = client.base_url + 'collections/sub-id/items'
+    url = client.base_url + 'analytics/collections/sub-id/items'
     assert_simple_request(url,
                           client.list_collection_features,
                           ('sub-id', None, None))
@@ -253,8 +253,8 @@ def test_get_associated_resource(client):
     sid = 'sub-id'
     fid = 'feature-id'
     rid = 'source-image-info'
-    url = client.base_url + 'collections/{}/items/{}/resources/{}'.format(
-        sid, fid, rid
+    url = '{}analytics/collections/{}/items/{}/resources/{}'.format(
+        client.base_url, sid, fid, rid
     )
     assert_simple_request(url,
                           client.get_associated_resource_for_analytic_feature,
diff --git a/tests/test_v1_cli.py b/tests/test_v1_cli.py
index d3e8bb2..6e1aacf 100644
--- a/tests/test_v1_cli.py
+++ b/tests/test_v1_cli.py
@@ -28,13 +28,6 @@ def client():
         yield client
 
 
-@pytest.fixture(scope="module")
-def analytics_client():
-    client = MagicMock(name='analytics_client', spec=ClientV1)
-    with patch('planet.scripts.v1.analytics_client_v1', lambda: client):
-        yield client
-
-
 def assert_success(result, expected_output, exit_code=0):
     if result.exception:
         print(result.output)
@@ -273,11 +266,11 @@ def test_geom_filter(runner, client):
 # For analytics entrypoints, only testing those entrypoints that have any logic
 # beyond just "make client function call"
 
-def test_get_mosaics_list_for_feed(runner, analytics_client, client):
+def test_get_mosaics_list_for_feed(runner, client):
     feeds_blob = json.loads(read_fixture('feeds.json'))
     mosaics_blob = json.loads(read_fixture('list-mosaics.json'))
 
-    configure_response(analytics_client.get_feed_info,
+    configure_response(client.get_feed_info,
                        json.dumps(feeds_blob['data'][0]))
     configure_response(client.get_mosaics_for_series,
                        json.dumps(mosaics_blob))
@@ -291,14 +284,14 @@ def test_get_mosaics_list_for_feed(runner, analytics_client, client):
     )
 
 
-def test_get_mosaics_list_for_subscription(runner, analytics_client, client):
+def test_get_mosaics_list_for_subscription(runner, client):
     sub_blob = json.loads(read_fixture('subscriptions.json'))
     feeds_blob = json.loads(read_fixture('feeds.json'))
     mosaics_blob = json.loads(read_fixture('list-mosaics.json'))
 
-    configure_response(analytics_client.get_subscription_info,
+    configure_response(client.get_subscription_info,
                        json.dumps(sub_blob['data'][0]))
-    configure_response(analytics_client.get_feed_info,
+    configure_response(client.get_feed_info,
                        json.dumps(feeds_blob['data'][0]))
     configure_response(client.get_mosaics_for_series,
                        json.dumps(mosaics_blob))
@@ -312,14 +305,14 @@ def test_get_mosaics_list_for_subscription(runner, analytics_client, client):
     )
 
 
-def test_get_mosaics_list_for_collection(runner, analytics_client, client):
+def test_get_mosaics_list_for_collection(runner, client):
     sub_blob = json.loads(read_fixture('subscriptions.json'))
     feeds_blob = json.loads(read_fixture('feeds.json'))
     mosaics_blob = read_fixture('list-mosaics.json')
 
-    configure_response(analytics_client.get_subscription_info,
+    configure_response(client.get_subscription_info,
                        json.dumps(sub_blob['data'][0]))
-    configure_response(analytics_client.get_feed_info,
+    configure_response(client.get_feed_info,
                        json.dumps(feeds_blob['data'][0]))
     configure_response(client.get_mosaics_for_series,
                        mosaics_blob)
@@ -333,9 +326,9 @@ def test_get_mosaics_list_for_collection(runner, analytics_client, client):
     )
 
 
-def test_get_collection_resource_types(runner, analytics_client):
+def test_get_collection_resource_types(runner, client):
     feature_blob = read_fixture('af_features.json')
-    configure_response(analytics_client.list_collection_features,
+    configure_response(client.list_collection_features,
                        feature_blob)
 
     expected_output = "Found resource types: ['source-image-info']\n"
@@ -347,9 +340,9 @@ def test_get_collection_resource_types(runner, analytics_client):
     )
 
 
-def test_get_associated_resource(runner, analytics_client):
+def test_get_associated_resource(runner, client):
     configure_response(
-        analytics_client.get_associated_resource_for_analytic_feature,
+        client.get_associated_resource_for_analytic_feature,
         '{"chowda":true}',
     )
     assert_success(