From 600025087d80bca127325665e0cfd1e61e65fb12 Mon Sep 17 00:00:00 2001 From: Uman Shahzad Date: Sat, 1 Jun 2019 02:37:07 +0500 Subject: [PATCH 1/3] Run `black` on the codebase. --- ipinfo/cache/default.py | 1 + ipinfo/details.py | 3 ++- ipinfo/exceptions.py | 2 ++ ipinfo/handler.py | 54 ++++++++++++++++++++++++----------------- tests/details_test.py | 1 + tests/handler_test.py | 3 ++- 6 files changed, 40 insertions(+), 24 deletions(-) diff --git a/ipinfo/cache/default.py b/ipinfo/cache/default.py index 0d58c05..c0b12df 100644 --- a/ipinfo/cache/default.py +++ b/ipinfo/cache/default.py @@ -3,6 +3,7 @@ """ import cachetools + from .interface import CacheInterface diff --git a/ipinfo/details.py b/ipinfo/details.py index 3712d71..6bda5e8 100644 --- a/ipinfo/details.py +++ b/ipinfo/details.py @@ -2,6 +2,7 @@ Details returned by the IPinfo service. """ + class Details: """Encapsulates data for single IP address.""" @@ -14,7 +15,7 @@ def __getattr__(self, attr): if attr in self.details: return self.details[attr] else: - raise AttributeError('{} is not a valid attribute of Details'.format(attr)) + raise AttributeError("{} is not a valid attribute of Details".format(attr)) @property def all(self): diff --git a/ipinfo/exceptions.py b/ipinfo/exceptions.py index a8c3787..2cebde1 100644 --- a/ipinfo/exceptions.py +++ b/ipinfo/exceptions.py @@ -2,6 +2,8 @@ Exceptions thrown by the IPinfo service. """ + class RequestQuotaExceededError(Exception): """Error indicating that users monthly request quota has been passed.""" + pass diff --git a/ipinfo/handler.py b/ipinfo/handler.py index 0473f58..a4cc3fa 100644 --- a/ipinfo/handler.py +++ b/ipinfo/handler.py @@ -5,8 +5,10 @@ import ipaddress import json import os -import requests import sys + +import requests + from .cache.default import DefaultCache from .details import Details from .exceptions import RequestQuotaExceededError @@ -18,35 +20,37 @@ class Handler: and maintains access to cache. """ - API_URL = 'https://ipinfo.io' + API_URL = "https://ipinfo.io" CACHE_MAXSIZE = 4096 CACHE_TTL = 60 * 60 * 24 - COUNTRY_FILE_DEFAULT = 'countries.json' + COUNTRY_FILE_DEFAULT = "countries.json" REQUEST_TIMEOUT_DEFAULT = 2 def __init__(self, access_token=None, **kwargs): """Initialize the Handler object with country name list and the cache initialized.""" self.access_token = access_token - self.countries = self._read_country_names(kwargs.get('countries_file')) + self.countries = self._read_country_names(kwargs.get("countries_file")) - self.request_options = kwargs.get('request_options', {}) - if 'timeout' not in self.request_options: - self.request_options['timeout'] = self.REQUEST_TIMEOUT_DEFAULT + self.request_options = kwargs.get("request_options", {}) + if "timeout" not in self.request_options: + self.request_options["timeout"] = self.REQUEST_TIMEOUT_DEFAULT - if 'cache' in kwargs: - self.cache = kwargs['cache'] + if "cache" in kwargs: + self.cache = kwargs["cache"] else: - cache_options = kwargs.get('cache_options', {}) - maxsize = cache_options.get('maxsize', self.CACHE_MAXSIZE) - ttl = cache_options.get('ttl', self.CACHE_TTL) + cache_options = kwargs.get("cache_options", {}) + maxsize = cache_options.get("maxsize", self.CACHE_MAXSIZE) + ttl = cache_options.get("ttl", self.CACHE_TTL) self.cache = DefaultCache(maxsize, ttl, **cache_options) def getDetails(self, ip_address=None): """Get details for specified IP address as a Details object.""" raw_details = self._requestDetails(ip_address) - raw_details['country_name'] = self.countries.get(raw_details.get('country')) - raw_details['ip_address'] = ipaddress.ip_address(raw_details.get('ip')) - raw_details['latitude'], raw_details['longitude'] = self._read_coords(raw_details.get('loc')) + raw_details["country_name"] = self.countries.get(raw_details.get("country")) + raw_details["ip_address"] = ipaddress.ip_address(raw_details.get("ip")) + raw_details["latitude"], raw_details["longitude"] = self._read_coords( + raw_details.get("loc") + ) return Details(raw_details) def _requestDetails(self, ip_address=None): @@ -54,9 +58,11 @@ def _requestDetails(self, ip_address=None): if ip_address not in self.cache: url = self.API_URL if ip_address: - url += '/' + ip_address + url += "/" + ip_address - response = requests.get(url, headers=self._get_headers(), **self.request_options) + response = requests.get( + url, headers=self._get_headers(), **self.request_options + ) if response.status_code == 429: raise RequestQuotaExceededError() response.raise_for_status() @@ -67,18 +73,20 @@ def _requestDetails(self, ip_address=None): def _get_headers(self): """Built headers for request to IPinfo API.""" headers = { - 'user-agent': 'IPinfoClient/Python{version}/1.0'.format(version=sys.version_info[0]), - 'accept': 'application/json' + "user-agent": "IPinfoClient/Python{version}/1.0".format( + version=sys.version_info[0] + ), + "accept": "application/json", } if self.access_token: - headers['authorization'] = 'Bearer {}'.format(self.access_token) + headers["authorization"] = "Bearer {}".format(self.access_token) return headers def _read_coords(self, location): lat, lon = None, None - coords = tuple(location.split(',')) if location else '' + coords = tuple(location.split(",")) if location else "" if len(coords) == 2 and coords[0] and coords[1]: lat, lon = coords[0], coords[1] return lat, lon @@ -86,7 +94,9 @@ def _read_coords(self, location): def _read_country_names(self, countries_file=None): """Read list of countries from specified country file or default file.""" if not countries_file: - countries_file = os.path.join(os.path.dirname(__file__), self.COUNTRY_FILE_DEFAULT) + countries_file = os.path.join( + os.path.dirname(__file__), self.COUNTRY_FILE_DEFAULT + ) with open(countries_file) as f: countries_json = f.read() diff --git a/tests/details_test.py b/tests/details_test.py index 9026856..dd53c49 100644 --- a/tests/details_test.py +++ b/tests/details_test.py @@ -1,4 +1,5 @@ import pytest + from ipinfo.details import Details diff --git a/tests/handler_test.py b/tests/handler_test.py index 36dfa2f..9368e5b 100644 --- a/tests/handler_test.py +++ b/tests/handler_test.py @@ -1,7 +1,8 @@ +import ipaddress + from ipinfo.cache.default import DefaultCache from ipinfo.details import Details from ipinfo.handler import Handler -import ipaddress def test_init(): From 88622276bf051bede4b5e48ab469c0f4c4c281b4 Mon Sep 17 00:00:00 2001 From: Uman Shahzad Date: Sat, 1 Jun 2019 02:38:49 +0500 Subject: [PATCH 2/3] Fix issue with `six` not getting installed. We were doing it via installing *pytest* before, which although worked was definitely not preferable because it meant users would get pytest in their prod environments. Now we will do it by explicitly putting six in there. Eventually we will remove python2 support and can remove six. --- requirements.in | 13 +++++++------ requirements.txt | 21 +++++++++++---------- setup.py | 29 ++++++++++++++--------------- 3 files changed, 32 insertions(+), 31 deletions(-) diff --git a/requirements.in b/requirements.in index 7d37a91..6880d3b 100644 --- a/requirements.in +++ b/requirements.in @@ -1,7 +1,8 @@ -cachetools==2.1.0 -pip-tools==3.1.0 -pycodestyle==2.4.0 -pytest==3.8.2 -python-dateutil==2.6.1 -pytz==2017.2 +# For app requests>=2.18.4 +cachetools==3.1.1 +pytest==4.5.0 + +# For dev +pip-tools==3.7.0 +black==19.3b0 diff --git a/requirements.txt b/requirements.txt index 1a4e4f9..874fc8f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,23 +2,24 @@ # This file is autogenerated by pip-compile # To update, run: # -# pip-compile --no-index --output-file requirements.txt requirements.in +# pip-compile --no-index --output-file=requirements.txt requirements.in # +appdirs==1.4.3 # via black atomicwrites==1.3.0 # via pytest -attrs==19.1.0 # via pytest -cachetools==2.1.0 +attrs==19.1.0 # via black, pytest +black==19.3b0 +cachetools==3.1.1 certifi==2019.3.9 # via requests chardet==3.0.4 # via requests -click==7.0 # via pip-tools +click==7.0 # via black, pip-tools idna==2.8 # via requests more-itertools==6.0.0 # via pytest -pip-tools==3.1.0 +pip-tools==3.7.0 pluggy==0.9.0 # via pytest py==1.8.0 # via pytest -pycodestyle==2.4.0 -pytest==3.8.2 -python-dateutil==2.6.1 -pytz==2017.2 +pytest==4.5.0 requests==2.21.0 -six==1.12.0 # via pip-tools, pytest, python-dateutil +six==1.12.0 # via pip-tools, pytest +toml==0.10.0 # via black urllib3==1.24.1 # via requests +wcwidth==0.1.7 # via pytest diff --git a/setup.py b/setup.py index 83be578..d08d86f 100644 --- a/setup.py +++ b/setup.py @@ -8,18 +8,17 @@ You can visit our developer docs at https://ipinfo.io/developers. """ -setup(name='ipinfo', - version='1.1.1', - description='Official Python library for IPInfo', - long_description=long_description, - url='https://github.com/ipinfo/python', - author='James Timmins', - author_email='jameshtimmins@gmail.com', - license='Apache License 2.0', - packages=['ipinfo', 'ipinfo.cache'], - install_requires=[ - 'requests', - 'cachetools', - ], - include_package_data=True, - zip_safe=False) +setup( + name="ipinfo", + version="1.1.1", + description="Official Python library for IPInfo", + long_description=long_description, + url="https://github.com/ipinfo/python", + author="James Timmins", + author_email="jameshtimmins@gmail.com", + license="Apache License 2.0", + packages=["ipinfo", "ipinfo.cache"], + install_requires=["requests", "cachetools", "six"], + include_package_data=True, + zip_safe=False, +) From d2b611fe3e6da385a13a19a3c7c228d2688743ce Mon Sep 17 00:00:00 2001 From: Uman Shahzad Date: Sat, 1 Jun 2019 02:39:12 +0500 Subject: [PATCH 3/3] Patch fix version bump --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index d08d86f..804bddb 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ setup( name="ipinfo", - version="1.1.1", + version="1.1.2", description="Official Python library for IPInfo", long_description=long_description, url="https://github.com/ipinfo/python",