Skip to main content

kv-cache

A fast, persistent key-value store using SQLite as a backend. Zero dependencies beyond the Python standard library. Designed for CLI tools needing persistent cache storage.

Features

  • SQLite-based persistent storage with WAL mode for performance
  • Built-in TTL (Time-to-Live) support with automatic cleanup
  • Thread-safe operations via thread-local connections
  • Function caching decorator (scache) supporting both sync and async functions
  • Deterministic cache key generation using SHA-256
  • Context manager support

Installation

pip install kv-cache

Quick Start

Basic Key-Value Operations

from kv_cache import KVStore

# Initialize the store
store = KVStore("cache.db")

# Store a value
store.set("user:1", {"name": "Alice", "age": 30})

# Store a value with a 1-hour TTL
store.set("session:abc", {"token": "xyz"}, ttl=3600)

# Retrieve values
user = store.get("user:1")               # {'name': 'Alice', 'age': 30}
missing = store.get("no_key", default=0)  # 0

# Delete a key
store.delete("user:1")

# List all keys, values, or items
store.keys()    # ['session:abc']
store.values()  # [{'token': 'xyz'}]
store.items()   # [('session:abc', {'token': 'xyz'})]

# Clear all entries
store.clear()

# Close the connection
store.close()

Context Manager

with KVStore("cache.db") as store:
    store.set("key", "value", ttl=60)
    print(store.get("key"))  # "value"
# Connection is automatically closed

Function Caching with scache

The scache decorator caches function return values. Cache keys are automatically generated from the function name and arguments.

import time
from kv_cache import KVStore, scache

store = KVStore("~/.myapp/cache.db")

@scache(ttl=3600, store=store)
def fetch_data(user_id, include_details=False):
    time.sleep(2)  # Simulate slow API call
    return {"user_id": user_id, "details": include_details}

fetch_data(42, include_details=True)   # Takes 2 seconds
fetch_data(42, include_details=True)   # Instant (cached)
fetch_data(42, include_details=False)  # Takes 2 seconds (different args = different key)

Async Function Caching

scache automatically detects async functions and wraps them accordingly.

@scache(ttl=300, store=store)
async def fetch_remote(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as resp:
            return await resp.json()

Custom Cache Key Function

Override the default key generation with a custom function:

def my_key_func(func, args, kwargs):
    # Only cache based on the first argument
    return f"{func.__name__}:{args[0]}"

@scache(ttl=600, store=store, key_func=my_key_func)
def search(query, page=1):
    return api.search(query, page)

Conditional Caching

Disable caching dynamically by setting a flag in the store:

@scache(ttl=3600, store=store, conditional_key="enable_cache")
def get_config():
    return load_config_from_disk()

# Caching is active by default
get_config()  # cached

# Disable caching by setting the conditional key to False
store.set("enable_cache", False)
get_config()  # always calls load_config_from_disk()

CLI Autocomplete Example

from kv_cache import KVStore

def get_completions(prefix: str) -> list:
    store = KVStore("~/.mycli/cache.db")

    cache_key = f"auto:{prefix}"
    results = store.get(cache_key)

    if results is None:
        results = fetch_from_remote_server(prefix)
        store.set(cache_key, results, ttl=3600)

    return results

API Reference

KVStore

KVStore(db_path: str, table_name: str = "key_value_store")

A persistent key-value store backed by SQLite.

Parameter Type Default Description
db_path str (required) Path to the SQLite database file. Parent directories are created automatically.
table_name str "key_value_store" Name of the SQLite table. Allows multiple logical stores in one database.

Methods

Method Signature Description
set set(key: str, value: Any, ttl: Optional[int] = None) Store a JSON-serializable value. Optional ttl in seconds.
get get(key: str, default: Any = None) -> Any Retrieve a value. Returns default if the key is missing or expired.
delete delete(key: str) Remove a key from the store.
keys keys() -> list Return all keys (including expired ones pending cleanup).
values values() -> list Return all deserialized values.
items items() -> list Return all (key, value) tuples.
clear clear() Delete all entries from the store.
close close() Close the database connection.

Context manager: KVStore supports with statements. The connection is closed on exit.

Thread safety: Each thread gets its own SQLite connection via threading.local().

Values: Any JSON-serializable Python object (dicts, lists, strings, numbers, booleans, None).


scache

scache(
    ttl: Optional[int] = None,
    store: Optional[KVStore] = None,
    conditional_key: str = '',
    key_func: Optional[Callable] = None
) -> Callable

Decorator that caches function return values in a KVStore.

Parameter Type Default Description
ttl Optional[int] None Cache lifetime in seconds. None means no expiration.
store Optional[KVStore] None KVStore instance to use. If None, creates a default store at cache.db.
conditional_key str '' A key in the store that controls whether caching is active. If the key's value is False, caching is bypassed.
key_func Optional[Callable] None Custom key generation function with signature (func, args, kwargs) -> str.

Key generation: By default, the cache key is a SHA-256 hash of the function name, serialized positional arguments, and sorted keyword arguments. This means:

  • Keyword argument order doesn't matter: f(a=1, b=2) and f(b=2, a=1) hit the same cache entry.
  • Different argument values always produce different keys.
  • Non-JSON-serializable objects fall back to their str() representation.

Return value caveat: Since None is used as the cache-miss sentinel, functions that return None will not be cached (the decorator will always re-execute them).

SQLite Configuration

The store uses the following SQLite pragmas for performance:

Pragma Value Purpose
journal_mode WAL Write-Ahead Logging for concurrent reads
synchronous NORMAL Balance between safety and speed
mmap_size 512 MB Memory-mapped I/O
cache_size 128 MB In-memory page cache
page_size 4 KB Database page size

Development

# Clone and install
git clone https://github.com/lcances/kv_cache.git
cd kv_cache
python -m venv venv
source venv/bin/activate
pip install -e ".[dev]"

# Run tests
pytest tests/

# Format code
black src/ tests/
isort src/ tests/

Requirements

  • Python >= 3.7
  • No external dependencies (stdlib only)

License

MIT License - see LICENSE for details.

Release files for kv-cache 0.3.4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for kv-cache 0.3.4
File Size Uploaded
kv_cache-0.3.4.tar.gz 25.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for kv-cache 0.3.4
File Interpreter ABI Platform
kv_cache-0.3.4-py3-none-any.whl Python 3 none any Details

Total release size: 37.5 kB

Release files / kv_cache-0.3.4.tar.gz

Download URL kv_cache-0.3.4.tar.gz
Size 25.7 kB
Tags Source
SHA-256 checksum
How to use checksums
d652a5d7ae451bdc1fca415fe348a645bf595ed6293fe995f084a3c27b51187f
BLAKE2b-256 checksum
How to use checksums
c0b2a7cc1fd031d42d3c88036a7554f84d76603559724df54b9f9fde87df161f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Mar 10, 2026.

Transparency log

Release files / kv_cache-0.3.4-py3-none-any.whl

Download URL kv_cache-0.3.4-py3-none-any.whl
Size 11.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8f11148ce135047d830089bc8419d6c6abc87b3c1add3ae02a9026011f709a75
BLAKE2b-256 checksum
How to use checksums
695e81363ae588c2d1bb8887a56440eb3063ee0a1e38486dd71d8f157f166545
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Mar 10, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.4 This release

2 release files

0.3.3

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page