Cache
persista.cache ¶
Contain caches.
persista.cache.AsyncTTLCache ¶
Async cache with per-entry expiry, backed by any
:class:~persista.store.base.AsyncBaseStore.
Each entry is wrapped as {"value": value, "expires_at":
expires_at} before being written to the store, since
:class:~persista.store.base.AsyncBaseStore only accepts dict
values. If the backing store is one that serializes values (e.g.
a SQLite- or Redis-backed store), cached values must be
JSON-serializable.
expires_at is a Unix timestamp (time.time()), not a
monotonic clock reading, because entries may be read back by a
different process or after a restart of this one. Expiry is
checked lazily on :meth:get: an expired entry is only evicted
the next time it is looked up, not proactively at its expiry
time.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
store
|
AsyncBaseStore | None
|
The backing store. Defaults to a new
:class: |
None
|
default_ttl
|
float
|
The default time-to-live, in seconds, applied to
entries whose |
300
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Example
>>> import asyncio
>>> from persista.cache import AsyncTTLCache
>>> async def main():
... cache = AsyncTTLCache(default_ttl=60)
... await cache.set("greeting", "hello")
... print(await cache.get("greeting"))
...
>>> asyncio.run(main())
hello
persista.cache.AsyncTTLCache.clear
async
¶
clear() -> None
Remove every entry from the cache, expired or not.
Example
>>> import asyncio
>>> from persista.cache import AsyncTTLCache
>>> async def main():
... cache = AsyncTTLCache()
... await cache.set("greeting", "hello")
... await cache.clear()
... print(await cache.get("greeting"))
...
>>> asyncio.run(main())
None
persista.cache.AsyncTTLCache.get
async
¶
get(key: str) -> Any | None
Retrieve a value by its key.
If the entry has expired, it is evicted from the backing
store as a side effect of this call, before None is
returned.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
The key to look up. |
required |
Returns:
| Type | Description |
|---|---|
Any | None
|
The cached value, or |
Any | None
|
its entry has expired. This means a cached value of |
Any | None
|
|
Example
>>> import asyncio
>>> from persista.cache import AsyncTTLCache
>>> async def main():
... cache = AsyncTTLCache()
... await cache.set("greeting", "hello")
... print(await cache.get("greeting"))
... print(await cache.get("missing"))
...
>>> asyncio.run(main())
hello
None
persista.cache.AsyncTTLCache.memoize ¶
memoize(
ttl: float | None = None,
strategy: str = "pickle",
ignore_non_serializable: bool = False,
) -> Callable[
[Callable[..., Awaitable[T]]],
Callable[..., Awaitable[T]],
]
Decorate an async function so its return values are cached.
The cache key is derived from the decorated function's
qualified name (__qualname__) and call arguments, via
:func:~persista.cache.utils.make_key, so calls with equal
arguments share a cached result. Call arguments must be
serializable with strategy, unless
ignore_non_serializable is set; the return value must
additionally be JSON-serializable if the backing store
serializes values (see the class docstring). Because the key
is based on __qualname__ rather than object identity, two
distinct functions defined with the same qualified name (e.g.
two calls to the same factory returning a closure) share
their cache entries.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ttl
|
float | None
|
The time-to-live, in seconds, applied to cached
results. Defaults to |
None
|
strategy
|
str
|
The serialization strategy used to compute the
cache key. Either |
'pickle'
|
ignore_non_serializable
|
bool
|
If |
False
|
Returns:
| Type | Description |
|---|---|
Callable[[Callable[..., Awaitable[T]]], Callable[..., Awaitable[T]]]
|
A decorator that wraps an async function with caching. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Example
>>> import asyncio
>>> from persista.cache import AsyncTTLCache
>>> cache = AsyncTTLCache()
>>> calls = []
>>> @cache.memoize(ttl=60)
... async def square(x):
... calls.append(x)
... return x * x
...
>>> async def main():
... print(await square(4))
... print(await square(4)) # served from the cache, not re-computed
...
>>> asyncio.run(main())
16
16
>>> calls
[4]
persista.cache.AsyncTTLCache.set
async
¶
set(key: str, value: Any, ttl: float | None = None) -> None
Add a value to the cache.
Calling this again with an existing key overwrites the previous value and resets its expiry.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
The key to set. |
required |
value
|
Any
|
The value to cache. Must be JSON-serializable if the backing store serializes values (see the class docstring). |
required |
ttl
|
float | None
|
The time-to-live, in seconds, before the entry
expires. Defaults to |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Example
>>> import asyncio
>>> from persista.cache import AsyncTTLCache
>>> async def main():
... cache = AsyncTTLCache()
... await cache.set("greeting", "hello")
... print(await cache.get("greeting"))
... await cache.set("greeting", "bonjour")
... print(await cache.get("greeting"))
...
>>> asyncio.run(main())
hello
bonjour
persista.cache.TTLCache ¶
Cache with per-entry expiry, backed by any
:class:~persista.store.base.BaseStore.
Each entry is wrapped as {"value": value, "expires_at":
expires_at} before being written to the store, since
:class:~persista.store.base.BaseStore only accepts dict
values. If the backing store is one that serializes values (e.g.
a SQLite- or Redis-backed store), cached values must be
JSON-serializable.
expires_at is a Unix timestamp (time.time()), not a
monotonic clock reading, because entries may be read back by a
different process or after a restart of this one. Expiry is
checked lazily on :meth:get: an expired entry is only evicted
the next time it is looked up, not proactively at its expiry
time.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
store
|
BaseStore | None
|
The backing store. Defaults to a new
:class: |
None
|
default_ttl
|
float
|
The default time-to-live, in seconds, applied to
entries whose |
300
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Example
>>> from persista.cache import TTLCache
>>> cache = TTLCache(default_ttl=60)
>>> cache.set("greeting", "hello")
>>> cache.get("greeting")
'hello'
persista.cache.TTLCache.clear ¶
clear() -> None
Remove every entry from the cache, expired or not.
Example
>>> from persista.cache import TTLCache
>>> cache = TTLCache()
>>> cache.set("greeting", "hello")
>>> cache.clear()
>>> cache.get("greeting") is None
True
persista.cache.TTLCache.get ¶
get(key: str) -> Any | None
Retrieve a value by its key.
If the entry has expired, it is evicted from the backing
store as a side effect of this call, before None is
returned.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
The key to look up. |
required |
Returns:
| Type | Description |
|---|---|
Any | None
|
The cached value, or |
Any | None
|
its entry has expired. This means a cached value of |
Any | None
|
|
Example
>>> from persista.cache import TTLCache
>>> cache = TTLCache()
>>> cache.set("greeting", "hello")
>>> cache.get("greeting")
'hello'
>>> cache.get("missing") is None
True
persista.cache.TTLCache.memoize ¶
memoize(
ttl: float | None = None,
strategy: str = "pickle",
ignore_non_serializable: bool = False,
) -> Callable[[Callable[..., T]], Callable[..., T]]
Decorate a function so its return values are cached.
Works on both sync and async functions (async def).
The cache key is derived from the decorated function's
qualified name (__qualname__) and call arguments, via
:func:~persista.cache.utils.make_key, so calls with equal
arguments share a cached result. Call arguments must be
serializable with strategy, unless
ignore_non_serializable is set; the return value must
additionally be JSON-serializable if the backing store
serializes values (see the class docstring). Because the key
is based on __qualname__ rather than object identity, two
distinct functions defined with the same qualified name (e.g.
two calls to the same factory returning a closure) share
their cache entries.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ttl
|
float | None
|
The time-to-live, in seconds, applied to cached
results. Defaults to |
None
|
strategy
|
str
|
The serialization strategy used to compute the
cache key. Either |
'pickle'
|
ignore_non_serializable
|
bool
|
If |
False
|
Returns:
| Type | Description |
|---|---|
Callable[[Callable[..., T]], Callable[..., T]]
|
A decorator that wraps a function with caching. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Example
>>> from persista.cache import TTLCache
>>> cache = TTLCache()
>>> calls = []
>>> @cache.memoize(ttl=60)
... def square(x):
... calls.append(x)
... return x * x
...
>>> square(4)
16
>>> square(4) # served from the cache, not re-computed
16
>>> calls
[4]
persista.cache.TTLCache.set ¶
set(key: str, value: Any, ttl: float | None = None) -> None
Add a value to the cache.
Calling this again with an existing key overwrites the previous value and resets its expiry.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
The key to set. |
required |
value
|
Any
|
The value to cache. Must be JSON-serializable if the backing store serializes values (see the class docstring). |
required |
ttl
|
float | None
|
The time-to-live, in seconds, before the entry
expires. Defaults to |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Example
>>> from persista.cache import TTLCache
>>> cache = TTLCache()
>>> cache.set("greeting", "hello")
>>> cache.get("greeting")
'hello'
>>> cache.set("greeting", "bonjour")
>>> cache.get("greeting")
'bonjour'
>>> cache.set("short-lived", "value", ttl=30)
persista.cache.async_cached ¶
async_cached(
ttl: int | None = None,
strategy: str = "pickle",
ignore_non_serializable: bool = False,
) -> Callable[
[Callable[..., Awaitable[T]]],
Callable[..., Awaitable[T]],
]
Cache an async function's return values in the shared default async cache.
Looks up :func:get_async_ttl_cache on every call, so replacing
the shared cache via :func:set_async_ttl_cache also changes
where already-decorated functions store their results.
The cache key is derived from the decorated function's qualified
name (__qualname__) and call arguments, via
:func:~persista.cache.utils.make_key.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ttl
|
int | None
|
The time-to-live, in seconds, applied to cached results.
Defaults to the cache's |
None
|
strategy
|
str
|
The serialization strategy used to compute the
cache key. Either |
'pickle'
|
ignore_non_serializable
|
bool
|
If |
False
|
Returns:
| Type | Description |
|---|---|
Callable[[Callable[..., Awaitable[T]]], Callable[..., Awaitable[T]]]
|
A decorator that wraps an async function with caching. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Example
>>> import asyncio
>>> from persista.cache import async_cached
>>> calls = []
>>> @async_cached(ttl=60)
... async def square(x):
... calls.append(x)
... return x * x
...
>>> async def main():
... print(await square(4))
... print(await square(4)) # served from the cache, not re-computed
...
>>> asyncio.run(main())
16
16
>>> calls
[4]
persista.cache.cached ¶
cached(
ttl: int | None = None,
strategy: str = "pickle",
ignore_non_serializable: bool = False,
) -> Callable[[Callable[..., T]], Callable[..., T]]
Cache a function's return values in the shared default cache.
Works on both sync and async functions (async def), by
looking up :func:get_ttl_cache on every call, so replacing the
shared cache via :func:set_ttl_cache also changes where
already-decorated functions store their results.
The cache key is derived from the decorated function's qualified
name (__qualname__) and call arguments, via
:func:~persista.cache.utils.make_key.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ttl
|
int | None
|
The time-to-live, in seconds, applied to cached results.
Defaults to the cache's |
None
|
strategy
|
str
|
The serialization strategy used to compute the
cache key. Either |
'pickle'
|
ignore_non_serializable
|
bool
|
If |
False
|
Returns:
| Type | Description |
|---|---|
Callable[[Callable[..., T]], Callable[..., T]]
|
A decorator that wraps a function with caching. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Example
>>> from persista.cache import cached
>>> calls = []
>>> @cached(ttl=60)
... def square(x):
... calls.append(x)
... return x * x
...
>>> square(4)
16
>>> square(4) # served from the cache, not re-computed
16
>>> calls
[4]
persista.cache.get_async_ttl_cache ¶
get_async_ttl_cache() -> AsyncTTLCache
Return the shared default async cache.
Returns:
| Type | Description |
|---|---|
AsyncTTLCache
|
The shared default :class: |
AsyncTTLCache
|
instance, used by :func: |
AsyncTTLCache
|
is given. |
Example
>>> import asyncio
>>> from persista.cache.interface import get_async_ttl_cache
>>> async def main():
... cache = get_async_ttl_cache()
... await cache.set("greeting", "hello")
... print(await cache.get("greeting"))
...
>>> asyncio.run(main())
hello
persista.cache.get_ttl_cache ¶
get_ttl_cache() -> TTLCache
Return the shared default cache.
Returns:
| Type | Description |
|---|---|
TTLCache
|
The shared default :class: |
TTLCache
|
instance, used by :func: |
TTLCache
|
given. |
Example
>>> from persista.cache.interface import get_ttl_cache
>>> cache = get_ttl_cache()
>>> cache.set("greeting", "hello")
>>> cache.get("greeting")
'hello'
persista.cache.make_json_key ¶
make_json_key(
func_name: str,
args: tuple[Any, ...],
kwargs: dict[str, Any],
ignore_non_serializable: bool = False,
) -> str
Derive a stable cache key from a function name and its call arguments.
func_name, args, and kwargs are JSON-serialized (with
kwargs keys sorted, so key order doesn't affect the result)
and hashed. args and the values in kwargs must be
JSON-serializable, unless ignore_non_serializable is set.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
func_name
|
str
|
The name of the function being cached, typically
its |
required |
args
|
tuple[Any, ...]
|
The positional arguments the function was called with.
Must be JSON-serializable, unless |
required |
kwargs
|
dict[str, Any]
|
The keyword arguments the function was called with.
Must be JSON-serializable, unless |
required |
ignore_non_serializable
|
bool
|
If |
False
|
Returns:
| Type | Description |
|---|---|
str
|
A hash of |
str
|
across calls with equal arguments regardless of |
str
|
order. |
Raises:
| Type | Description |
|---|---|
TypeError
|
If |
Example
>>> from persista.cache.utils import make_json_key
>>> make_json_key("add", (1, 2), {}) == make_json_key("add", (1, 2), {})
True
>>> make_json_key("add", (), {"a": 1, "b": 2}) == make_json_key("add", (), {"b": 2, "a": 1})
True
>>> make_json_key("add", (1, 2), {}) == make_json_key("add", (1, 3), {})
False
persista.cache.make_key ¶
make_key(
func_name: str,
args: tuple[Any, ...],
kwargs: dict[str, Any],
strategy: str = "pickle",
ignore_non_serializable: bool = False,
) -> str
Derive a stable cache key from a function name and its call arguments, using the given serialization strategy.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
func_name
|
str
|
The name of the function being cached, typically
its |
required |
args
|
tuple[Any, ...]
|
The positional arguments the function was called with.
Must be serializable with |
required |
kwargs
|
dict[str, Any]
|
The keyword arguments the function was called with.
Must be serializable with |
required |
strategy
|
str
|
The serialization strategy used to compute the key.
Either |
'pickle'
|
ignore_non_serializable
|
bool
|
If |
False
|
Returns:
| Type | Description |
|---|---|
str
|
A hash of |
str
|
across calls with equal arguments regardless of |
str
|
order. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
TypeError
|
If |
PicklingError
|
If |
Example
>>> from persista.cache.utils import make_key
>>> make_key("add", (1, 2), {}, strategy="json") == make_key(
... "add", (1, 2), {}, strategy="json"
... )
True
>>> make_key("add", (1, 2), {}) == make_key("add", (1, 3), {})
False
persista.cache.make_pickle_key ¶
make_pickle_key(
func_name: str,
args: tuple[Any, ...],
kwargs: dict[str, Any],
ignore_non_serializable: bool = False,
) -> str
Derive a stable cache key from a function name and its call arguments.
This is similar to make_json_key but uses pickle instead of
json to serialize func_name, args, and kwargs
before hashing, so it supports a broader range of argument types
at the cost of a key that is only stable within a single Python
version (pickle's format can change across versions).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
func_name
|
str
|
The name of the function being cached, typically
its |
required |
args
|
tuple[Any, ...]
|
The positional arguments the function was called with.
Must be picklable, unless |
required |
kwargs
|
dict[str, Any]
|
The keyword arguments the function was called with.
Must be picklable, unless |
required |
ignore_non_serializable
|
bool
|
If |
False
|
Returns:
| Type | Description |
|---|---|
str
|
A hash of |
str
|
across calls with equal arguments regardless of |
str
|
order. |
Raises:
| Type | Description |
|---|---|
PicklingError
|
If |
Example
>>> from persista.cache.utils import make_pickle_key
>>> make_pickle_key("add", (1, 2), {}) == make_pickle_key("add", (1, 2), {})
True
>>> make_pickle_key("add", (), {"a": 1, "b": 2}) == make_pickle_key(
... "add", (), {"b": 2, "a": 1}
... )
True
>>> make_pickle_key("add", (1, 2), {}) == make_pickle_key("add", (1, 3), {})
False
persista.cache.set_async_ttl_cache ¶
set_async_ttl_cache(cache: AsyncTTLCache) -> None
Replace the shared default async cache.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cache
|
AsyncTTLCache
|
The :class: |
required |
Example
>>> from persista.cache import AsyncTTLCache
>>> from persista.cache import get_async_ttl_cache, set_async_ttl_cache
>>> set_async_ttl_cache(AsyncTTLCache(default_ttl=60))
>>> get_async_ttl_cache().default_ttl
60
persista.cache.set_ttl_cache ¶
set_ttl_cache(cache: TTLCache) -> None
Replace the shared default cache.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cache
|
TTLCache
|
The :class: |
required |
Example
>>> from persista.cache import TTLCache
>>> from persista.cache import get_ttl_cache, set_ttl_cache
>>> set_ttl_cache(TTLCache(default_ttl=60))
>>> get_ttl_cache().default_ttl
60