Install & Compatibility
Where this runs
tested against v0.5.0 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslpy 3.10–3.95 runs
installs and imports cleanly · install 0.0s · import 0.084s · 18MB
glibcpy 3.10–3.95 runs
installs and imports cleanly · install 1.6s · import 0.074s · 18MB
16MB installed
● package 16MB
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
PersistentCache
✓ from shelved_cache import PersistentCache
AsyncPersistentCache
✓ from shelved_cache import AsyncPersistentCache
For asynchronous function caching, available in the 'decorators' submodule.
This quickstart demonstrates how to use `shelved-cache` to make a `cachetools.LRUCache` persistent. It shows a function being decorated, calls it multiple times to demonstrate caching, explicitly closes the cache, and then reopens it in a simulated new process to prove persistence. Ensure proper cleanup of the cache files created.
import cachetools
from shelved_cache import PersistentCache
from cachetools import LRUCache
import os
# Define a unique cache file path
cache_file = "my_function_cache.db"
# --- Cleanup any previous cache files for a clean run ---
# shelve can create multiple files (.db, .bak, .dir, .dat)
for ext in ["", ".bak", ".dir", ".dat"]:
if os.path.exists(cache_file + ext):
os.remove(cache_file + ext)
# Initialize a persistent LRU cache, linking it to a file
pc_for_square = PersistentCache(LRUCache, cache_file, maxsize=100)
@cachetools.cached(pc_for_square)
def square(x):
print(f"Calculating square for {x}...")
return x * x
# First call: calculation happens
result1 = square(5)
print(f"First call: square(5) = {result1}")
# Second call: result is retrieved from cache (no 'Calculating...' output)
result2 = square(5)
print(f"Second call: square(5) = {result2}")
# A different argument will trigger a new calculation and cache entry
result3 = square(10)
print(f"Third call: square(10) = {result3}")
# It's crucial to close the persistent cache to ensure data is written to disk.
pc_for_square.close()
print("\n--- Cache closed and reopened to demonstrate persistence ---")
# Simulate a new application run or process by creating a new PersistentCache instance
# linked to the *same* file.
pc_reopened = PersistentCache(LRUCache, cache_file, maxsize=100)
@cachetools.cached(pc_reopened)
def square_reopened(x):
# This should *not* print if the value was correctly persisted
print(f"Calculating square (reopened) for {x}...")
return x * x
# This call should retrieve from the persisted cache without recalculating
result_reopened = square_reopened(5)
print(f"Reopened call: square_reopened(5) = {result_reopened}")
pc_reopened.close()
# --- Final cleanup of created cache files ---
for ext in ["", ".bak", ".dir", ".dat"]:
if os.path.exists(cache_file + ext):
os.remove(cache_file + ext)
Debug
Known issues
breakingVersion 0.5.0 drops support for Python 3.9. Older versions (0.4.0) also dropped support for Python 3.7 and 3.8. Users should ensure they are running on Python 3.10 or newer.fixUpgrade Python to version 3.10.0 or higher.
affects: 0.4.0, 0.5.0
breakingVersion 0.5.0 requires `cachetools` version `^6.0.0`. Older versions of `cachetools` are no longer supported.fixUpgrade `cachetools` to version 6.0.0 or higher: `pip install "cachetools>=6.0.0,<7.0.0"`.
affects: 0.5.0
gotchaWhen decorating multiple functions with `shelved-cache`, each function MUST use a *separate* `PersistentCache` instance and a *different* file name for its persistence store. Reusing the same file for multiple caches will lead to errors.fixFor each decorated function, create a new `PersistentCache(cache_type, 'unique_filename.db', ...)` instance.
affects: All
gotchaThe underlying `shelve` module, which `shelved-cache` uses, does not natively support concurrent read/write access from multiple processes. While multiple simultaneous reads are safe, if one process has the shelf open for writing, no other process should have it open for reading or writing without explicit external locking. This can lead to data corruption or deadlocks in multi-process environments.fixFor multi-process applications requiring concurrent writes, consider external synchronization mechanisms (e.g., file locks, message queues) or an alternative cache backend (e.g., Redis, dedicated database).
affects: All
gotchaUsers on Windows with Python 3.13 and above might encounter permission errors or unexpected behavior. While earlier Windows issues were addressed, this specific combination has been noted as potentially problematic.fixIf encountering issues, consider using a different Python version, operating system, or an alternative caching solution on Windows.
affects: 0.4.0, 0.5.0 (with Python 3.13+ on Windows)
Errors
Common errors & fixes
ModuleNotFoundError: No module named 'shelved_cache'
The `shelved-cache` package is not installed in the current Python environment.
fixpip install shelved-cache
TypeError: shelved_cache() missing 2 required positional arguments: 'cache' and 'filename'
The `@shelved_cache` decorator requires a `cachetools` cache instance and a filename as arguments; it cannot be used without parameters.
fixProvide the required `cache` and `filename` arguments to the decorator, for example: `@shelved_cache(cachetools.LRUCache(maxsize=128), 'my_cache.db')`
ImportError: cannot import name 'ShelvedCache' from 'shelved_cache'
The `shelved-cache` library exports its main decorator as `shelved_cache` (lowercase), not `ShelvedCache` (camel case).
fixUse `from shelved_cache import shelved_cache` for the correct import.
OSError: [Errno 2] No such file or directory: 'your/non/existent/path/my_cache.db'
The specified cache file path in the `filename` argument includes a directory that does not exist. The underlying `shelve` module does not automatically create intermediate directories.
fixEnsure all intermediate directories in the `filename` path exist before initializing the `shelved_cache`, for example by using `os.makedirs(os.path.dirname(filename), exist_ok=True)`.
Upgrade
Version history
0.5.0latest on PyPI · released Dec 15, 2025
Audit
Dependencies
cachetoolsrequiredProvides the in-memory cache implementations (e.g., LRUCache) that Shelved Cache wraps for persistence. Version 0.5.0 supports cachetools ^6.0.0.