Skip to main content

PicoCache: Persistent Memoization

A Persistent, datastore‑backed lru_cache for Python.
PicoCache gives you the ergonomics of functools.lru_cache while keeping your cached values safe across process restarts and even across machines.
PicoCache ships with a zero‑dependency SQLiteCache that relies only on the standard‑library sqlite3 module. Additional back‑ends can be enabled via extras:

  • SQLAlchemyCache – persists to any SQL database supported by SQLAlchemy.
  • RedisCache – stores values in Redis, ideal for distributed deployments.
  • DjangoCache – plugs straight into Django’s configured cache backend (Memcached, Redis, database, etc.).

Why PicoCache?

  • Familiar API – decorators feel identical to functools.lru_cache.
  • Durable – survive restarts, scale horizontally.
  • Introspectable – cache_info() and cache_clear() just like the standard library.
  • Zero boilerplate – pass a connection URL and start decorating.

Installation

# core (built‑in SQLiteCache, no external deps)
pip install picocache

# optional extras
pip install picocache[redis]        # RedisCache
pip install picocache[sqlalchemy]   # SQLAlchemyCache
pip install picocache[django]       # DjangoCache
# or any combination, e.g.
pip install "picocache[redis,sqlalchemy]"

Quick‑start

1. Built‑in SQLiteCache (no external deps)

from picocache import SQLiteCache

cache = SQLiteCache()     # defaults to ./picocache.db

@cache
def fib(n: int) -> int:
    return n if n < 2 else fib(n - 1) + fib(n - 2)

2. SQLAlchemy back‑end

from picocache import SQLAlchemyCache

# Create the decorator bound to an SQLite file
sql_cache = SQLAlchemyCache("sqlite:///cache.db")

@sql_cache(maxsize=256)        # feels just like functools.lru_cache
def fib(n: int) -> int:
    return n if n < 2 else fib(n - 1) + fib(n - 2)

3. Redis

from picocache import RedisCache

redis_cache = RedisCache("redis://localhost:6379/0")

@redis_cache(maxsize=128, typed=True)
def slow_add(a: int, b: int) -> int:
    print("Executing body…")
    return a + b

On the second call with the same arguments, slow_add() returns instantly and “Executing body…” is not printed – the result came from Redis.

4. Django

from picocache import DjangoCache

django_cache = DjangoCache()          # uses settings.CACHES["default"]

@django_cache(maxsize=None)           # unlimited size, rely on Django’s TTL
def expensive_fn(x):
    ...

Thread Safety

PicoCache is fully thread-safe. Multiple threads can safely call decorated functions concurrently without any additional synchronization.

Key Thread Safety Features:

  1. Atomic Operations: All cache operations (lookup, store, evict) are atomic and protected by locks.
  2. No Duplicate Computation: If multiple threads request the same uncached value simultaneously, only one thread computes it while others wait for the result.
  3. Safe Statistics: Hit/miss counters are updated atomically.
  4. Concurrent Access: Different threads can safely access different cached values in parallel.

Backend-Specific Notes:

  • SQLiteCache: Uses a global lock for all operations. Thread-safe but may become a bottleneck under high concurrency.
  • RedisCache: Leverages Redis's atomic operations and connection pooling for excellent concurrent performance.
  • SQLAlchemyCache: Uses SQLAlchemy's connection pooling for thread-safe database access.
  • DjangoCache: Inherits thread safety from Django's cache framework. When maxsize is specified, adds an additional functools.lru_cache layer which is also thread-safe.

Example with Threading:

from picocache import SQLiteCache
import threading

cache = SQLiteCache()

@cache(maxsize=128)
def expensive_computation(x):
    import time
    time.sleep(1)  # Simulate expensive work
    return x * x

# Multiple threads can safely call the cached function
threads = []
for i in range(10):
    t = threading.Thread(target=lambda: expensive_computation(5))
    threads.append(t)
    t.start()

for t in threads:
    t.join()

# Only one thread will perform the computation; others will wait and reuse the result
print(expensive_computation.cache_info())  # Shows hits=9, misses=1

API

Each decorator is constructed with connection details (if any) and called with the same signature as functools.lru_cache:

SQLAlchemyCache(url_or_engine, *, key_serializer=None, value_serializer=None, ...)
RedisCache(url_or_params, *, key_serializer=None, value_serializer=None, ...)
DjangoCache(*, key_serializer=None, value_serializer=None, ...)

__call__(maxsize=None, typed=False)

Returns a decorator that memoises the target function.

Param Type Default Meaning
maxsize int/None None Per‑function entry limit (None → no limit).
typed bool False Treat arguments with different types as distinct (same as stdlib).

The wrapped function gains:

  • .cache_info() → namedtuple(hits, misses, currsize, maxsize)
  • .cache_clear() or .clear() → empties the persistent store for that function.

Running the tests

uv sync --all-extras
just test
  • SQL tests run against an in‑memory SQLite DB (no external services).
  • Redis tests are skipped automatically unless a Redis server is available on localhost:6379.

License

MIT – see LICENSE for details.

Metadata

Release files for picocache 1.4.0

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

Source distribution (sdist)

Source distribution for picocache 1.4.0
File Size Uploaded Provenance
picocache-1.4.0.tar.gz 14.3 kB Without provenance Details

Built distribution (wheel)

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

Total release size: 30.1 kB

Release files / picocache-1.4.0.tar.gz

Download URL picocache-1.4.0.tar.gz
Size 14.3 kB
Tags Source
SHA-256 checksum
How to use checksums
d7d14c0065311046e16a7b2dd283816a78e7d22d4b5dbf398ddb5ca7d3b27011
BLAKE2b-256 checksum
How to use checksums
b61ceda90e7ce3fd53a53f85ffe324f51a14ac95eaef0c3c2b277ad503ab11e4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.13.0 {"installer":{"name":"uv","version":"0.13.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / picocache-1.4.0-py3-none-any.whl

Download URL picocache-1.4.0-py3-none-any.whl
Size 15.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0846b94fcfd14cb3faa1738acf23b2a538c21ba446be3bcc8c11ec0e6fa0192d
BLAKE2b-256 checksum
How to use checksums
ee2dbc9516f43030be1b1c5949c79c068357166bbcbb86a408adce9fde4dc54b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.13.0 {"installer":{"name":"uv","version":"0.13.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Security for picocache 1.4.0

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

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