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

Use build_key(key, namespace) consistently across modules and classes #570

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
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
3 changes: 2 additions & 1 deletion aiocache/backends/memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,10 @@ async def _delete(self, key, _conn=None):
return self.__delete(key)

async def _clear(self, namespace=None, _conn=None):
"""Empty the cache for the namespace provided or the entire cache"""
if namespace:
for key in list(SimpleMemoryBackend._cache):
if key.startswith(namespace):
if self.key_filter(key, namespace):
self.__delete(key)
else:
SimpleMemoryBackend._cache = {}
Expand Down
14 changes: 13 additions & 1 deletion aiocache/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,13 @@ class BaseCache:
the backend. Default is None
:param key_builder: alternative callable to build the key. Receives the key and the namespace
as params and should return something that can be used as key by the underlying backend.
:param key_filter: callable that returns `True` if the specified key is
in the specified namespace. Callable signature must be:
`key_filter(key, namespace)`.
This callable is complementary to the `key_builder` callable.
If `key_builder` is provided, `key_filter` should also be provided.
If `key_filter` is not provided, default behavior will be compatible
with the default behavior of `key_builder`.
:param timeout: int or float in seconds specifying maximum timeout for the operations to last.
By default its 5. Use 0 or None if you want to disable it.
:param ttl: int the expiration time in seconds to use as a default in all operations of
Expand All @@ -107,12 +114,13 @@ class BaseCache:
NAME: str

def __init__(
self, serializer=None, plugins=None, namespace=None, key_builder=None, timeout=5, ttl=None
self, serializer=None, plugins=None, namespace=None, key_builder=None, key_filter=None, timeout=5, ttl=None
):
self.timeout = float(timeout) if timeout is not None else timeout
self.namespace = namespace
self.ttl = float(ttl) if ttl is not None else ttl
self.build_key = key_builder or self._build_key
self.key_filter = key_filter or self._key_filter

self._serializer = None
self.serializer = serializer or serializers.StringSerializer()
Expand Down Expand Up @@ -488,6 +496,10 @@ def _build_key(self, key, namespace=None):
return "{}{}".format(self.namespace, key)
return key

def _key_filter(self, key, namespace):
"""Return True if key is in namespace"""
return key.startswith(namespace)

def _get_ttl(self, ttl):
return ttl if ttl is not SENTINEL else self.ttl

Expand Down
13 changes: 10 additions & 3 deletions aiocache/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,14 +136,16 @@ def _key_from_args(self, func, args, kwargs):

async def get_from_cache(self, key):
try:
value = await self.cache.get(key)
namespace = self._kwargs.get("namespace", None)
value = await self.cache.get(key, namespace=namespace)
return value
except Exception:
logger.exception("Couldn't retrieve %s, unexpected error", key)

async def set_in_cache(self, key, value):
try:
await self.cache.set(key, value, ttl=self.ttl)
namespace = self._kwargs.get("namespace", None)
await self.cache.set(key, value, namespace=namespace, ttl=self.ttl)
except Exception:
logger.exception("Couldn't set %s in key %s, unexpected error", value, key)

Expand Down Expand Up @@ -205,7 +207,12 @@ async def decorator(self, f, *args, **kwargs):


def _get_cache(cache=Cache.MEMORY, serializer=None, plugins=None, **cache_kwargs):
return cache(serializer=serializer, plugins=plugins, **cache_kwargs)
return Cache(
cache,
serializer=serializer,
plugins=plugins,
**cache_kwargs,
)


def _get_args_dict(func, args, kwargs):
Expand Down
32 changes: 27 additions & 5 deletions aiocache/plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,15 @@ async def do_save_time(self, client, *args, took=0, **kwargs):
)


class HitMissRatioPlugin(BasePlugin):
class _HitMissRatioPlugin(BasePlugin):
"""
Calculates the ratio of hits the cache has. The data is saved in the cache class as a dict
attribute called ``hit_miss_ratio``. For example, to access the hit ratio of the cache,
you can do ``cache.hit_miss_ratio['hit_ratio']``. It also provides the "total" and "hits"
keys.
Calculates the ratio of hits the cache has. The data is saved in the
cache class as a dict attribute called ``hit_miss_ratio``.
For example, to access the hit ratio of the cache,
you can do ``cache.hit_miss_ratio['hit_ratio']``.
It also provides the "total" and "hits" keys.

:param key: str should already include the namespace, if available
"""

async def post_get(self, client, key, took=0, ret=None, **kwargs):
Expand Down Expand Up @@ -96,3 +99,22 @@ async def post_multi_get(self, client, keys, took=0, ret=None, **kwargs):
client.hit_miss_ratio["hit_ratio"] = (
client.hit_miss_ratio["hits"] / client.hit_miss_ratio["total"]
)


class HitMissRatioPlugin(_HitMissRatioPlugin):
"""
Calculates the ratio of hits the cache has. The data is saved in the
cache class as a dict attribute called ``hit_miss_ratio``.
For example, to access the hit ratio of the cache,
you can do ``cache.hit_miss_ratio['hit_ratio']``.
It also provides the "total" and "hits" keys.

:param key: str should not include the namespace
"""

async def post_get(self, client, key, took=0, ret=None, **kwargs):
"""Update cache stats; use namespace if available"""
namespace = kwargs.get("namespace", None)
ns_key = client.build_key(key, namespace=namespace)
await super().post_get(client, ns_key, took=took, ret=ret, **kwargs)
return