Skip to main content

A lightweight, SQLite-backed cache for Python with first-class sync and async support.

Project description

Cachetronomy

A lightweight, SQLite-backed cache for Python with first-class sync and async support. Features TTL and memory-pressure eviction, persistent hot-key tracking, pluggable serialization, a decorator API and a CLI.

Package Version | Supported Python Versions | PyPI Downloads | License | GitHub Last Commit | Status | Dynamic TOML Badge

Why Cachetronomy?

  • Persistent: stores entries in SQLite; survives restarts—no external server.
  • Unified API: one Cachetronaut class handles both sync and async calls via synchronaut.
  • Smart Eviction: TTL expiry and RAM-pressure eviction run in background tasks.
  • Hot-Key Tracking: logs every read in memory & SQLite; query top-N hotspots.
  • Flexible Serialization: JSON, orjson, MsgPack out-of-the-box; swap in your own.
  • Decorator API: wrap any function or coroutine to cache its results automatically.
  • CLI: full-featured command-line interface for inspection and maintenance.

Installation

pip install cachetronomy
# for orjson & msgpack support:
pip install cachetronomy[fast]

Quick Start

The same Cachetronaut client works in both sync and async code — call its methods directly or await them. See the examples/ directory for fuller, runnable demos.

from cachetronomy import Cachetronaut

cache = Cachetronaut(db_path='cachetronomy.db')

# Basic set / get — values persist across restarts.
cache.set('user:1', {'name': 'Alice'}, time_to_live=300)
cache.get('user:1')        # {'name': 'Alice'}
cache.get('missing')       # None

# Memoize any function with the decorator. The key is built from the
# function name and its arguments; the return value is cached automatically.
@cache(time_to_live=900)
def expensive(n: int) -> int:
    return sum(range(n))

expensive(1_000_000)       # computed once, then served from cache

cache.shutdown()

The decorator works on coroutines too:

import asyncio
from cachetronomy import Cachetronaut

cache = Cachetronaut(db_path='cachetronomy.db')

@cache(time_to_live=60)
async def fetch_user(user_id: int) -> dict:
    await asyncio.sleep(0.5)            # simulate I/O
    return {'id': user_id, 'name': 'Ash'}

async def main():
    await fetch_user(1)                # miss → runs the coroutine
    await fetch_user(1)                # hit  → returned from cache
    await cache.shutdown()

asyncio.run(main())

None is a real cached value, not a miss. Pass a sentinel as default to tell them apart:

MISS = object()
cache.set('maybe', None, time_to_live=60)
cache.get('maybe')                     # None  (cached value)
cache.get('maybe', default=MISS)       # None  (a hit)
cache.get('absent', default=MISS)      # MISS  (a genuine miss)

CLI Usage

The cachetronomy command provides a full-featured CLI for cache inspection and maintenance.

Basic Commands

# Get help
cachetronomy --help

# Set a value with TTL
cachetronomy set --time-to-live=300 my-key "my value"

# Get a value
cachetronomy get my-key

# Delete a key
cachetronomy delete my-key

# List all keys
cachetronomy all-keys

# List profiles
cachetronomy list-profiles

# View store statistics
cachetronomy store-stats

# Clear expired entries
cachetronomy clear-expired

# Clear by tags
cachetronomy clear-by-tags --tags='["api"]' --exact-match=false

Common Operations

Set and retrieve values:

# Store with TTL
cachetronomy set --time-to-live=3600 user:1 '{"name": "Alice"}'

# Retrieve
cachetronomy get user:1

# With tags
cachetronomy set --tags='["users", "api"]' user:2 '{"name": "Bob"}'

Profile management:

# List available profiles
cachetronomy list-profiles

# Switch profile
cachetronomy set-profile production

# Get current profile
cachetronomy get-profile

Maintenance:

# Clear expired entries
cachetronomy clear-expired

# Clear all cache
cachetronomy clear-all

# View access logs
cachetronomy access-logs

# View eviction logs
cachetronomy eviction-logs

Database Path

By default, the CLI uses cachetronomy.db in the current directory. Specify a different path:

cachetronomy --db-path /path/to/cache.db list-profiles

Note on CLI Limitations

Some methods are not available via CLI due to type complexity:

  • get_many, set_many, delete_many - Use Python API for bulk operations
  • health_check, stats - Use Python API for monitoring dicts
  • get_or_compute - Use Python API for read-through caching

These methods remain fully functional in the Python API.

Core Mechanisms

Mechanism How It Works
Key Building Generates a consistent, order-independent key from the function name and its arguments.
Cache Lookup On get(), check the in-memory cache first; if the entry is missing or stale, continues to the next storage layer.
Storage On set(), stores the newly computed result both in memory (for speed) and in a small on-disk database (for persistence).
Profiles & Settings Lets you switch between saved caching profiles and settings without disrupting running code.
TTL Eviction A background task periodically deletes entries that have exceeded their time-to-live.
Memory-Pressure Eviction Another background task frees up space by evicting the least-used entries when available system memory gets too low.
Manual Eviction Helper methods allow you to remove individual keys or groups of entries whenever you choose.
Hot-Key Tracking Records how frequently each key is accessed so the system knows which items are most important to keep.
Serialization Converts data into a compact binary or JSON-like format before writing it to storage, and remembers which format it used.

API Reference

Note: Each cachetronomy CLI invocation is a fresh, stateless process, so in-memory features (hot-key tracking, memory-pressure eviction, etc.) aren’t available. All persistent, “cold-storage” operations (get/set against the SQLite store, TTL cleanup, access-log and eviction-log reporting, profiles, etc.) still work as expected.

Method Description
__init__ Construct a new cache client with the given database path and settings.
shutdown Gracefully stop eviction threads and close the underlying database connection.
set Store a value under key with optional TTL, tags, serializer, etc.
get Retrieve a cached entry, optionally unmarshaled into a Pydantic model. Returns default (None) on a miss; pass a sentinel as default to tell a real miss apart from a cached None.
delete Remove the given key from the cache immediately.
get_many Retrieve multiple keys at once, returning a dict of key-value pairs.
set_many Store multiple key-value pairs at once with optional TTL and tags.
delete_many Delete multiple keys at once, returning the count of keys that existed.
health_check Perform a health check, returning system status (healthy/degraded/unhealthy, db accessible, memory ok, key counts).
stats Get comprehensive cache statistics (total keys, hot keys, evictions, profile info).
get_or_compute Read-through helper: get a value from cache, or compute and cache it on a miss. (Does not provide stampede protection.)
evict Remove a key from the in-memory cache without deleting it from the persistent store.
store_keys Return a list of all keys currently persisted in cold storage.
memory_keys Return a list of all keys currently held in the in-process memory cache.
all_keys List every key across both memory and the persistent store.
key_metadata Fetch the metadata (TTL, serialization format, tags, version, etc.) for a single cache key.
store_metadata Retrieve a list of metadata objects for every entry in the persistent store.
items List every cached item in the persistent store.
evict_all Evict every entry from memory (logs each eviction) but leaves the store intact.
clear_all Delete all entries from both memory and store without logging individually.
clear_expired Purge only those entries whose TTL has elapsed.
clear_by_tags Remove entries matching any of the provided tags.
clear_by_profile Remove all entries that were saved under the given profile name.
memory_stats Return the top-N hottest keys by in-memory access count.
store_stats Return the top-N hottest keys by persisted access count.
access_logs Fetch raw access-log rows from SQLite for detailed inspection.
key_access_logs Fetch all access-log entries for a single key.
clear_access_logs Delete all access-log rows from the database.
delete_access_logs Delete all access-log rows for the given key.
eviction_logs Fetch recent eviction events (manual, TTL, memory-pressure, etc.).
clear_eviction_logs Delete all recorded eviction events.
profile (@property) Get current Profile.
set_profile Switch to a named Profile, applying its settings and restarting eviction threads.
update_active_profile Modify the active profile’s settings in-place and persist them.
get_profile Load the settings of a named profile without applying them.
delete_profile Remove a named profile from the profiles table.
list_profiles List all saved profiles available in the profiles table.

Database Schema

cache Table

Stores serialized cached objects, their TTL metadata, tags, and versioning.

Column Type Description
key TEXT (PK 🔑) Unique cache key
data BLOB Serialized value (orjson, msgpack, json)
fmt TEXT Serialization format used
expire_at DATETIME UTC expiry time.
tags TEXT Serialized list of tags (JSON)
version INTEGER Version number for schema evolution/versioning
saved_by_profile TEXT Profile name that created or last updated this entry

access_log Table

Tracks when a key was accessed and how frequently.

Column Type Description
key TEXT (PK 🔑) Cache key
access_count INTEGER Number of times accessed
last_accessed DATETIME Most recent access time
last_accessed_by_profile TEXT Profile that made the last access

eviction_log Table

Tracks key eviction events and their reasons (manual, TTL, memory, tag).

Column Type Description
id INTEGER (PK 🔑) Autoincrement ID
key TEXT Evicted key
evicted_at DATETIME Timestamp of eviction
reason TEXT Reason string ('manual_eviction', 'time_eviction', etc.)
last_access_count INTEGER Final recorded access count before eviction
evicted_by_profile TEXT Name of profile that triggered the eviction

profiles Table

Holds saved profile configurations for future reuse.

Column Type Description
name TEXT (PK 🔑) Unique profile name
time_to_live INTEGER Default TTL for entries
ttl_cleanup_interval INTEGER Frequency in seconds to run TTL cleanup
memory_based_eviction BOOLEAN Whether memory pressure-based eviction is enabled
free_memory_target REAL MB of free RAM to maintain
memory_cleanup_interval INTEGER How often to check system memory
max_items_in_memory INTEGER Cap for in-RAM cache
tags TEXT Default tags for all entries in this profile

Development & Testing

git clone https://github.com/cachetronaut/cachetronomy.git
cd cachetronomy
uv run --extra fast --extra dev python -m pytest -q   # run the test suite
uv run --extra lint ruff check src                    # lint

There is 100% parity between sync and async clients via synchronaut; coverage includes TTL, memory eviction, decorator api, profiles, serialization and logging.

Contributing

  1. Fork & branch
  2. Add tests for new features
  3. Submit a PR

See AGENTS.md for repository conventions.

License

MIT — 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

cachetronomy-0.4.1.tar.gz (92.4 kB view details)

Uploaded Source

Built Distribution

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

cachetronomy-0.4.1-py3-none-any.whl (41.1 kB view details)

Uploaded Python 3

File details

Details for the file cachetronomy-0.4.1.tar.gz.

File metadata

  • Download URL: cachetronomy-0.4.1.tar.gz
  • Upload date:
  • Size: 92.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for cachetronomy-0.4.1.tar.gz
Algorithm Hash digest
SHA256 37e32c6a22a991a9a06a6759b2a56a1a62def0e85f926340aa1f8827abe1104c
MD5 fcb9ecb5e214b83598c0fa05d3fed46d
BLAKE2b-256 c4490991ab1bfb60e1233679d0b30942780bf414ffbb39b04f75281d60244909

See more details on using hashes here.

File details

Details for the file cachetronomy-0.4.1-py3-none-any.whl.

File metadata

  • Download URL: cachetronomy-0.4.1-py3-none-any.whl
  • Upload date:
  • Size: 41.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for cachetronomy-0.4.1-py3-none-any.whl
Algorithm Hash digest
SHA256 f79fd8e9802acf4ef8a382d396e5423b4dffdccbf6203d2357af7dbce165a895
MD5 39f5bf0b68eda85a2438e0c8241a2a12
BLAKE2b-256 fe8e6930aea7d49ed9453601ae9604615cbac5482ebc727f3bfb5fbc76d27c78

See more details on using hashes here.

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