Cashews
Cashews is a Python library providing asynchronous cache tools, designed to help build fast and reliable applications. It supports multiple storage backends like in-memory, Redis, and DiskCache, offering a decorator-based API and various caching strategies. The current version is 7.5.0, and it maintains an active release cadence with regular updates and community support.
Warnings
- breaking Cashews dropped support for Python 3.9 starting from version 7.5.0. Ensure your project uses Python 3.10 or newer.
- gotcha The `ttl` (time-to-live) parameter is mandatory for all cache decorators and direct cache operations to prevent unbounded storage growth and ensure proper cache invalidation. Failing to provide `ttl` can lead to memory or storage overflow.
- gotcha When using Redis, Cashews defaults to `pickle` for serializing values. While convenient, `pickle` can have security implications with untrusted data and may not serialize all object types. It's recommended to use the `secret` and `digestmod` parameters for enhanced security, or consider other serialization options if available.
- gotcha Using wildcard patterns (e.g., `"items:page:*"`) with `cache.invalidate()` when connected to a Redis backend can be inefficient. This operation might scan the entire Redis database, leading to performance issues on large datasets.
- gotcha In earlier versions (prior to 7.4.4), improper cross-context usage of Cashews could lead to `ContextVar LookupError`. This typically occurs in complex asynchronous applications where contexts are not managed correctly.
- gotcha When utilizing Redis client-side caching with Cashews, manually modifying or expiring keys in Redis directly (e.g., via `redis-cli`) will invalidate the client-side cache for those keys, but Cashews' internal state might not immediately reflect these external changes if not managed carefully. This can lead to unexpected cache misses or stale data if not properly accounted for.
Install
-
pip install cashews -
pip install cashews[redis] -
pip install cashews[diskcache] -
pip install cashews[speedup] -
pip install cashews[dill]
Imports
- cache
from cashews import cache
Quickstart
import asyncio
import os
from datetime import timedelta
from cashews import cache
# Configure Redis cache. Replace with your Redis URL or use "mem://" for in-memory.
# For production, use environment variables for connection strings.
REDIS_URL = os.environ.get("CASHEWS_REDIS_URL", "redis://localhost:6379/0")
cache.setup(REDIS_URL, client_side=True)
@cache(ttl=timedelta(minutes=5), key="user:{user_id}")
async def get_user_data(user_id: int):
"""
Simulates a long-running operation to fetch user data.
This function's result will be cached.
"""
print(f"Fetching data for user_id: {user_id} from source...")
await asyncio.sleep(1) # Simulate I/O delay
return {"id": user_id, "name": f"User {user_id}", "email": f"user{user_id}@example.com"}
async def main():
print("First call (should fetch from source):")
user1_data = await get_user_data(1)
print(f"Result: {user1_data}")
print("\nSecond call (should hit cache):")
user1_data_cached = await get_user_data(1)
print(f"Result: {user1_data_cached}")
print("\nFetching data for a different user (should fetch from source):")
user2_data = await get_user_data(2)
print(f"Result: {user2_data}")
# Example of explicit cache invalidation:
# await cache.invalidate(get_user_data, user_id=1)
# print("\nAfter invalidation, first call again (should fetch from source):")
# user1_data_recalled = await get_user_data(1)
# print(f"Result: {user1_data_recalled}")
if __name__ == "__main__":
asyncio.run(main())