Skip to content

Commit 594caaa

Browse files
committed
Handle new credit errors
1 parent ea3a130 commit 594caaa

File tree

3 files changed

+56
-54
lines changed

3 files changed

+56
-54
lines changed

geoip2/errors.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,7 @@ class InvalidRequestError(GeoIP2Error):
4545

4646
class OutOfQueriesError(GeoIP2Error):
4747
"""Your account is out of funds for the service queried."""
48+
49+
50+
class PermissionRequiredError(GeoIP2Error):
51+
"""Your account does not have permission to access this service."""

geoip2/webservice.py

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,16 @@
2828
import sys
2929

3030
import requests
31+
32+
import geoip2
33+
import geoip2.models
34+
3135
from requests.utils import default_user_agent
3236

37+
from .errors import (AddressNotFoundError, AuthenticationError, GeoIP2Error,
38+
HTTPError, InvalidRequestError, OutOfQueriesError,
39+
PermissionRequiredError)
40+
3341
if sys.version_info[0] == 2 or (sys.version_info[0] == 3 and
3442
sys.version_info[1] < 3):
3543
import ipaddr as ipaddress # pylint:disable=F0401
@@ -38,11 +46,6 @@
3846
else:
3947
import ipaddress # pylint:disable=F0401
4048

41-
import geoip2
42-
import geoip2.models
43-
from .errors import (AddressNotFoundError, AuthenticationError, GeoIP2Error,
44-
HTTPError, InvalidRequestError, OutOfQueriesError)
45-
4649

4750
class Client(object):
4851
"""Creates a new client object.
@@ -103,7 +106,7 @@ def __init__(self,
103106
self._timeout = timeout
104107

105108
def city(self, ip_address='me'):
106-
"""This method calls the GeoIP2 Precision City endpoint.
109+
"""Call GeoIP2 Precision City endpoint with the specified IP.
107110
108111
:param ip_address: IPv4 or IPv6 address as a string. If no
109112
address is provided, the address that the web service is
@@ -115,7 +118,7 @@ def city(self, ip_address='me'):
115118
return self._response_for('city', geoip2.models.City, ip_address)
116119

117120
def country(self, ip_address='me'):
118-
"""This method calls the GeoIP2 Country endpoint.
121+
"""Call the GeoIP2 Country endpoint with the specified IP.
119122
120123
:param ip_address: IPv4 or IPv6 address as a string. If no address
121124
is provided, the address that the web service is called from will
@@ -127,7 +130,7 @@ def country(self, ip_address='me'):
127130
return self._response_for('country', geoip2.models.Country, ip_address)
128131

129132
def insights(self, ip_address='me'):
130-
"""This method calls the GeoIP2 Precision: Insights endpoint.
133+
"""Call the GeoIP2 Precision: Insights endpoint with the specified IP.
131134
132135
:param ip_address: IPv4 or IPv6 address as a string. If no address
133136
is provided, the address that the web service is called from will
@@ -205,10 +208,12 @@ def _handle_web_service_error(self, message, code, status, uri):
205208
if code in ('IP_ADDRESS_NOT_FOUND', 'IP_ADDRESS_RESERVED'):
206209
raise AddressNotFoundError(message)
207210
elif code in ('AUTHORIZATION_INVALID', 'LICENSE_KEY_REQUIRED',
208-
'USER_ID_REQUIRED'):
211+
'USER_ID_REQUIRED', 'USER_ID_UNKNOWN'):
209212
raise AuthenticationError(message)
210-
elif code == 'OUT_OF_QUERIES':
213+
elif code in ('INSUFFICIENT_FUNDS', 'OUT_OF_QUERIES'):
211214
raise OutOfQueriesError(message)
215+
elif code == 'PERMISSION_REQUIRED':
216+
raise PermissionRequiredError(message)
212217

213218
raise InvalidRequestError(message, code, status, uri)
214219

tests/webservice_test.py

Lines changed: 37 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@
66

77
import geoip2
88
import requests_mock
9-
from geoip2.errors import AddressNotFoundError, AuthenticationError, \
10-
GeoIP2Error, HTTPError, InvalidRequestError, OutOfQueriesError
9+
from geoip2.errors import (AddressNotFoundError, AuthenticationError,
10+
GeoIP2Error, HTTPError, InvalidRequestError, OutOfQueriesError,
11+
PermissionRequiredError)
1112
from geoip2.webservice import Client
1213

1314
if sys.version_info[:2] == (2, 6):
@@ -21,6 +22,7 @@
2122

2223

2324
class TestClient(unittest.TestCase):
25+
2426
def setUp(self):
2527
self.client = Client(42, 'abcdef123456')
2628

@@ -149,63 +151,54 @@ def test_300_error(self, mock):
149151
self.client.country('1.2.3.11')
150152

151153
@requests_mock.mock()
152-
def test_address_not_found_error(self, mock):
153-
body = {'error': 'Not in DB', 'code': 'IP_ADDRESS_NOT_FOUND'}
154-
mock.get(self.base_uri + 'country/' + '1.2.3.13',
155-
json=body,
156-
status_code=404,
157-
headers={'Content-Type': self._content_type('country')})
158-
with self.assertRaisesRegex(AddressNotFoundError, 'Not in DB'):
159-
self.client.country('1.2.3.13')
154+
def test_ip_address_required(self, mock):
155+
self._test_error(mock, 400, 'IP_ADDRESS_REQUIRED', InvalidRequestError)
160156

161157
@requests_mock.mock()
162-
def test_private_address_error(self, mock):
163-
body = {'error': 'Private', 'code': 'IP_ADDRESS_RESERVED'}
164-
mock.get(self.base_uri + 'country/' + '1.2.3.14',
165-
json=body,
166-
status_code=401,
167-
headers={'Content-Type': self._content_type('country')})
168-
with self.assertRaisesRegex(AddressNotFoundError, 'Private'):
169-
self.client.country('1.2.3.14')
158+
def test_ip_address_not_found(self, mock):
159+
self._test_error(mock, 404, 'IP_ADDRESS_NOT_FOUND',
160+
AddressNotFoundError)
161+
162+
@requests_mock.mock()
163+
def test_ip_address_reserved(self, mock):
164+
self._test_error(mock, 400, 'IP_ADDRESS_RESERVED',
165+
AddressNotFoundError)
166+
167+
@requests_mock.mock()
168+
def test_permission_required(self, mock):
169+
self._test_error(mock, 403, 'PERMISSION_REQUIRED',
170+
PermissionRequiredError)
170171

171172
@requests_mock.mock()
172173
def test_auth_invalid(self, mock):
173-
body = {'error': 'Invalid auth', 'code': 'AUTHORIZATION_INVALID'}
174-
mock.get(self.base_uri + 'country/' + '1.2.3.15',
175-
json=body,
176-
status_code=400,
177-
headers={'Content-Type': self._content_type('country')})
178-
with self.assertRaisesRegex(AuthenticationError, 'Invalid auth'):
179-
self.client.country('1.2.3.15')
174+
self._test_error(mock, 400, 'AUTHORIZATION_INVALID',
175+
AuthenticationError)
180176

181177
@requests_mock.mock()
182-
def test_license_required(self, mock):
183-
body = {'error': 'License required', 'code': 'LICENSE_KEY_REQUIRED'}
184-
mock.get(self.base_uri + 'country/' + '1.2.3.16',
185-
json=body,
186-
status_code=401,
187-
headers={'Content-Type': self._content_type('country')})
188-
with self.assertRaisesRegex(AuthenticationError, 'License required'):
189-
self.client.country('1.2.3.16')
178+
def test_license_key_required(self, mock):
179+
self._test_error(mock, 401, 'LICENSE_KEY_REQUIRED',
180+
AuthenticationError)
190181

191182
@requests_mock.mock()
192183
def test_user_id_required(self, mock):
193-
body = {'error': 'User ID required', 'code': 'USER_ID_REQUIRED'}
194-
mock.get(self.base_uri + 'country/' + '1.2.3.17',
195-
json=body,
196-
status_code=401,
197-
headers={'Content-Type': self._content_type('country')})
198-
with self.assertRaisesRegex(AuthenticationError, 'User ID required'):
199-
self.client.country('1.2.3.17')
184+
self._test_error(mock, 401, 'USER_ID_REQUIRED', AuthenticationError)
185+
186+
@requests_mock.mock()
187+
def test_user_id_unkown(self, mock):
188+
self._test_error(mock, 401, 'USER_ID_UNKNOWN', AuthenticationError)
200189

201190
@requests_mock.mock()
202191
def test_out_of_queries_error(self, mock):
203-
body = {'error': 'Out of Queries', 'code': 'OUT_OF_QUERIES'}
204-
mock.get(self.base_uri + 'country/' + '1.2.3.18',
192+
self._test_error(mock, 402, 'OUT_OF_QUERIES', OutOfQueriesError)
193+
194+
def _test_error(self, mock, status, error_code, error_class):
195+
msg = 'Some error message'
196+
body = {'error': msg, 'code': error_code}
197+
mock.get(self.base_uri + 'country/1.2.3.18',
205198
json=body,
206-
status_code=402,
199+
status_code=status,
207200
headers={'Content-Type': self._content_type('country')})
208-
with self.assertRaisesRegex(OutOfQueriesError, 'Out of Queries'):
201+
with self.assertRaisesRegex(error_class, msg):
209202
self.client.country('1.2.3.18')
210203

211204
@requests_mock.mock()

0 commit comments

Comments
 (0)