base-cacheable-class
A flexible base class for adding caching capabilities to your Python classes.
Features
- Asynchronous Support
- Simple decorator-based caching for class methods
- Support for both in-memory and Redis cache backends
- TTL (Time To Live) support
- Cache invalidation strategies
- Async/await support
- Type hints included
To come
- Synchronous Operation Support
Installation
uv add base-cacheable-class
For Redis support:
uv add base-cacheable-class[redis]
Quick Start
Basic Usage with In-Memory Cache
import asyncio
from base_cacheable_class import BaseCacheableClass, InMemoryCache, InMemoryCacheDecorator
class UserService(BaseCacheableClass):
def __init__(self):
cache = InMemoryCache()
cache_decorator = InMemoryCacheDecorator(cache, default_ttl=300) # 5 minutes default
super().__init__(cache_decorator)
@BaseCacheableClass.cache(ttl=60) # Cache for 1 minute
async def get_user(self, user_id: int):
# Expensive operation here
return {"id": user_id, "name": f"User {user_id}"}
@BaseCacheableClass.invalidate("get_user", param_mapping={"user_id": "user_id"})
async def update_user(self, user_id: int, name: str):
# Update user logic here
return {"id": user_id, "name": name}
async def main():
service = UserService()
# First call - will execute the function
user = await service.get_user(1)
print(user) # {"id": 1, "name": "User 1"}
# Second call - will return cached result
user = await service.get_user(1)
print(user) # {"id": 1, "name": "User 1"} (from cache)
# Update user - will invalidate cache
await service.update_user(1, "Updated User")
# Next call - will execute the function again
user = await service.get_user(1)
print(user) # {"id": 1, "name": "User 1"}
if __name__ == "__main__":
asyncio.run(main())
Using Redis Cache
import asyncio
from base_cacheable_class import BaseCacheableClass, RedisCache, RedisCacheDecorator
class ProductService(BaseCacheableClass):
def __init__(self):
cache = RedisCache(
host="localhost",
port=6379,
password="your_password",
db=0
)
cache_decorator = RedisCacheDecorator(cache, default_ttl=3600) # 1 hour default
super().__init__(cache_decorator)
@BaseCacheableClass.cache(ttl=300) # Cache for 5 minutes
async def get_product(self, product_id: int):
# Fetch product from database
return {"id": product_id, "name": f"Product {product_id}"}
@BaseCacheableClass.invalidate_all()
async def refresh_catalog(self):
# Clear all caches when catalog is refreshed
return "Catalog refreshed"
async def main():
service = ProductService()
# Use the service
product = await service.get_product(1)
print(product)
# Clear all caches
await service.refresh_catalog()
if __name__ == "__main__":
asyncio.run(main())
- Special Thanks to: https://github.com/Ilevk/fastapi-tutorial/blob/098d3a05f224220cc2cd5125dea5c5cf7bb810ab/app/core/redis.py#L35
API Reference
Decorators
@BaseCacheableClass.cache(ttl=None)
Cache the decorated method's result. If ttl is None, cache indefinitely.
@BaseCacheableClass.invalidate(target_func_name, param_mapping=None)
Invalidate cache for specific function when the decorated method is called.
target_func_name: Name of the function whose cache should be invalidatedparam_mapping: Dict mapping current function params to target function params
@BaseCacheableClass.invalidate_all()
Clear all caches when the decorated method is called.
Cache Backends
InMemoryCache
Simple in-memory cache using a dictionary. Singleton pattern ensures single instance.
RedisCache
Redis-based cache with support for distributed systems.
Constructor parameters:
host: Redis hostport: Redis portpassword: Redis passworddb: Redis database number (default: 0)username: Redis usernamesocket_timeout: Socket timeout in seconds (default: 0.5)socket_connect_timeout: Connection timeout in seconds (default: 0.5)
Multi-tier Caching (L1/L2) Patterns
class MultiTierCacheDecorator(CacheDecoratorInterface):
"""Implements L1/L2 caching with memory as L1 and Redis as L2."""
def __init__(self, l1_cache: CacheDecoratorInterface, l2_cache: CacheDecoratorInterface):
self.l1_cache = l1_cache
self.l2_cache = l2_cache
async def get(self, key: str) -> Optional[Any]:
# Try L1 first
value = await self.l1_cache.get(key)
if value is not None:
return value
# Try L2
value = await self.l2_cache.get(key)
if value is not None:
# Populate L1
await self.l1_cache.set(key, value, ttl=60) # Short TTL for L1
return value
License
MIT License
Metadata
Release files for base-cacheable-class 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| base_cacheable_class-0.1.0.tar.gz | 6.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| base_cacheable_class-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 18.6 kB
Release files / base_cacheable_class-0.1.0.tar.gz
| Download URL | base_cacheable_class-0.1.0.tar.gz |
|---|---|
| Size | 6.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1e2eb2b0726f65efd4e2bc70a2702fd224b7ac250787a5e93ae87b40786c06ab
|
|
BLAKE2b-256 checksum How to use checksums |
5cea36749c5638b42947ea56bf1df72cec67c3e0fbb3144d6a504d36cb6103c1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.12.0
|
Release files / base_cacheable_class-0.1.0-py3-none-any.whl
| Download URL | base_cacheable_class-0.1.0-py3-none-any.whl |
|---|---|
| Size | 11.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
91d34ee0c09aafeb89828947836f920897a23e5a8cb9f05e594740a393a32f20
|
|
BLAKE2b-256 checksum How to use checksums |
4b5b2c6f4a68d545de6fcdebfb2f86ebb32146c91423680ad8a1d3ca51d57655
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.12.0
|