From 8a23c4323d7d5920aaf7bc6fcb59300ed41b421a Mon Sep 17 00:00:00 2001 From: Chris Arriola Date: Thu, 16 Jan 2020 12:55:33 -0800 Subject: [PATCH 1/4] feat: Adding experience_id support to Client class. --- .gitignore | 1 + googlemaps/client.py | 47 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 0d2efbbc..c4477ba5 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,4 @@ env googlemaps.egg-info *.egg .vscode/ +.idea/ diff --git a/googlemaps/client.py b/googlemaps/client.py index 9a195c3c..ac054917 100644 --- a/googlemaps/client.py +++ b/googlemaps/client.py @@ -39,12 +39,13 @@ except ImportError: # Python 2 from urllib import urlencode - +_X_GOOG_MAPS_EXPERIENCE_ID = "X-Goog-Maps-Experience-ID" _USER_AGENT = "GoogleGeoApiClientPython/%s" % googlemaps.__version__ _DEFAULT_BASE_URL = "https://maps.googleapis.com" _RETRIABLE_STATUSES = set([500, 503, 504]) + class Client(object): """Performs requests to the Google Maps API web services.""" @@ -52,7 +53,7 @@ def __init__(self, key=None, client_id=None, client_secret=None, timeout=None, connect_timeout=None, read_timeout=None, retry_timeout=60, requests_kwargs=None, queries_per_second=50, channel=None, - retry_over_query_limit=True): + retry_over_query_limit=True, experience_id=None): """ :param key: Maps API key. Required, unless "client_id" and "client_secret" are set. @@ -99,6 +100,10 @@ def __init__(self, key=None, client_id=None, client_secret=None, retried. Defaults to True. :type retry_over_query_limit: bool + :param experience_id: The value for the HTTP header field name + 'X-Goog-Maps-Experience-ID'. + :type experience_id: str + :raises ValueError: when either credentials are missing, incomplete or invalid. :raises NotImplementedError: if connect_timeout and read_timeout are @@ -150,7 +155,7 @@ def __init__(self, key=None, client_id=None, client_secret=None, self.retry_timeout = timedelta(seconds=retry_timeout) self.requests_kwargs = requests_kwargs or {} headers = self.requests_kwargs.pop('headers', {}) - headers.update({"User-Agent": _USER_AGENT}) + headers.update({"User-Agent": _USER_AGENT}) self.requests_kwargs.update({ "headers": headers, "timeout": self.timeout, @@ -160,6 +165,42 @@ def __init__(self, key=None, client_id=None, client_secret=None, self.queries_per_second = queries_per_second self.retry_over_query_limit = retry_over_query_limit self.sent_times = collections.deque("", queries_per_second) + self.set_experience_id(experience_id) + + def set_experience_id(self, *experience_id_args): + """Sets the value for the HTTP header field name + 'X-Goog-Maps-Experience-ID' to be used on subsequent API calls. + + :param experience_id_args: the experience ID + :type experience_id_args: string varargs + """ + if len(experience_id_args) == 0 or experience_id_args[0] is None: + self.clear_experience_id() + return + + headers = self.requests_kwargs.pop("headers", {}) + headers[_X_GOOG_MAPS_EXPERIENCE_ID] = ",".join(experience_id_args) + self.requests_kwargs["headers"] = headers + + def get_experience_id(self): + """Gets the experience ID for the HTTP header field name + 'X-Goog-Maps-Experience-ID' + + :return: The experience ID if set + :rtype: str + """ + headers = self.requests_kwargs.get("headers", {}) + return headers.get(_X_GOOG_MAPS_EXPERIENCE_ID, None) + + def clear_experience_id(self): + """Clears the experience ID for the HTTP header field name + 'X-Goog-Maps-Experience-ID' if set. + """ + headers = self.requests_kwargs.get("headers") + if headers is None: + return + headers.pop(_X_GOOG_MAPS_EXPERIENCE_ID, {}) + self.requests_kwargs["headers"] = headers def _request(self, url, params, first_request_time=None, retry_counter=0, base_url=_DEFAULT_BASE_URL, accepts_clientid=True, From b50e4e9c377ce747a92881af2342c3d5ffeddb05 Mon Sep 17 00:00:00 2001 From: Chris Arriola Date: Thu, 16 Jan 2020 17:16:13 -0800 Subject: [PATCH 2/4] Writing tests. --- googlemaps/test/test_client.py | 55 ++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/googlemaps/test/test_client.py b/googlemaps/test/test_client.py index 90d83b3e..39c7742f 100644 --- a/googlemaps/test/test_client.py +++ b/googlemaps/test/test_client.py @@ -26,6 +26,7 @@ import googlemaps import googlemaps.client as _client import googlemaps.test as _test +from googlemaps.client import _X_GOOG_MAPS_EXPERIENCE_ID class ClientTest(_test.TestCase): @@ -291,6 +292,60 @@ def test_requests_version(self): googlemaps.Client(**client_args_timeout) googlemaps.Client(**client_args) + def test_single_experience_id(self): + experience_id1 = "Exp1" + client = googlemaps.Client(key="AIzaasdf", experience_id=experience_id1) + self.assertEqual(experience_id1, client.get_experience_id()) + + experience_id2 = "Exp2" + client.set_experience_id(experience_id2) + self.assertEqual(experience_id2, client.get_experience_id()) + + def test_multiple_experience_id(self): + client = googlemaps.Client(key="AIzaasdf") + + experience_id1 = "Exp1" + experience_id2 = "Exp2" + client.set_experience_id(experience_id1, experience_id2) + + result = "%s,%s" % (experience_id1, experience_id2) + self.assertEqual(result, client.get_experience_id()) + + def test_no_experience_id(self): + client = googlemaps.Client(key="AIzaasdf") + self.assertIsNone(client.get_experience_id()) + + def test_clearing_experience_id(self): + client = googlemaps.Client(key="AIzaasdf") + client.set_experience_id("ExpId") + client.clear_experience_id() + self.assertIsNone(client.get_experience_id()) + + @responses.activate + def _perform_mock_request(self, experience_id=None): + # Mock response + responses.add(responses.GET, + "https://maps.googleapis.com/maps/api/geocode/json", + body='{"status":"OK","results":[]}', + status=200, + content_type="application/json") + + # Perform network call + client = googlemaps.Client(key="AIzaasdf") + client.set_experience_id(experience_id) + client.geocode("Sesame St.") + return responses.calls[0].request + + def test_experience_id_in_header(self): + experience_id = "Exp1" + request = self._perform_mock_request(experience_id) + header_value = request.headers[_X_GOOG_MAPS_EXPERIENCE_ID] + self.assertEqual(experience_id, header_value) + + def test_experience_id_no_in_header(self): + request = self._perform_mock_request() + self.assertIsNone(request.headers.get(_X_GOOG_MAPS_EXPERIENCE_ID)) + @responses.activate def test_no_retry_over_query_limit(self): responses.add(responses.GET, From 562e233fa9c5f1f3b90a60247a4891a841dd1752 Mon Sep 17 00:00:00 2001 From: Chris Arriola Date: Fri, 17 Jan 2020 12:02:26 -0800 Subject: [PATCH 3/4] Adding sample tags. --- googlemaps/test/test_client.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/googlemaps/test/test_client.py b/googlemaps/test/test_client.py index 39c7742f..9722c18d 100644 --- a/googlemaps/test/test_client.py +++ b/googlemaps/test/test_client.py @@ -22,6 +22,7 @@ import responses import requests +import uuid import googlemaps import googlemaps.client as _client @@ -321,6 +322,33 @@ def test_clearing_experience_id(self): client.clear_experience_id() self.assertIsNone(client.get_experience_id()) + def test_experience_id_sample(self): + # [START maps_experience_id] + experience_id = str(uuid.uuid4()) + + # instantiate client with experience id + client = googlemaps.Client( + key="AIza-Maps-API-Key", + experience_id=experience_id + ) + + # clear the current experience id + client.clear_experience_id() + + # set a new experience id + other_experience_id = str(uuid.uuid4()) + client.set_experience_id(experience_id, other_experience_id) + + # make API request, the client will set the header + # X-GOOG-MAPS-EXPERIENCE-ID: experienceId,otherExperienceId + + # get current experience id + ids = client.get_experience_id() + # [END maps_experience_id] + + result = "%s,%s" % (experience_id, other_experience_id) + self.assertEqual(result, ids) + @responses.activate def _perform_mock_request(self, experience_id=None): # Mock response From 09d06841cd4b516e2cf9b655b3f748fcabaeb311 Mon Sep 17 00:00:00 2001 From: Chris Arriola Date: Fri, 17 Jan 2020 12:13:20 -0800 Subject: [PATCH 4/4] Use underscore. --- googlemaps/test/test_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/googlemaps/test/test_client.py b/googlemaps/test/test_client.py index 9722c18d..9c689b67 100644 --- a/googlemaps/test/test_client.py +++ b/googlemaps/test/test_client.py @@ -340,7 +340,7 @@ def test_experience_id_sample(self): client.set_experience_id(experience_id, other_experience_id) # make API request, the client will set the header - # X-GOOG-MAPS-EXPERIENCE-ID: experienceId,otherExperienceId + # X-GOOG-MAPS-EXPERIENCE-ID: experience_id,other_experience_id # get current experience id ids = client.get_experience_id()