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)andf(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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d652a5d7ae451bdc1fca415fe348a645bf595ed6293fe995f084a3c27b51187f
|
|
| MD5 |
9915c8b7c77613e7019c8af6ca438b85
|
|
| BLAKE2b-256 |
c0b2a7cc1fd031d42d3c88036a7554f84d76603559724df54b9f9fde87df161f
|
Provenance
The following attestation bundles were made for kv_cache-0.3.4.tar.gz:
Publisher:
publish-pypi.yml on lcances/kv_cache
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
kv_cache-0.3.4.tar.gz -
Subject digest:
d652a5d7ae451bdc1fca415fe348a645bf595ed6293fe995f084a3c27b51187f - Sigstore transparency entry: 1073820090
- Sigstore integration time:
-
Permalink:
lcances/kv_cache@e8ef0a8ab450d6c770cb6d91b269d730fbf7b884 -
Branch / Tag:
refs/tags/0.3.4 - Owner: https://github.com/lcances
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@e8ef0a8ab450d6c770cb6d91b269d730fbf7b884 -
Trigger Event:
release
-
Statement type:
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8f11148ce135047d830089bc8419d6c6abc87b3c1add3ae02a9026011f709a75
|
|
| MD5 |
7dcd35d2825c0dac263c61ae3f58db7d
|
|
| BLAKE2b-256 |
695e81363ae588c2d1bb8887a56440eb3063ee0a1e38486dd71d8f157f166545
|
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
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
kv_cache-0.3.4-py3-none-any.whl -
Subject digest:
8f11148ce135047d830089bc8419d6c6abc87b3c1add3ae02a9026011f709a75 - Sigstore transparency entry: 1073820158
- Sigstore integration time:
-
Permalink:
lcances/kv_cache@e8ef0a8ab450d6c770cb6d91b269d730fbf7b884 -
Branch / Tag:
refs/tags/0.3.4 - Owner: https://github.com/lcances
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@e8ef0a8ab450d6c770cb6d91b269d730fbf7b884 -
Trigger Event:
release
-
Statement type: