Skip to content

Commit 9b935de

Browse files
committed
adding error and cache
1 parent 056324b commit 9b935de

File tree

4 files changed

+94
-12
lines changed

4 files changed

+94
-12
lines changed

ipinfo/handler.py

Lines changed: 75 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -306,23 +306,89 @@ def getMap(self, ips):
306306
response.raise_for_status()
307307
return response.json()["reportUrl"]
308308

309-
def getIterativeBatchDetails(self, ip_addresses, batch_size=None):
309+
def getIterativeBatchDetails(
310+
self,
311+
ip_addresses,
312+
batch_size=None,
313+
raise_on_fail=True,
314+
):
310315
if batch_size == None:
311316
batch_size = BATCH_MAX_SIZE
312317

318+
results = {}
319+
320+
# pre-populate with anything we've got in the cache, and keep around
321+
# the IPs not in the cache.
322+
lookup_addresses = []
323+
for ip_address in ip_addresses:
324+
# if the supplied IP address uses the objects defined in the
325+
# built-in module ipaddress extract the appropriate string notation
326+
# before formatting the URL.
327+
if isinstance(ip_address, IPv4Address) or isinstance(
328+
ip_address, IPv6Address
329+
):
330+
ip_address = ip_address.exploded
331+
332+
# check if bogon.
333+
if ip_address and is_bogon(ip_address):
334+
details = {}
335+
details["ip"] = ip_address
336+
details["bogon"] = True
337+
yield Details(details)
338+
339+
# check cache first.
340+
try:
341+
cached_ipaddr = self.cache[cache_key(ip_address)]
342+
results[ip_address] = cached_ipaddr
343+
except KeyError:
344+
lookup_addresses.append(ip_address)
345+
346+
# all in cache - return early.
347+
if len(lookup_addresses) == 0:
348+
for ip_address, details in results.items():
349+
yield ip_address, details
350+
351+
# loop over batch chunks and do lookup for each.
313352
url = API_URL + "/batch"
314353
headers = handler_utils.get_headers(self.access_token, self.headers)
315354
headers["content-type"] = "application/json"
355+
for i in range(0, len(lookup_addresses), batch_size):
356+
batch = lookup_addresses[i : i + batch_size]
316357

317-
# Split the IP addresses into batches
318-
batches = [
319-
ip_addresses[i : i + batch_size]
320-
for i in range(0, len(ip_addresses), batch_size)
321-
]
358+
# lookup.
359+
try:
360+
response = requests.post(url, json=batch, headers=headers)
361+
except Exception as e:
362+
return handler_utils.return_or_fail(raise_on_fail, e, result)
322363

323-
for batch in batches:
324-
response = requests.post(url, json=batch, headers=headers)
325-
json_response = response.json()
364+
# fail on bad status codes
365+
try:
366+
if response.status_code == 429:
367+
raise RequestQuotaExceededError()
368+
response.raise_for_status()
369+
except Exception as e:
370+
return handler_utils.return_or_fail(raise_on_fail, e, result)
326371

372+
# fill cache
373+
json_response = response.json()
374+
print(f"JSON: {json_response}")
327375
for ip_address, details in json_response.items():
376+
self.cache[cache_key(ip_address)] = details
377+
378+
# merge cached results with new lookup
379+
results.update(json_response)
380+
381+
# format all
382+
for detail in results.values():
383+
if isinstance(detail, dict):
384+
handler_utils.format_details(
385+
detail,
386+
self.countries,
387+
self.eu_countries,
388+
self.countries_flags,
389+
self.countries_currencies,
390+
self.continents,
391+
)
392+
393+
for ip_address, details in results.items():
328394
yield ip_address, details

ipinfo/handler_utils.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,9 @@ def format_details(
7979
"""
8080
details["country_name"] = countries.get(details.get("country"))
8181
details["isEU"] = details.get("country") in eu_countries
82-
details["country_flag_url"] = COUNTRY_FLAGS_URL + details.get("country") + ".svg"
82+
details["country_flag_url"] = (
83+
COUNTRY_FLAGS_URL + details.get("country") + ".svg"
84+
)
8385
details["country_flag"] = copy.deepcopy(
8486
countries_flags.get(details.get("country"))
8587
)

tests/handler_async_test.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,10 @@ async def test_get_details():
4848
assert country_flag["emoji"] == "🇺🇸"
4949
assert country_flag["unicode"] == "U+1F1FA U+1F1F8"
5050
country_flag_url = details.country_flag_url
51-
assert country_flag_url == "https://cdn.ipinfo.io/static/images/countries-flags/US.svg"
51+
assert (
52+
country_flag_url
53+
== "https://cdn.ipinfo.io/static/images/countries-flags/US.svg"
54+
)
5255
country_currency = details.country_currency
5356
assert country_currency["code"] == "USD"
5457
assert country_currency["symbol"] == "$"

tests/handler_test.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,10 @@ def test_get_details():
4545
assert country_flag["emoji"] == "🇺🇸"
4646
assert country_flag["unicode"] == "U+1F1FA U+1F1F8"
4747
country_flag_url = details.country_flag_url
48-
assert country_flag_url == "https://cdn.ipinfo.io/static/images/countries-flags/US.svg"
48+
assert (
49+
country_flag_url
50+
== "https://cdn.ipinfo.io/static/images/countries-flags/US.svg"
51+
)
4952
country_currency = details.country_currency
5053
assert country_currency["code"] == "USD"
5154
assert country_currency["symbol"] == "$"
@@ -189,3 +192,11 @@ def test_bogon_details():
189192
details = handler.getDetails("127.0.0.1")
190193
assert isinstance(details, Details)
191194
assert details.all == {"bogon": True, "ip": "127.0.0.1"}
195+
196+
197+
def test_iterative_bogon_details():
198+
token = os.environ.get("IPINFO_TOKEN", "")
199+
handler = Handler(token)
200+
details = next(handler.getIterativeBatchDetails(["127.0.0.1"]))
201+
assert isinstance(details, Details)
202+
assert details.all == {"bogon": True, "ip": "127.0.0.1"}

0 commit comments

Comments
 (0)