Yet another Python cache library. This has Python 3 typing hints.
$ pip install cachepot
>>> from cachepot import CacheStore, FileSystemCacheBackend
>>> from cachepot.serializer.pickle import PickleSerializer
>>> store = CacheStore(
... namespace='testing',
... key_serializer=PickleSerializer(),
... value_serializer=PickleSerializer(),
... backend=FileSystemCacheBackend('/tmp'),
... default_expire_seconds=3600,
... )
>>> store.put({'some': 'key'}, {'some': 'value'})
>>> store.get({'some': 'key'})
{'some': 'value'}
>>> store.put({'some': 'short expiring key'}, {'some': 'value'}, expire_seconds=10)
>>> store.delete_expired()
0delete_expired() returns the number of entries removed when the backend can
observe that count. Redis handles TTL expiry server-side, so its backend
returns None when the deleted-entry count is unknown.
SQLite also opportunistically removes expired rows during later writes, while
delete_expired() remains available when you want to force a cleanup cycle.
Security note:
PickleSerializeruses Python'spicklemodule, which can execute arbitrary code during deserialization. The serializer is intentionally not exported fromcachepot's top-level namespace. Import it explicitly fromcachepot.serializer.pickleonly when the cache backend storage is fully under your control and trusted. For untrusted environments, preferJSONSerializerinstead.
result = store.proxy(some_func)(some_args, cache_key=some_arg)is the equivalent of
result = store.get(some_arg)
if result is None:
result = some_func(some_args)
store.put(some_arg, result)In short, this works as proxy. This helps to make codes straight forward.
cache_key and expire_seconds are keyword-only arguments of the proxy
itself, not of the proxied function. store.proxy(...) raises TypeError
at proxy creation time if the proxied function declares a parameter named
cache_key or expire_seconds, because those names are reserved for the
proxy.
When a proxied cache write fails, cachepot keeps returning the computed
result, emits a CachepotWarning, logs the failure on the cachepot.store
logger, and increments store.cache_write_failures. This lets applications
forward failures to their existing logging or metrics pipeline without giving
up graceful degradation.
Serializers convert python objects into bytes. Backends save/load bytes. So serializers and backends are independent. CacheStore is the facade of them.
Backends now enforce a finite per-entry size contract by default:
max_entry_bytes=8 * 1024 * 1024 (8 MiB). Entries larger than that are
rejected on save(), and load() checks the backend-side size before
materializing the payload into process memory. You can override the limit
per backend instance when your application has a different budget.
- Python3 typing supports
- namespaces
- Proxy method
- Expired entry cleanup
- str ... cachepot.serializer.str.StringSerializer
- pickle ... cachepot.serializer.pickle.PickleSerializer
- JSON ... cachepot.serializer.json.JSONSerializer
And more serializers you can define.
- Save to files ... cachepot.backend.filesystem.FileSystemCacheBackend
- Save to SQLite3 DB records ... cachepot.backend.sqlite.SQLiteCacheBackend
- Save to Redis DB ... cachepot.backend.redis.RedisCacheBackend
Of course you can define own backend.
This repository uses lefthook to run the same checks as CI locally, so problems surface before they reach CI.
# Install dependencies
uv sync
# Install the Git hooks (once; requires lefthook on your PATH)
lefthook installOnce installed, the hooks run automatically:
- pre-commit:
uv run poe check - pre-push:
uv run poe checkanduv run poe test
You can also run the checks manually:
uv run poe check
uv run poe testCI still runs the full matrix (see .github/workflows/); the hooks only bring that
feedback earlier on your machine.
The 3-Clause BSD License. See also LICENSE file.