Skip to content

Commit

Permalink
NEW: implement cache prefix, resolves #31
Browse files Browse the repository at this point in the history
  • Loading branch information
eigenein committed Aug 18, 2023
1 parent 53a6662 commit f3dbf9d
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 18 deletions.
19 changes: 12 additions & 7 deletions cachetory/caches/async_.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@
class Cache(AbstractAsyncContextManager, Generic[ValueT, WireT]):
"""Asynchronous cache."""

__slots__ = ("_serializer", "_backend", "_serialize_executor")
__slots__ = ("_serializer", "_backend", "_serialize_executor", "_prefix")

def __init__(
self,
*,
serializer: Serializer[ValueT, WireT],
backend: AsyncBackend[WireT],
serialize_executor: Union[None, Executor, NotSet] = _NOT_SET,
prefix: str = "",
) -> None:
"""
Instantiate a cache.
Expand All @@ -34,24 +35,28 @@ def __init__(
using the executor (for example, `ProcessPoolExecutor`).
This may be useful to better utilize CPU when caching large blobs.
If not specified, (de)serialization is performed in the current thread.
prefix: backend key prefix
"""
self._serializer = serializer
self._backend = backend
self._serialize_executor = serialize_executor
self._prefix = prefix

async def get(self, key: str, default: DefaultT = None) -> Union[ValueT, DefaultT]: # type: ignore
try:
data = await self._backend.get(key)
data = await self._backend.get(f"{self._prefix}{key}")
except KeyError:
return default
else:
return await self._deserialize(data)

async def get_many(self, *keys: str) -> Dict[str, ValueT]:
return {key: await self._deserialize(data) async for key, data in self._backend.get_many(*keys)}
return {
f"{self._prefix}{key}": await self._deserialize(data) async for key, data in self._backend.get_many(*keys)
}

async def expire_in(self, key: str, time_to_live: Optional[timedelta] = None) -> None:
return await self._backend.expire_in(key, time_to_live)
return await self._backend.expire_in(f"{self._prefix}{key}", time_to_live)

async def set( # noqa: A003
self,
Expand All @@ -61,7 +66,7 @@ async def set( # noqa: A003
if_not_exists: bool = False,
) -> None:
await self._backend.set(
key,
f"{self._prefix}{key}",
await self._serialize(value),
time_to_live=time_to_live,
if_not_exists=if_not_exists,
Expand All @@ -70,10 +75,10 @@ async def set( # noqa: A003
async def set_many(self, items: Union[Iterable[Tuple[str, ValueT]], Mapping[str, ValueT]]) -> None:
if isinstance(items, Mapping):
items = items.items()
await self._backend.set_many([(key, await self._serialize(value)) for key, value in items])
await self._backend.set_many([(f"{self._prefix}{key}", await self._serialize(value)) for key, value in items])

async def delete(self, key: str) -> bool:
return await self._backend.delete(key)
return await self._backend.delete(f"{self._prefix}{key}")

async def __aexit__(self, exc_type, exc_val, exc_tb) -> None:
return await self._backend.__aexit__(exc_type, exc_val, exc_tb)
Expand Down
30 changes: 19 additions & 11 deletions cachetory/caches/sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,18 @@
class Cache(AbstractContextManager, Generic[ValueT, WireT]):
"""Synchronous cache."""

__slots__ = ("_serializer", "_backend")
__slots__ = ("_serializer", "_backend", "_prefix")

def __init__(self, *, serializer: Serializer[ValueT, WireT], backend: SyncBackend[WireT]) -> None:
"""Instantiate a cache."""
def __init__(self, *, serializer: Serializer[ValueT, WireT], backend: SyncBackend[WireT], prefix: str = "") -> None:
"""
Instantiate a cache.
Args:
prefix: backend key prefix
"""
self._serializer = serializer
self._backend = backend
self._prefix = prefix

def __getitem__(self, key: str) -> ValueT:
"""
Expand All @@ -33,7 +39,7 @@ def __getitem__(self, key: str) -> ValueT:
>>> with pytest.raises(KeyError):
>>> _ = cache["missing"]
"""
return self._serializer.deserialize(self._backend.get(key))
return self._serializer.deserialize(self._backend.get(f"{self._prefix}{key}"))

def get(self, key: str, default: DefaultT = None) -> Union[ValueT, DefaultT]: # type: ignore
"""
Expand Down Expand Up @@ -67,7 +73,9 @@ def get_many(self, *keys: str) -> Dict[str, ValueT]:
>>> cache["key"] = 42
>>> assert cache.get_many("key", "missing") == {"key": 42}
"""
return {key: self._serializer.deserialize(data) for key, data in self._backend.get_many(*keys)}
return {
f"{self._prefix}{key}": self._serializer.deserialize(data) for key, data in self._backend.get_many(*keys)
}

def expire_in(self, key: str, time_to_live: Optional[timedelta] = None) -> None:
"""
Expand All @@ -77,11 +85,11 @@ def expire_in(self, key: str, time_to_live: Optional[timedelta] = None) -> None:
key: cache key
time_to_live: time to live, or `None` to make it eternal
"""
return self._backend.expire_in(key, time_to_live)
return self._backend.expire_in(f"{self._prefix}{key}", time_to_live)

def __setitem__(self, key: str, value: ValueT) -> None:
"""Set the cache item. To customize the behavior, use `set()`."""
self._backend.set(key, self._serializer.serialize(value), time_to_live=None)
self._backend.set(f"{self._prefix}{key}", self._serializer.serialize(value), time_to_live=None)

def set( # noqa: A003
self,
Expand All @@ -100,7 +108,7 @@ def set( # noqa: A003
if_not_exists: only set the item if it does not already exist
"""
self._backend.set(
key,
f"{self._prefix}{key}",
self._serializer.serialize(value),
time_to_live=time_to_live,
if_not_exists=if_not_exists,
Expand All @@ -109,13 +117,13 @@ def set( # noqa: A003
def set_many(self, items: Union[Iterable[Tuple[str, ValueT]], Mapping[str, ValueT]]) -> None:
if isinstance(items, Mapping):
items = items.items()
self._backend.set_many((key, self._serializer.serialize(value)) for key, value in items)
self._backend.set_many((f"{self._prefix}{key}", self._serializer.serialize(value)) for key, value in items)

def delete(self, key: str) -> bool:
return self._backend.delete(key)
return self._backend.delete(f"{self._prefix}{key}")

def __delitem__(self, key: str) -> None:
self._backend.delete(key)
self.delete(key)

def __exit__(self, exc_type, exc_val, exc_tb) -> None:
return self._backend.__exit__(exc_type, exc_val, exc_tb)

0 comments on commit f3dbf9d

Please sign in to comment.