Skip to content

Commit 4ac8c9b

Browse files
authored
Merge pull request #66 from amirreza8002/cluster_cleanup
decorator cleanup
2 parents aaf4767 + 7c36156 commit 4ac8c9b

File tree

5 files changed

+68
-27
lines changed

5 files changed

+68
-27
lines changed

CHANGES.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
### Breaking changes
2+
- `BackendCommands` and `AsyncBackendCommands` are no longer decorated with `omit_exception`.
3+
- added `omit_exception_async` to decorate async operations, instead of using `omit_exception` for both sync and async.
4+
- `omit_exception` no longer supports async functions and generators.
5+
- added `DecoratedBackendCommands` and `DecoratedAsyncBackendCommands` as commands decorated with `omit_exception` and `omit_exception_async`.
6+
- `AsyncValkeyCache` and `ValkeyCache` no longer inherit from `BackendCommands` and `AsyncBackendCommands`, they inherit from `DecoratedBackendCommands` and `DecoratedAsyncBackendCommands` instead.
7+
8+
### improvement
9+
- removed the undecorator loop from cluster client
10+
111
Version 0.3.2
212
-------------
313

django_valkey/async_cache/cache.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,21 @@
11
from valkey.asyncio.client import Valkey as AValkey
22

3-
from django_valkey.base import BaseValkeyCache, AsyncBackendCommands
3+
from django_valkey.base import (
4+
BaseValkeyCache,
5+
AsyncBackendCommands,
6+
decorate_all_methods,
7+
omit_exception_async,
8+
)
49
from django_valkey.async_cache.client.default import AsyncDefaultClient
510

611

12+
@decorate_all_methods(omit_exception_async)
13+
class DecoratedAsyncBackendCommands(AsyncBackendCommands):
14+
pass
15+
16+
717
class AsyncValkeyCache(
8-
BaseValkeyCache[AsyncDefaultClient, AValkey], AsyncBackendCommands
18+
BaseValkeyCache[AsyncDefaultClient, AValkey], DecoratedAsyncBackendCommands
919
):
1020
DEFAULT_CLIENT_CLASS = "django_valkey.async_cache.client.default.AsyncDefaultClient"
1121
is_async = True

django_valkey/base.py

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import inspect
55
import logging
66
from collections.abc import AsyncGenerator, Callable, Iterator
7-
from inspect import iscoroutinefunction
87
from typing import (
98
Any,
109
TypeVar,
@@ -32,7 +31,7 @@
3231

3332
def decorate_all_methods(decorator):
3433
def decorate(cls):
35-
for attr in vars(cls):
34+
for attr in dir(cls):
3635
# dunders and `get` should not be decorated
3736
# get is handled by `_get`
3837
if attr.startswith("__") or attr in {"get", "get_or_set"}:
@@ -91,6 +90,34 @@ def _generator_decorator(self, *args, **kwargs):
9190
except ConnectionInterrupted as e:
9291
yield __handle_error(self, e)
9392

93+
# sync generators (iter_keys, sscan_iter) are only generator on client class
94+
# in the backend they are just a function (that returns a generator)
95+
# so inspect.isgeneratorfunction does not work
96+
if not gen:
97+
wrapper = _decorator
98+
99+
# if method is a generator or async generator, it should be iterated over by this decorator
100+
# generators don't error by simply being called, they need to be iterated over.
101+
else:
102+
wrapper = _generator_decorator
103+
104+
return wrapper
105+
106+
107+
def omit_exception_async(
108+
method: Callable | None = None, return_value: Any | None = None, gen=False
109+
):
110+
if method is None:
111+
return functools.partial(omit_exception, return_value=return_value)
112+
113+
def __handle_error(self, e) -> Any | None:
114+
if getattr(self, "_ignore_exceptions", None):
115+
if getattr(self, "_log_ignored_exceptions", None):
116+
self.logger.exception("Exception ignored")
117+
118+
return return_value
119+
raise e.__cause__
120+
94121
@functools.wraps(method)
95122
async def _async_decorator(self, *args, **kwargs):
96123
try:
@@ -106,22 +133,13 @@ async def _async_generator_decorator(self, *args, **kwargs):
106133
except ConnectionInterrupted as e:
107134
yield __handle_error(self, e)
108135

109-
# sync generators (iter_keys, sscan_iter) are only generator on client class
110-
# in the backend they are just a function (that returns a generator)
111-
# so inspect.isgeneratorfunction does not work
112-
if not inspect.isasyncgenfunction(method) and not gen:
113-
wrapper = _async_decorator if iscoroutinefunction(method) else _decorator
114-
115-
# if method is a generator or async generator, it should be iterated over by this decorator
116-
# generators don't error by simply being called, they need to be iterated over.
136+
if inspect.isasyncgenfunction(method):
137+
# if method is a generator or async generator, it should be iterated over by this decorator
138+
# generators don't error by simply being called, they need to be iterated over.
139+
wrapper = _async_generator_decorator
117140
else:
118-
wrapper = (
119-
_async_generator_decorator
120-
if inspect.isasyncgenfunction(method)
121-
else _generator_decorator
122-
)
141+
wrapper = _async_decorator
123142

124-
wrapper.original = method
125143
return wrapper
126144

127145

@@ -199,7 +217,6 @@ def make_pattern(self, *args, **kwargs) -> bool:
199217
return self.client.make_pattern(*args, **kwargs)
200218

201219

202-
@decorate_all_methods(omit_exception)
203220
class BackendCommands:
204221
def __contains__(self, item):
205222
return self.has_key(item)
@@ -384,7 +401,6 @@ def hexists(self: BaseValkeyCache, *args, **kwargs) -> bool:
384401
return self.client.hexists(*args, **kwargs)
385402

386403

387-
@decorate_all_methods(omit_exception)
388404
class AsyncBackendCommands:
389405
def __getattr__(self, item):
390406
if item.startswith("a"):

django_valkey/cache.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,18 @@
11
from valkey import Valkey
22

3-
from django_valkey.base import BaseValkeyCache, BackendCommands
3+
from django_valkey.base import (
4+
BaseValkeyCache,
5+
BackendCommands,
6+
decorate_all_methods,
7+
omit_exception,
8+
)
49
from django_valkey.client import DefaultClient
510

611

7-
class ValkeyCache(BaseValkeyCache[DefaultClient, Valkey], BackendCommands):
12+
@decorate_all_methods(omit_exception)
13+
class DecoratedBackendCommands(BackendCommands):
14+
pass
15+
16+
17+
class ValkeyCache(BaseValkeyCache[DefaultClient, Valkey], DecoratedBackendCommands):
818
DEFAULT_CLIENT_CLASS = "django_valkey.client.DefaultClient"

django_valkey/cluster_cache/cache.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,3 @@ class ClusterValkeyCache(
3636
BackendCommands,
3737
):
3838
DEFAULT_CLIENT_CLASS = "django_valkey.cluster_cache.client.DefaultClusterClient"
39-
40-
41-
for name, value in vars(BackendCommands).items():
42-
if original := getattr(value, "original", None):
43-
setattr(ClusterValkeyCache, name, original)

0 commit comments

Comments
 (0)