Skip to content

Commit d2d6d8e

Browse files
committed
Added test for incr and decr command and drop aiomemcache support
1 parent 32190a9 commit d2d6d8e

17 files changed

+493
-259
lines changed

ellar/cache/backends/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
from .serializer import AioCacheSerializer, ICacheSerializer, RedisSerializer
1+
from .serializer import ICacheSerializer, RedisSerializer
22

3-
__all__ = ["ICacheSerializer", "RedisSerializer", "AioCacheSerializer"]
3+
__all__ = ["ICacheSerializer", "RedisSerializer"]

ellar/cache/backends/_aio_cache.py

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
# import pickle
2+
# import typing as t
3+
# from abc import ABC
4+
#
5+
# from ellar.helper.event_loop import get_or_create_eventloop
6+
#
7+
# try:
8+
# from aiomcache import Client
9+
# except ImportError as e: # pragma: no cover
10+
# raise RuntimeError(
11+
# "To use `AioMemCacheBackend`, you have to install 'aiomcache' package e.g. `pip install aiomcache`"
12+
# ) from e
13+
#
14+
# from ..interface import IBaseCacheBackendAsync
15+
# from ..make_key_decorator import make_key_decorator, make_key_decorator_and_validate
16+
# from ..model import BaseCacheBackend
17+
# from .serializer import AioCacheSerializer, ICacheSerializer
18+
#
19+
#
20+
# class _AioMemCacheBackendSync(IBaseCacheBackendAsync, ABC):
21+
# def _async_executor(self, func: t.Awaitable) -> t.Any:
22+
# return get_or_create_eventloop().run_until_complete(func)
23+
#
24+
# def get(self, key: str, version: str = None) -> t.Any:
25+
# return self._async_executor(self.get_async(key, version=version))
26+
#
27+
# def delete(self, key: str, version: str = None) -> bool:
28+
# res = self._async_executor(self.delete_async(key, version=version))
29+
# return bool(res)
30+
#
31+
# def set(
32+
# self,
33+
# key: str,
34+
# value: t.Any,
35+
# timeout: t.Union[float, int] = None,
36+
# version: str = None,
37+
# ) -> bool:
38+
# res = self._async_executor(
39+
# self.set_async(key, value, version=version, timeout=timeout)
40+
# )
41+
# return bool(res)
42+
#
43+
# def touch(
44+
# self, key: str, timeout: t.Union[float, int] = None, version: str = None
45+
# ) -> bool:
46+
# res = self._async_executor(
47+
# self.touch_async(key, version=version, timeout=timeout)
48+
# )
49+
# return bool(res)
50+
#
51+
# def incr(self, key: str, delta: int = 1, version: str = None) -> int:
52+
# res = self._async_executor(self.incr_async(key, delta=delta, version=version))
53+
# return t.cast(int, res)
54+
#
55+
# def decr(self, key: str, delta: int = 1, version: str = None) -> int:
56+
# res = self._async_executor(self.decr_async(key, delta=delta, version=version))
57+
# return t.cast(int, res)
58+
#
59+
#
60+
# class AioMemCacheBackend(_AioMemCacheBackendSync, BaseCacheBackend):
61+
# """Memcached-based cache backend."""
62+
#
63+
# pickle_protocol = pickle.HIGHEST_PROTOCOL
64+
# MEMCACHE_CLIENT: t.Type = Client
65+
#
66+
# def __init__(
67+
# self,
68+
# host: str,
69+
# port: int = 11211,
70+
# pool_size: int = 2,
71+
# pool_minsize: int = None,
72+
# serializer: ICacheSerializer = None,
73+
# **kwargs: t.Any
74+
# ) -> None:
75+
# super().__init__(**kwargs)
76+
# self._client: Client = None # type: ignore[assignment]
77+
# self._client_options = dict(
78+
# host=host, port=port, pool_size=pool_size, pool_minsize=pool_minsize
79+
# )
80+
# self._serializer = serializer or AioCacheSerializer()
81+
#
82+
# def get_backend_timeout(self, timeout: t.Union[float, int] = None) -> int:
83+
# return int(super().get_backend_timeout(timeout))
84+
#
85+
# @property
86+
# def _cache_client(self) -> Client:
87+
# if self._client is None:
88+
# self._client = self.MEMCACHE_CLIENT(**self._client_options)
89+
# return self._client
90+
#
91+
# @make_key_decorator
92+
# async def get_async(self, key: str, version: str = None) -> t.Optional[t.Any]:
93+
# value = await self._cache_client.get(key.encode("utf-8"))
94+
# if value:
95+
# return self._serializer.load(value)
96+
# return None # pragma: no cover
97+
#
98+
# @make_key_decorator_and_validate
99+
# async def set_async(
100+
# self,
101+
# key: str,
102+
# value: t.Any,
103+
# timeout: t.Union[float, int] = None,
104+
# version: str = None,
105+
# ) -> bool:
106+
# return await self._cache_client.set(
107+
# key.encode("utf-8"),
108+
# self._serializer.dumps(value),
109+
# exptime=self.get_backend_timeout(timeout),
110+
# )
111+
#
112+
# @make_key_decorator
113+
# async def delete_async(self, key: str, version: str = None) -> bool:
114+
# return await self._cache_client.delete(key.encode("utf-8"))
115+
#
116+
# @make_key_decorator
117+
# async def touch_async(
118+
# self, key: str, timeout: t.Union[float, int] = None, version: str = None
119+
# ) -> bool:
120+
# return await self._cache_client.touch(
121+
# key.encode("utf-8"), exptime=self.get_backend_timeout(timeout)
122+
# )
123+
#
124+
# @make_key_decorator
125+
# async def incr_async(self, key: str, delta: int = 1, version: str = None) -> int:
126+
# res = await self._cache_client.incr(key.encode("utf-8"), increment=delta)
127+
# return t.cast(int, res)
128+
#
129+
# @make_key_decorator
130+
# async def decr_async(self, key: str, delta: int = 1, version: str = None) -> int:
131+
# res = await self._cache_client.decr(key.encode("utf-8"), decrement=delta)
132+
# return t.cast(int, res)

ellar/cache/backends/aio_cache.py

Lines changed: 0 additions & 132 deletions
This file was deleted.

ellar/cache/backends/base.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,17 +46,16 @@ def touch(
4646

4747
@make_key_decorator
4848
def incr(self, key: str, delta: int = 1, version: str = None) -> int:
49-
result = self._cache_client.incr(key, delta)
49+
result = self._cache_client.incr(key, abs(delta))
5050
return t.cast(int, result)
5151

5252
@make_key_decorator
5353
def decr(self, key: str, delta: int = 1, version: str = None) -> int:
54-
result = self._cache_client.decr(key, delta)
54+
result = self._cache_client.decr(key, abs(delta))
5555
return t.cast(int, result)
5656

5757
def close(self, **kwargs: t.Any) -> None:
58-
# Many clients don't clean up connections properly.
59-
self._cache_client.disconnect_all()
58+
"""Many clients don't clean up connections properly."""
6059

6160
def clear(self) -> None:
6261
self._cache_client.flush_all()

ellar/cache/backends/local_cache.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,16 +133,21 @@ def _incr_decr_action(self, key: str, delta: int) -> int:
133133
self._cache[key] = pickled
134134
return new_value
135135

136+
@make_key_decorator
136137
async def incr_async(self, key: str, delta: int = 1, version: str = None) -> int:
137138
async with self._lock:
138139
if self._has_expired(key):
139140
await self._delete(key)
140141
raise ValueError("Key '%s' not found" % key)
141142
return self._incr_decr_action(key, delta)
142143

144+
@make_key_decorator
143145
async def decr_async(self, key: str, delta: int = 1, version: str = None) -> int:
144146
async with self._lock:
145147
if self._has_expired(key):
146148
await self._delete(key)
147149
raise ValueError("Key '%s' not found" % key)
148-
return self._incr_decr_action(key, delta * -1)
150+
res = self._incr_decr_action(key, delta * -1)
151+
if res < 0:
152+
return self._incr_decr_action(key, res * -1)
153+
return res

ellar/cache/backends/pymem_cache.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,6 @@ def __init__(self, servers: t.List[str], options: t.Dict = None, **kwargs: t.Any
6262
}
6363

6464
super().__init__(servers, options=_options, **kwargs)
65+
66+
def close(self, **kwargs: t.Any) -> None:
67+
self._cache_client.disconnect_all()

ellar/cache/backends/redis/backend.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ def get_backend_timeout(
129129
async def get_async(self, key: str, version: str = None) -> t.Any:
130130
client = self._get_client()
131131
value = await client.get(key)
132-
if value:
132+
if value is not None:
133133
return self._serializer.load(value)
134134
return None
135135

ellar/cache/backends/serializer.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,16 @@ def dumps(self, data: t.Any) -> t.Any:
3333
return pickle.dumps(data, self._protocol)
3434

3535

36-
class AioCacheSerializer(RedisSerializer):
37-
def load(self, data: t.Any) -> t.Any:
38-
try:
39-
return int(data.decode("utf-8"))
40-
except ValueError:
41-
return pickle.loads(data)
42-
43-
def dumps(self, data: t.Any) -> t.Any:
44-
# Only skip pickling for integers, an int subclasses as bool should be
45-
# pickled.
46-
if type(data) is int:
47-
return str(data).encode("utf-8")
48-
return pickle.dumps(data, self._protocol)
36+
# class AioCacheSerializer(RedisSerializer):
37+
# def load(self, data: t.Any) -> t.Any:
38+
# try:
39+
# return int(data.decode("utf-8"))
40+
# except ValueError:
41+
# return pickle.loads(data)
42+
#
43+
# def dumps(self, data: t.Any) -> t.Any:
44+
# # Only skip pickling for integers, an int subclasses as bool should be
45+
# # pickled.
46+
# if type(data) is int:
47+
# return str(data).encode("utf-8")
48+
# return pickle.dumps(data, self._protocol)

ellar/cache/interface.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import typing as t
22
from abc import ABC, abstractmethod
33

4-
if t.TYPE_CHECKING:
4+
if t.TYPE_CHECKING: # pragma: no cover
55
from ellar.cache.model import BaseCacheBackend
66

77

0 commit comments

Comments
 (0)