Skip to content

Cache API

SyncCacheDB and AsyncCacheDB provide a persistent key-value cache backed by SQLite. Values are serialized with pickle, so only read data from trusted databases.

Basic usage

Sync

from scriptdb import SyncCacheDB


with SyncCacheDB.open("cache.db") as cache:
    cache.set("answer", {"value": 42})
    print(cache.get("answer"))

Async

from scriptdb import AsyncCacheDB


async with AsyncCacheDB.open("cache.db") as cache:
    await cache.set("answer", {"value": 42})
    print(await cache.get("answer"))

Methods

set(key, value, expire_sec=None)

Store any pickle-serializable value. None means no expiration. A positive expire_sec stores an absolute UTC expiration time. Zero or a negative value is immediately expired:

cache.set("forever", "value")
cache.set("temporary", "value", expire_sec=60)
cache.set("disabled", "value", expire_sec=0)

get(key, default=None)

Return the value or the default when the key is missing or expired:

user = cache.get("user:42", default={})

is_set(key)

Check whether a non-expired key exists without deserializing its value:

if cache.is_set("user:42"):
    refresh_user(cache.get("user:42"))

delete(key)

Delete one key and return the affected row count:

removed = cache.delete("user:42")

del_many(key_mask)

Delete keys matching a mask. * means any sequence of characters. The _ character is treated literally:

cache.del_many("user:*")

keys(key_mask)

Return non-expired keys matching the same mask syntax:

user_keys = cache.keys("user:*")

clear()

Delete all keys and return the number removed:

cache.clear()

cache() decorator

Decorate a sync callable with SyncCacheDB:

with SyncCacheDB.open("cache.db") as cache:
    @cache.cache(expire_sec=30)
    def square(value):
        print("calculated")
        return value * value

    square(4)  # calculates
    square(4)  # reads the cached result

Use key_func when the default key is not appropriate:

@cache.cache(key_func=lambda user_id: f"user:{user_id}")
def load_user(user_id):
    return fetch_user(user_id)

AsyncCacheDB.cache() returns an async wrapper and supports both async and sync callables:

@cache.cache(expire_sec=60, key_func=lambda url: url)
async def fetch(url):
    return await http_get(url)

The decorator caches return values, not exceptions. Choose keys carefully so different calls do not collide.

RAM key index

Enable cache_keys_in_ram=True to keep live key metadata in memory:

with SyncCacheDB.open("cache.db", cache_keys_in_ram=True) as cache:
    if cache.is_set("expensive:42"):
        value = cache.get("expensive:42")

This speeds up repeated negative existence checks and lets get() avoid a database query for known-missing keys. The index is process-local, is maintained by the cache API, and consumes memory proportional to the number of keys. Missing keys are normal cache misses; do not use this mode when another process modifies the same cache database.

Expired entries are cleaned periodically. expire_sec=None entries remain until explicitly deleted or cleared.