diff --git a/Readme.md b/Readme.md index bf5c5ff..588f3d9 100644 --- a/Readme.md +++ b/Readme.md @@ -32,7 +32,7 @@ scalable and reliable applications. This library intends to make it easy to impl - Client-side cache (10x faster than simple cache with redis) - Bloom filters - Different cache invalidation techniques (time-based or tags) -- Cache any objects securely with pickle (use [hash key](#redis)) +- Cache any objects securely with pickle (use [secret](#redis)) - 2x faster than `aiocache` (with client side caching) ## Usage Example @@ -84,9 +84,9 @@ More examples [here](https://github.com/Krukov/cashews/tree/master/examples) from cashews import cache # via url -cache.setup("redis://0.0.0.0/?db=1&socket_connect_timeout=0.5&suppress=0&hash_key=my_secret&enable=1") +cache.setup("redis://0.0.0.0/?db=1&socket_connect_timeout=0.5&suppress=0&secret=my_secret&enable=1") # or via kwargs -cache.setup("redis://0.0.0.0/", db=1, wait_for_connection_timeout=0.5, suppress=False, hash_key=b"my_key", enable=True) +cache.setup("redis://0.0.0.0/", db=1, wait_for_connection_timeout=0.5, suppress=False, secret=b"my_key", enable=True) ``` Alternatively, you can create a cache instance yourself: @@ -156,8 +156,8 @@ If you would like to use [client-side cache](https://redis.io/topics/client-side Client side cache will add `cashews:` prefix for each key, to customize it use `client_side_prefix` option. ```python -cache.setup("redis://0.0.0.0/?db=1&minsize=10&suppress=false&hash_key=my_secret", prefix="func") -cache.setup("redis://0.0.0.0/2", password="my_pass", socket_connect_timeout=0.1, retry_on_timeout=True, hash_key="my_secret") +cache.setup("redis://0.0.0.0/?db=1&minsize=10&suppress=false&secret=my_secret", prefix="func") +cache.setup("redis://0.0.0.0/2", password="my_pass", socket_connect_timeout=0.1, retry_on_timeout=True, secret="my_secret") cache.setup("redis://0.0.0.0", client_side=True, client_side_prefix="my_prefix:", pickle_type="dill") ``` diff --git a/cashews/formatter.py b/cashews/formatter.py index 18f5a76..0df6825 100644 --- a/cashews/formatter.py +++ b/cashews/formatter.py @@ -9,7 +9,7 @@ from ._typing import KeyOrTemplate, KeyTemplate TemplateValue = str -_re_special_chars_map = {i: "\\" + chr(i) for i in b"()[]?*+-|^$\\.&~# \t\n\r\v\f"} +_re_special_chars_map = {i: "\\" + chr(i) for i in b"()[]?*+-|^$\\&~# \t\n\r\v\f"} def _decode_bytes(value: bytes): @@ -164,7 +164,8 @@ def default_format(template: KeyTemplate, **values) -> KeyOrTemplate: def _re_default(field_name): - return f"(?P<{field_name.replace('.', '_')}>.+)?" + field_name = field_name.split(".")[0] + return f"(?P<{field_name}>.+)?" _re_formatter = _ReplaceFormatter(default=_re_default) diff --git a/cashews/wrapper/tags.py b/cashews/wrapper/tags.py index 326ef19..701773b 100644 --- a/cashews/wrapper/tags.py +++ b/cashews/wrapper/tags.py @@ -3,7 +3,6 @@ from cashews._typing import TTL, Key, KeyOrTemplate, OnRemoveCallback, Tag, Tags, Value from cashews.backends.interface import Backend -from cashews.exceptions import TagNotRegisteredError from cashews.formatter import default_format, template_to_re_pattern from .commands import CommandWrapper @@ -36,14 +35,6 @@ def _match_patterns(key: Key, patterns: List[Pattern]) -> Optional[Match]: return match return None - def check_tags_registered(self, key: Key, tags: Tags): - tags = set(tags) - key_tags = set(self.get_key_tags(key)) - difference = tags.difference(key_tags) - - if difference: - raise TagNotRegisteredError(f"tag: {difference} not registered: call cache.register_tag before using tags") - class CommandsTagsWrapper(CommandWrapper): def __init__(self, name: str = ""): @@ -116,7 +107,6 @@ async def set( ) -> bool: _set = await super().set(key=key, value=value, expire=expire, exist=exist) if _set and tags: - self._tags_registry.check_tags_registered(key, tags) for tag in tags: await self.set_add(self._tags_key_prefix + tag, key, expire=expire) return _set @@ -124,7 +114,6 @@ async def set( async def incr(self, key: Key, value: int = 1, expire: Optional[float] = None, tags: Tags = ()) -> int: _set = await super().incr(key=key, value=value, expire=expire) if _set and tags: - self._tags_registry.check_tags_registered(key, tags) for tag in tags: await self.set_add(self._tags_key_prefix + tag, key, expire=expire) return _set diff --git a/tests/conftest.py b/tests/conftest.py index fdb3a91..ce2963e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -68,7 +68,7 @@ async def _backend(request, redis_dsn, backend_factory): backend = backend_factory( Redis, redis_dsn, - hash_key=None, + secret=None, max_connections=20, suppress=False, socket_timeout=1, @@ -80,7 +80,7 @@ async def _backend(request, redis_dsn, backend_factory): backend = backend_factory( Redis, redis_dsn, - hash_key=uuid4().hex, + secret=uuid4().hex, max_connections=20, suppress=False, socket_timeout=10, @@ -92,7 +92,7 @@ async def _backend(request, redis_dsn, backend_factory): backend = backend_factory( BcastClientSide, redis_dsn, - hash_key=None, + secret=None, max_connections=5, suppress=False, socket_timeout=0.1, diff --git a/tests/test_client_side_cache.py b/tests/test_client_side_cache.py index bdca991..6775ea7 100644 --- a/tests/test_client_side_cache.py +++ b/tests/test_client_side_cache.py @@ -14,7 +14,7 @@ def _create_cache(redis_dsn, backend_factory): from cashews.backends.redis.client_side import BcastClientSide async def call(local_cache=None): - backend = backend_factory(BcastClientSide, redis_dsn, hash_key=None, local_cache=local_cache) + backend = backend_factory(BcastClientSide, redis_dsn, secret=None, local_cache=local_cache) await backend.init() await backend.clear() return backend diff --git a/tests/test_pickle_serializer.py b/tests/test_pickle_serializer.py index 4dc62c0..0325f31 100644 --- a/tests/test_pickle_serializer.py +++ b/tests/test_pickle_serializer.py @@ -37,13 +37,13 @@ async def _cache(request, redis_dsn): if pickle_type == "redis": from cashews.backends.redis import Redis - redis = Redis(redis_dsn, hash_key="test", safe=False, digestmod=digestmod) + redis = Redis(redis_dsn, secret="test", safe=False, digestmod=digestmod) await redis.init() await redis.clear() yield redis await redis.close() else: - yield Memory(hash_key=b"test", digestmod=digestmod, pickle_type=pickle_type) + yield Memory(secret=b"test", digestmod=digestmod, pickle_type=pickle_type) @pytest.mark.parametrize( @@ -271,7 +271,7 @@ async def test_no_hash(key, value): async def test_cache_from_hash_to_no_hash(): val = Decimal("10.2") - cache = Memory(hash_key="test") + cache = Memory(secret="test") await cache.set("key", val) assert await cache.get("key") == val @@ -286,7 +286,7 @@ async def test_cache_from_no_hash_to_hash(): await cache.set("key", val) assert await cache.get("key") == val - cache_hash = Memory(hash_key="test") + cache_hash = Memory(secret="test") cache_hash.store = cache.store assert await cache_hash.get("key") == val diff --git a/tests/test_redis_down.py b/tests/test_redis_down.py index 9839932..30be1ac 100644 --- a/tests/test_redis_down.py +++ b/tests/test_redis_down.py @@ -16,7 +16,7 @@ def redis_backend(): async def test_safe_redis(redis_backend): - redis = redis_backend(safe=True, address="redis://localhost:9223", hash_key=None) + redis = redis_backend(safe=True, address="redis://localhost:9223", secret=None) await redis.init() assert await redis.set("test", "test") is False @@ -52,7 +52,7 @@ async def test_safe_redis(redis_backend): async def test_unsafe_redis_down(redis_backend): - redis = redis_backend(safe=False, address="redis://localhost:9223", hash_key=None) + redis = redis_backend(safe=False, address="redis://localhost:9223", secret=None) await redis.init() with pytest.raises(CacheBackendInteractionError): await redis.ping() @@ -63,7 +63,7 @@ async def test_unsafe_redis_down(redis_backend): async def test_cache_decorators_on_redis_down(redis_backend): mock = Mock(return_value="val") cache = Cache() - cache._add_backend(redis_backend(safe=True, address="redis://localhost:9223", hash_key=None)) + cache._add_backend(redis_backend(safe=True, address="redis://localhost:9223", secret=None)) @cache(ttl=1) @cache.failover(1) diff --git a/tests/test_settings_url.py b/tests/test_settings_url.py index d719a0b..16bb21b 100644 --- a/tests/test_settings_url.py +++ b/tests/test_settings_url.py @@ -58,10 +58,10 @@ def test_url_but_backend_dependency_is_not_installed(url, error): }, ), ( - "redis://localhost/0/?hash_key=secret&password=test&safe=1&minsize=3&create_connection_timeout=0.1", # noqa: E501 + "redis://localhost/0/?secret=secret&password=test&safe=1&minsize=3&create_connection_timeout=0.1", # noqa: E501 { "address": "redis://localhost/0/", - "hash_key": "secret", + "secret": "secret", "password": "test", "safe": True, "minsize": 3, diff --git a/tests/test_tags_feature.py b/tests/test_tags_feature.py index 64ada02..3ef4a06 100644 --- a/tests/test_tags_feature.py +++ b/tests/test_tags_feature.py @@ -241,3 +241,19 @@ async def cached( return f"{a}{b}" assert await cached(1) == "1None" + + +async def test_template_tag_function(cache: Cache): + @cache(ttl="1m", key="{user.name:hash}:func", tags=["tag:{user.name}", "tag:{user.name:hash}"]) + async def func(user): + return random() + + class User: + def __init__(self, name): + self.name = name + + def __hash__(self): + return hash(self.name) + + await func(User("test")) + await cache.delete_tags("tag:test")