Skip to content

Commit

Permalink
Adding a basic memory cache, scoped to a block
Browse files Browse the repository at this point in the history
  • Loading branch information
vegitron committed Jun 28, 2017
1 parent 87781ed commit c3e1885
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 0 deletions.
9 changes: 9 additions & 0 deletions restclients_core/dao.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from restclients_core.util.mock import load_resource_from_path
from restclients_core.util.local_cache import set_cache_value, get_cache_value
from restclients_core.models import MockHTTP
from restclients_core.exceptions import ImproperlyConfigured
from restclients_core.cache import NoCache
Expand Down Expand Up @@ -346,14 +347,22 @@ def _get_mock_paths(self):
def load(self, method, url, headers, body):
service = self._service_name

cache_key = "%s-%s" % (service, url)
value = get_cache_value(cache_key)
if value:
return value

for path in self._get_mock_paths():
response = load_resource_from_path(path, service, "file", url,
headers)

if response:
set_cache_value(cache_key, response)
return response

response = MockHTTP()
response.status = 404
response.reason = "Not Found"

set_cache_value(key, response)
return response
48 changes: 48 additions & 0 deletions restclients_core/tests/test_local_cache.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from unittest import TestCase
from threading import currentThread
from restclients_core.util.local_cache import (local_cache, set_cache_value,
get_cache_value, LOCAL_CACHE)


class TestCache(TestCase):
def test_context(self):
thread = currentThread()
with local_cache() as lc:
v1 = test_method1("init")

self.assertTrue(thread in LOCAL_CACHE)
v2 = test_method1("nope, old cached value")
self.assertEquals(v2, "init")

self.assertFalse(thread in LOCAL_CACHE)

def test_decorator(self):
thread = currentThread()

@local_cache()
def use_the_cache():
v1 = test_method1("init decorator")

self.assertTrue(thread in LOCAL_CACHE)
v2 = test_method1("nope, old cached value")
self.assertEquals(v2, "init decorator")

use_the_cache()
self.assertFalse(thread in LOCAL_CACHE)

def test_no_cache(self):
v1 = test_method1("init none")
self.assertEquals(v1, "init none")

v2 = test_method1("second, none")
self.assertEquals(v2, "second, none")


def test_method1(val):
key = "test_method1_key"
value = get_cache_value(key)
if value:
return value

set_cache_value(key, val)
return val
75 changes: 75 additions & 0 deletions restclients_core/util/local_cache.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
from threading import currentThread


LOCAL_CACHE = {}


class local_cache(object):
"""
A decorator or context manager that will cache some values for the
lifetime of the decorator/context manager.
"""
def _function(self, func, *args, **kwargs):
def wrapped(*args, **kwargs):
try:
self.__enter__()
value = func(*args, **kwargs)
finally:
self.__exit__()
return value
return wrapped

# This handles function decorators + class decorators. Needs to switch
# on argument type :(
def __call__(self, decorated, *args, **kwargs):
if isinstance(decorated, type):
raise Exception("Can only decorate a function, not a class")

return self._function(decorated, *args, **kwargs)

# These handle context managers, and are used by the others
def __enter__(self, *args, **kwargs):
thread = currentThread()

LOCAL_CACHE[thread] = {}
return self

def __exit__(*args, **kwargs):
thread = currentThread()
del LOCAL_CACHE[thread]


def _get_local_cache():
thread = currentThread()
if thread in LOCAL_CACHE:
return LOCAL_CACHE[thread]
if hasattr(thread, 'parent'):
thread = thread.parent
if thread in LOCAL_CACHE:
return LOCAL_CACHE[thread]

return


def set_cache_value(key, value):
"""
If local cache is being used, this will set a cache value for the
lifetime of that cache.
"""
cache = _get_local_cache()
if cache is None:
return

cache[key] = value


def get_cache_value(key):
"""
If local cache is being used, this will get the cache value, if it exists.
"""
cache = _get_local_cache()
if cache is None:
return

if key in cache:
return cache[key]

0 comments on commit c3e1885

Please sign in to comment.