Skip to content

Commit

Permalink
Merge pull request #49 from ipinfo/uman/vsn-cache-key
Browse files Browse the repository at this point in the history
Implement versioned cache key.
  • Loading branch information
UmanShahzad authored Apr 22, 2021
2 parents e229f52 + ba05c4c commit ed864d3
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 22 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# IPInfo Changelog

## 4.2.0

- Cache keys are now versioned.
This allows more reliable changes to cached data in the future without
causing confusing incompatibilities. This should be transparent to the user.
This is primarily useful for users with persistent cache implementations.

## 4.1.0

- The SDK version is available via `ipinfo.version` as `SDK_VERSION`.
Expand Down
20 changes: 13 additions & 7 deletions ipinfo/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
CACHE_TTL,
REQUEST_TIMEOUT_DEFAULT,
BATCH_REQ_TIMEOUT_DEFAULT,
cache_key,
)
from . import handler_utils

Expand Down Expand Up @@ -74,8 +75,12 @@ def getDetails(self, ip_address=None, timeout=None):
):
ip_address = ip_address.exploded

if ip_address in self.cache:
return Details(self.cache[ip_address])
# check cache first.
try:
cached_ipaddr = self.cache[cache_key(ip_address)]
return Details(cached_ipaddr)
except KeyError:
pass

# prepare req http opts
req_opts = {**self.request_options}
Expand All @@ -95,7 +100,7 @@ def getDetails(self, ip_address=None, timeout=None):

# format & cache
handler_utils.format_details(details, self.countries)
self.cache[ip_address] = details
self.cache[cache_key(ip_address)] = details

return Details(details)

Expand Down Expand Up @@ -153,9 +158,10 @@ def getBatchDetails(
):
ip_address = ip_address.exploded

if ip_address in self.cache:
result[ip_address] = self.cache[ip_address]
else:
try:
cached_ipaddr = self.cache[cache_key(ip_address)]
result[ip_address] = cached_ipaddr
except KeyError:
lookup_addresses.append(ip_address)

# all in cache - return early.
Expand Down Expand Up @@ -201,7 +207,7 @@ def getBatchDetails(
# fill cache
json_response = response.json()
for ip_address, details in json_response.items():
self.cache[ip_address] = details
self.cache[cache_key(ip_address)] = details

# merge cached results with new lookup
result.update(json_response)
Expand Down
20 changes: 13 additions & 7 deletions ipinfo/handler_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
CACHE_TTL,
REQUEST_TIMEOUT_DEFAULT,
BATCH_REQ_TIMEOUT_DEFAULT,
cache_key,
)
from . import handler_utils

Expand Down Expand Up @@ -99,8 +100,12 @@ async def getDetails(self, ip_address=None, timeout=None):
):
ip_address = ip_address.exploded

if ip_address in self.cache:
return Details(self.cache[ip_address])
# check cache first.
try:
cached_ipaddr = self.cache[cache_key(ip_address)]
return Details(cached_ipaddr)
except KeyError:
pass

# not in cache; do http req
url = API_URL
Expand All @@ -118,7 +123,7 @@ async def getDetails(self, ip_address=None, timeout=None):

# format & cache
handler_utils.format_details(details, self.countries)
self.cache[ip_address] = details
self.cache[cache_key(ip_address)] = details

return Details(details)

Expand Down Expand Up @@ -181,9 +186,10 @@ async def getBatchDetails(
):
ip_address = ip_address.exploded

if ip_address in self.cache:
result[ip_address] = self.cache[ip_address]
else:
try:
cached_ipaddr = self.cache[cache_key(ip_address)]
result[ip_address] = cached_ipaddr
except KeyError:
lookup_addresses.append(ip_address)

# all in cache - return early.
Expand Down Expand Up @@ -267,7 +273,7 @@ async def _do_batch_req(
for ip_address, details in json_resp.items():
if isinstance(details, dict):
handler_utils.format_details(details, self.countries)
self.cache[ip_address] = details
self.cache[cache_key(ip_address)] = details

# merge cached results with new lookup
result.update(json_resp)
Expand Down
11 changes: 11 additions & 0 deletions ipinfo/handler_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
# The default TTL of the cache in seconds
CACHE_TTL = 60 * 60 * 24

# The current version of the cached data.
# Update this if the data being cached has changed in shape for the same key.
CACHE_KEY_VSN = "1"

# The default request timeout for per-IP requests.
REQUEST_TIMEOUT_DEFAULT = 2

Expand Down Expand Up @@ -93,3 +97,10 @@ def return_or_fail(raise_on_fail, e, v):
raise e
else:
return v


def cache_key(k):
"""
Transforms a user-input key into a versioned cache key.
"""
return f"{k}:{CACHE_KEY_VSN}"
2 changes: 1 addition & 1 deletion ipinfo/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
SDK_VERSION = "4.1.0"
SDK_VERSION = "4.2.0"
14 changes: 7 additions & 7 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,34 @@
#
# pip-compile --no-emit-index-url --no-emit-trusted-host
#
aiohttp==3.7.3 # via -r requirements.in
aiohttp==3.7.4.post0 # via -r requirements.in
appdirs==1.4.4 # via black
async-timeout==3.0.1 # via aiohttp
attrs==20.3.0 # via aiohttp, pytest
black==20.8b1 # via -r requirements.in
cachetools==4.2.0 # via -r requirements.in
certifi==2020.12.5 # via requests
chardet==3.0.4 # via aiohttp, requests
chardet==4.0.0 # via aiohttp, requests
click==7.1.2 # via black, pip-tools
idna==2.10 # via requests, yarl
iniconfig==1.1.1 # via pytest
multidict==5.1.0 # via aiohttp, yarl
mypy-extensions==0.4.3 # via black
packaging==20.8 # via pytest
packaging==20.9 # via pytest
pathspec==0.8.1 # via black
pip-tools==5.4.0 # via -r requirements.in
pluggy==0.13.1 # via pytest
py==1.10.0 # via pytest
pyparsing==2.4.7 # via packaging
pytest-asyncio==0.14.0 # via -r requirements.in
pytest==6.2.1 # via -r requirements.in, pytest-asyncio
regex==2020.11.13 # via black
requests==2.25.0 # via -r requirements.in
regex==2021.4.4 # via black
requests==2.25.1 # via -r requirements.in
six==1.15.0 # via pip-tools
toml==0.10.2 # via black, pytest
typed-ast==1.4.1 # via black
typed-ast==1.4.3 # via black
typing-extensions==3.7.4.3 # via aiohttp, black
urllib3==1.26.2 # via requests
urllib3==1.26.4 # via requests
yarl==1.6.3 # via aiohttp

# The following packages are considered to be unsafe in a requirements file:
Expand Down

0 comments on commit ed864d3

Please sign in to comment.