Skip to content
This repository was archived by the owner on Jan 5, 2026. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,25 @@
import base64
from exceptions import InvalidGoogleCredentials

CLIENT_SECRET_APIKEY = 'key='


class GoogleMapsClientFactory():
clients = {}

@classmethod
def get(cls, client_id, client_secret, channel=None):
def get(cls, client_id=None, client_secret=None, channel=None):
cache_key = "{}:{}:{}".format(client_id, client_secret, channel)
client = cls.clients.get(cache_key)
if not client:
if client_id:
if client_secret.startswith(CLIENT_SECRET_APIKEY):
client = googlemaps.Client(key=client_secret.replace(CLIENT_SECRET_APIKEY, ''))
else:
cls.assert_valid_crendentials(client_secret)
client = googlemaps.Client(
client_id=client_id,
client_secret=client_secret,
channel=channel)
else:
client = googlemaps.Client(key=client_secret)
cls.clients[cache_key] = client
return client

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@
class GoogleMapsGeocoder():

def __init__(self, client_id, client_secret, logger):
if client_id is None:
self._logger = logger
if client_id is None and client_secret is None:
raise InvalidGoogleCredentials
self.client_id, self.channel = self.parse_client_id(client_id)
self.client_secret = client_secret
self.geocoder = GoogleMapsClientFactory.get(self.client_id, self.client_secret, self.channel)
self._logger = logger

def geocode(self, searchtext, city=None, state=None, country=None):
return self.geocode_meta(searchtext, city, state, country)[0]
Expand Down Expand Up @@ -100,6 +100,9 @@ def _build_optional_parameters(self, city=None, state=None,
return optional_params

def parse_client_id(self, client_id):
if not client_id:
return None, None

arguments = parse_qs(client_id)
client = arguments['client'][0] if arguments.has_key('client') else client_id
channel = arguments['channel'][0] if arguments.has_key('channel') else None
Expand Down
2 changes: 1 addition & 1 deletion server/lib/python/cartodb_services/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
setup(
name='cartodb_services',

version='0.21.4',
version='0.21.5',

description='CartoDB Services API Python Library',

Expand Down
5 changes: 5 additions & 0 deletions server/lib/python/cartodb_services/test/credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,8 @@ def mapbox_api_key():
def tomtom_api_key():
"""Returns TomTom API key. Requires setting TOMTOM_API_KEY environment variable."""
return os.environ['TOMTOM_API_KEY']


def google_api_key():
"""Returns Google API key. Requires setting GOOGLE_API_KEY environment variable."""
return os.environ['GOOGLE_API_KEY']
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,18 @@ def test_consecutive_calls_with_different_ids_return_different_clients(self):
client2 = GoogleMapsClientFactory.get(id2, key)
self.assertNotEqual(client1, client2)

def test_invalid_credentials(self):
def test_invalid_credentials_client_secret(self):
with self.assertRaises(InvalidGoogleCredentials):
GoogleMapsClientFactory.get('dummy_client_id', 'lalala')

def test_invalid_credentials_api_key_client(self):
with self.assertRaises(ValueError):
GoogleMapsClientFactory.get('fake_client', 'key=fake_apikey')

def test_invalid_credentials_api_key_noclient(self):
with self.assertRaises(ValueError):
GoogleMapsClientFactory.get(None, 'key=fake_apikey')

def test_credentials_with_dashes_can_be_valid(self):
client = GoogleMapsClientFactory.get('yet_another_dummy_client_id', 'Ola-k-ase---')
self.assertIsInstance(client, googlemaps.Client)
Expand All @@ -60,10 +68,6 @@ def test_credentials_with_underscores_can_be_valid(self):
client = GoogleMapsClientFactory.get('yet_another_dummy_client_id', 'Ola_k_ase___')
self.assertIsInstance(client, googlemaps.Client)

def test_invalid_credentials(self):
with self.assertRaises(InvalidGoogleCredentials):
GoogleMapsClientFactory.get('dummy_client_id', 'lalala')

def test_credentials_with_channel(self):
client = GoogleMapsClientFactory.get('yet_another_dummy_client_id', 'Ola_k_ase___', 'channel')
self.assertIsInstance(client, googlemaps.Client)
37 changes: 29 additions & 8 deletions server/lib/python/cartodb_services/test/test_googlegeocoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@
import requests_mock
from mock import Mock

from credentials import google_api_key
from cartodb_services.google import GoogleMapsGeocoder
from cartodb_services.google.exceptions import MalformedResult

requests_mock.Mocker.TEST_PREFIX = 'test_'


@requests_mock.Mocker()
class GoogleGeocoderTestCase(unittest.TestCase):
class GoogleGeocoderTestCase():
GOOGLE_MAPS_GEOCODER_URL = 'https://maps.googleapis.com/maps/api/geocode/json'

EMPTY_RESPONSE = """{
Expand Down Expand Up @@ -87,12 +87,6 @@ class GoogleGeocoderTestCase(unittest.TestCase):

MALFORMED_RESPONSE = """{"manolo": "escobar"}"""

def setUp(self):
logger = Mock()
self.geocoder = GoogleMapsGeocoder('dummy_client_id',
'MgxyOFxjZXIyOGO52jJlMzEzY1Oqy4hsO49E',
logger)

def test_geocode_address_with_valid_params(self, req_mock):
req_mock.register_uri('GET', self.GOOGLE_MAPS_GEOCODER_URL,
text=self.GOOD_RESPONSE)
Expand All @@ -119,6 +113,15 @@ def test_geocode_with_malformed_result(self, req_mock):
city='Madrid',
country='España')


@requests_mock.Mocker()
class GoogleGeocoderClientSecretTestCase(unittest.TestCase, GoogleGeocoderTestCase):
def setUp(self):
logger = Mock()
self.geocoder = GoogleMapsGeocoder('dummy_client_id',
'MgxyOFxjZXIyOGO52jJlMzEzY1Oqy4hsO49E',
logger)

def test_client_data_extraction(self, req_mock):
client_id, channel = self.geocoder.parse_client_id('dummy_client_id')
self.assertEqual(client_id, 'dummy_client_id')
Expand All @@ -133,3 +136,21 @@ def test_client_data_extraction_with_client_and_channel_parameter(self, req_mock
client_id, channel = self.geocoder.parse_client_id('client=gme-test&channel=testchannel')
self.assertEqual(client_id, 'gme-test')
self.assertEqual(channel, 'testchannel')


@requests_mock.Mocker()
class GoogleGeocoderApiKeyTestCase(unittest.TestCase, GoogleGeocoderTestCase):
def setUp(self):
logger = Mock()
self.geocoder = GoogleMapsGeocoder(None,
google_api_key(),
logger)


@requests_mock.Mocker()
class GoogleGeocoderClientApiKeyTestCase(unittest.TestCase, GoogleGeocoderTestCase):
def setUp(self):
logger = Mock()
self.geocoder = GoogleMapsGeocoder('fake_client_id',
google_api_key(),
logger)
17 changes: 17 additions & 0 deletions server/lib/python/cartodb_services/test/test_quota_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,23 @@ def test_should_check_org_mapbox_geocoder_quota_correctly(self):
qs.increment_success_service_use(amount=1500000)
assert qs.check_user_quota() is False

def test_should_check_user_google_geocoder_quota_correctly(self):
qs = self.__build_geocoder_quota_service('test_user',
provider='google')
qs.increment_success_service_use()
assert qs.check_user_quota() is True
qs.increment_success_service_use(amount=1500000)
assert qs.check_user_quota() is True # We don't check quota for google geocoder

def test_should_check_org_google_geocoder_quota_correctly(self):
qs = self.__build_geocoder_quota_service('test_user',
orgname='testorg',
provider='google')
qs.increment_success_service_use()
assert qs.check_user_quota() is True
qs.increment_success_service_use(amount=1500000)
assert qs.check_user_quota() is True # We don't check quota for google geocoder

def test_should_check_user_mapzen_routing_quota_correctly(self):
qs = self.__build_routing_quota_service('test_user', provider='mapzen')
qs.increment_success_service_use()
Expand Down