Skip to main content

A fast key-value store using SQLite for CLI tools

Project description

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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

kv_cache-0.3.4.tar.gz (25.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

kv_cache-0.3.4-py3-none-any.whl (11.8 kB view details)

Uploaded Python 3

File details

Details for the file kv_cache-0.3.4.tar.gz.

File metadata

  • Download URL: kv_cache-0.3.4.tar.gz
  • Upload date:
  • Size: 25.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for kv_cache-0.3.4.tar.gz
Algorithm Hash digest
SHA256 d652a5d7ae451bdc1fca415fe348a645bf595ed6293fe995f084a3c27b51187f
MD5 9915c8b7c77613e7019c8af6ca438b85
BLAKE2b-256 c0b2a7cc1fd031d42d3c88036a7554f84d76603559724df54b9f9fde87df161f

See more details on using hashes here.

Provenance

The following attestation bundles were made for kv_cache-0.3.4.tar.gz:

Publisher: publish-pypi.yml on lcances/kv_cache

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file kv_cache-0.3.4-py3-none-any.whl.

File metadata

  • Download URL: kv_cache-0.3.4-py3-none-any.whl
  • Upload date:
  • Size: 11.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for kv_cache-0.3.4-py3-none-any.whl
Algorithm Hash digest
SHA256 8f11148ce135047d830089bc8419d6c6abc87b3c1add3ae02a9026011f709a75
MD5 7dcd35d2825c0dac263c61ae3f58db7d
BLAKE2b-256 695e81363ae588c2d1bb8887a56440eb3063ee0a1e38486dd71d8f157f166545

See more details on using hashes here.

Provenance

The following attestation bundles were made for kv_cache-0.3.4-py3-none-any.whl:

Publisher: publish-pypi.yml on lcances/kv_cache

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page