Skip to main content

hypercache

Explicit, persistent caching for expensive Python functions and methods.

What it does

  • Caches expensive calls (API calls, embeddings, LLM generations)
  • Works with sync and async methods
  • Persists across restarts (disk, extensible to Redis)
  • Normalizes non-hashable inputs (dicts, Pydantic models, dataclasses, bytes)
  • Supports TTL, stale windows, and background refresh

Why not functools.lru_cache or cachetools

lru_cache cachetools hypercache
Async support No No Yes
Persistent storage No No Yes
Non-hashable inputs No No Yes (normalize)
Instance state in key N/A Manual config=
TTL / stale / refresh No TTL only Yes

Install

pip install hypercache

Observe cache telemetry

Any library can observe cache decisions by installing a scoped callback:

from hypercache import CachePolicy, CacheService, MemoryStore, observe_cache

cache = CacheService(MemoryStore())
events = []

with observe_cache(events.append):
    cache.run(
        instance="demo",
        operation="embed",
        version="embed:v1",
        inputs={"text": "hello"},
        policy=CachePolicy(),
        compute=lambda: {"vector": [1, 2, 3]},
    )

event = events[0]
assert event.hit is False
assert event.operation == "embed"

The observer is task-local via ContextVar, so nested async calls stay scoped to the current request or workflow run.

Basic usage

from datetime import timedelta
from hypercache import CachePolicy, CacheService, MemoryStore, cached


def _embedder_config(self) -> dict:
    return {"model": self.model, "dimensions": self.dimensions}


class Embedder:
    def __init__(self, model: str = "text-embedding-3-large", dimensions: int = 1536):
        self._cache = CacheService(MemoryStore(max_entries=512))
        self.model = model
        self.dimensions = dimensions

    @cached(
        version="embed:v1",
        policy=CachePolicy(
            ttl=timedelta(hours=6),
            stale=timedelta(minutes=30),
            refresh_in_background=True,
        ),
        config=_embedder_config,
    )
    async def embed(self, text: str) -> dict:
        return await call_embedding_api(text)
  • Inputs are auto-captured from the function signature. No duplicate parameter lists.
  • config= explicitly declares which instance state affects the cache key. No hidden method lookups.
  • version= lets you invalidate all cached values when the implementation changes.

Sharing config across methods

Define the config function once, reference it from multiple decorators:

def _llm_config(self) -> dict:
    return {"model": self.model, "temperature": self.temperature}


class LLM:
    def __init__(self, model: str, temperature: float):
        self._cache = CacheService(MemoryStore())
        self.model = model
        self.temperature = temperature

    @cached(version="generate:v1", policy=CachePolicy(), config=_llm_config)
    async def generate(self, prompt: str) -> dict:
        ...

    @cached(version="structured:v1", policy=CachePolicy(), config=_llm_config)
    async def generate_structured(self, prompt: str, schema: dict) -> dict:
        ...

Excluding inputs from the key

Use exclude= to drop arguments that shouldn't affect caching:

@cached(
    version="embed:v1",
    policy=CachePolicy(),
    config=_embedder_config,
    exclude=frozenset({"request_id", "trace_id"}),
)
async def embed(self, text: str, request_id: str | None = None, trace_id: str | None = None):
    ...

Persistent cache

Swap the store — everything else stays the same:

from pathlib import Path
from hypercache import DiskCacheStore

cache = CacheService(DiskCacheStore(Path("./cache")))

Direct usage (no decorator)

result = cache.run(
    instance=embedder,
    operation="embed",
    version="embed:v1",
    inputs={"text": "hello"},
    config={"model": embedder.model},
    policy=CachePolicy(),
    compute=lambda: embedder.embed_uncached("hello"),
)

Invalidation

Embedder.embed.key_for(embedder, "hello")     # inspect key
Embedder.embed.invalidate(embedder, "hello")   # delete one entry
Embedder.embed.clear(embedder)                 # delete all entries for this method

Design principles

  • No magic: no hidden method lookups, no Protocols that silently match by name
  • Explicit: config= in the decorator, not a convention on the class
  • DRY: inputs auto-captured from signature, no duplicate parameter lists
  • IDE-friendly: named functions, not lambdas; errors surface at import time

Release files for hypercache 0.2.2

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

Source distribution (sdist)

Source distribution for hypercache 0.2.2
File Size Uploaded
hypercache-0.2.2.tar.gz 10.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for hypercache 0.2.2
File Interpreter ABI Platform
hypercache-0.2.2-py3-none-any.whl Python 3 none any Details

Total release size: 23.1 kB

Release files / hypercache-0.2.2.tar.gz

Download URL hypercache-0.2.2.tar.gz
Size 10.2 kB
Tags Source
SHA-256 checksum
How to use checksums
583e47f865585d4cc6be7b96c0530fa468bb6d755e15e8c337f911551bd85369
BLAKE2b-256 checksum
How to use checksums
5b453f05f427c62006362ff691449c71abbc27740d6b22394322826a2303531d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.3

Release files / hypercache-0.2.2-py3-none-any.whl

Download URL hypercache-0.2.2-py3-none-any.whl
Size 12.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c3044ae79a3bb7021d46f0ce2302a86476a241f78a0e57225283727922f2bc8a
BLAKE2b-256 checksum
How to use checksums
1ce8d9d81d62b487e367c90c1c2c3ba4ce9f69c6e4862c760c1d9a9df2ff5306
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.3

Release history Release notifications | RSS feed

This release

0.2.2 This release

2 release files

0.2.1

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