Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cache available from function object when decorated #354

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions aiocache/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
class cached:
"""
Caches the functions return value into a key generated with module_name, function_name and args.
The cache is available in the function object as ``<function_name>.cache``.

In some cases you will need to send more args to configure the cache object.
An example would be endpoint and port for the RedisCache. You can send those args as
Expand Down Expand Up @@ -65,6 +66,8 @@ def __call__(self, f):
@functools.wraps(f)
async def wrapper(*args, **kwargs):
return await self.decorator(f, *args, **kwargs)

wrapper.cache = self.cache
return wrapper

async def decorator(self, f, *args, **kwargs):
Expand Down Expand Up @@ -180,6 +183,7 @@ class multi_cached:
"""
Only supports functions that return dict-like structures. This decorator caches each key/value
of the dict-like object returned by the function.
The cache is available in the function object as ``<function_name>.cache``.

If key_builder is passed, before storing the key, it will be transformed according to the output
of the function.
Expand Down Expand Up @@ -230,6 +234,8 @@ def __call__(self, f):
@functools.wraps(f)
async def wrapper(*args, **kwargs):
return await self.decorator(f, *args, **kwargs)

wrapper.cache = self.cache
return wrapper

async def decorator(self, f, *args, **kwargs):
Expand Down
26 changes: 26 additions & 0 deletions tests/ut/test_decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ async def fn(n):

assert await fn(1) == 1
assert await fn(2) == 2
assert fn.cache == mock_cache

@pytest.mark.asyncio
async def test_keeps_signature(self, mock_cache):
Expand Down Expand Up @@ -182,6 +183,18 @@ async def what():
assert get_c.call_count == 1
assert cache.get.call_count == 2

@pytest.mark.asyncio
async def test_cache_per_function(self):
@cached()
async def foo():
pass

@cached()
async def bar():
pass

assert foo.cache != bar.cache


class TestCachedStampede:
@pytest.fixture
Expand Down Expand Up @@ -454,6 +467,7 @@ async def fn(keys=None):

assert await fn(keys=['test']) == {'test': 1}
assert await fn(keys=['test']) == {'test': 1}
assert fn.cache == mock_cache

@pytest.mark.asyncio
async def test_keeps_signature(self):
Expand Down Expand Up @@ -482,6 +496,18 @@ async def what(keys=None):
assert get_c.call_count == 1
assert cache.multi_get.call_count == 2

@pytest.mark.asyncio
async def test_cache_per_function(self):
@multi_cached('keys')
async def foo():
pass

@multi_cached('keys')
async def bar():
pass

assert foo.cache != bar.cache


def test_get_args_dict():
def fn(a, b, *args, keys=None, **kwargs):
Expand Down