diff --git a/.travis.yml b/.travis.yml index 72420ba..5dcebb5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ python: - "2.7" - "3.5" - "3.6" - - "pypy" + # - "pypy3" # out of date OpenSSL error matrix: include: diff --git a/Changes.txt b/Changes.txt index 5f1309b..3eb443c 100644 --- a/Changes.txt +++ b/Changes.txt @@ -1,3 +1,7 @@ +v1.2.1 Wed 6 May 2020 + Ensure OpenSSL is available on installation + Add exponential backoff to HTTP requests + v1.2 Sun 9 Jun 2019 Use https as default Handle 401 and 403 exceptions diff --git a/opencage/__init__.py b/opencage/__init__.py index d4043d5..8d050a0 100644 --- a/opencage/__init__.py +++ b/opencage/__init__.py @@ -2,4 +2,4 @@ __author__ = "OpenCage Data" __email__ = 'info@opencagedata.com' -__version__ = '1.0.0' +__version__ = '1.2.1' diff --git a/opencage/geocoder.py b/opencage/geocoder.py index aea7ebc..0465056 100644 --- a/opencage/geocoder.py +++ b/opencage/geocoder.py @@ -4,8 +4,13 @@ from decimal import Decimal import collections +import os import six import requests +import backoff + +def backoff_max_time(): + return int(os.environ.get('BACKOFF_MAX_TIME', '120')) class OpenCageGeocodeError(Exception): @@ -142,7 +147,29 @@ def geocode(self, query, **kwargs): # Add user parameters data.update(kwargs) - response = requests.get(self.url, params=data) + response = self._opencage_request(data) + + return floatify_latlng(response['results']) + + def reverse_geocode(self, lat, lng, **kwargs): + """ + Given a latitude & longitude, return an address for that point from OpenCage's Geocoder. + + :param lat: Latitude + :param lng: Longitude + :return: Results from OpenCageData + :rtype: dict + :raises RateLimitExceededError: if you have exceeded the number of queries you can make. Exception says when you can try again + :raises UnknownError: if something goes wrong with the OpenCage API + """ + return self.geocode(_query_for_reverse_geocoding(lat, lng), **kwargs) + + @backoff.on_exception( + backoff.expo, + (UnknownError, requests.exceptions.RequestException), + max_tries=5, max_time=backoff_max_time) + def _opencage_request(self, params): + response = requests.get(self.url, params=params) if (response.status_code == 401): raise NotAuthorizedError() @@ -166,22 +193,7 @@ def geocode(self, query, **kwargs): if 'results' not in response_json: raise UnknownError("JSON from API doesn't have a 'results' key") - - return floatify_latlng(response_json['results']) - - def reverse_geocode(self, lat, lng, **kwargs): - """ - Given a latitude & longitude, return an address for that point from OpenCage's Geocoder. - - :param lat: Latitude - :param lng: Longitude - :return: Results from OpenCageData - :rtype: dict - :raises RateLimitExceededError: if you have exceeded the number of queries you can make. Exception says when you can try again - :raises UnknownError: if something goes wrong with the OpenCage API - """ - return self.geocode(_query_for_reverse_geocoding(lat, lng), **kwargs) - + return response_json def _query_for_reverse_geocoding(lat, lng): """ diff --git a/setup.py b/setup.py index 5295692..948aa72 100644 --- a/setup.py +++ b/setup.py @@ -27,7 +27,7 @@ setup( name="opencage", - version="1.2", + version="1.2.1", description="Simple wrapper module for the OpenCage Geocoder API", long_description=long_description, long_description_content_type='text/markdown', @@ -56,6 +56,8 @@ install_requires=[ 'Requests>=2.2.0', 'six>=1.4.0', + 'pyopenssl>=0.15.1', + 'backoff>=1.10.0' ], test_suite='tests', tests_require=[ diff --git a/tests.py b/tests.py index e8c1d4c..c2c2550 100644 --- a/tests.py +++ b/tests.py @@ -6,6 +6,7 @@ import unittest +import os import six import httpretty @@ -13,6 +14,8 @@ from opencage.geocoder import InvalidInputError, RateLimitExceededError, UnknownError, ForbiddenError, NotAuthorizedError from opencage.geocoder import floatify_latlng, _query_for_reverse_geocoding +# reduce maximum backoff retry time from 120s to 1s +os.environ['BACKOFF_MAX_TIME'] = '1' class OpenCageGeocodeTestCase(unittest.TestCase): def setUp(self):