A high-performance async caching solution for Python with extended features
A lightweight, efficient caching solution designed specifically for asyncio applications. Supports both LRU (Least Recently Used) and TTL (Time To Live) caching strategies with a clean, decorator-based API.
- 🚀 Async-First: Built specifically for asyncio applications
- 🔄 Multiple Cache Types:
- LRU (Least Recently Used) cache
- TTL (Time To Live) cache
 
- 🎯 Flexible Key Generation: Works with primitive types, custom objects, and ORM models
- 🛠 Configurable: Adjustable cache size and TTL duration
- 🧹 Cache Management: Clear cache on demand
- 💡 Smart Argument Handling: Skip specific arguments in cache key generation
- 🔍 Cache Bypass: Ability to bypass cache for specific calls
pip install async-cache-extThe LRU cache maintains a fixed number of items, removing the least recently used item when the cache is full.
from cache import AsyncLRU
@AsyncLRU(maxsize=128)
async def get_user_data(user_id: int) -> dict:
    # Expensive database operation
    data = await db.fetch_user(user_id)
    return dataThe TTL cache automatically expires entries after a specified time period.
from cache import AsyncTTL
@AsyncTTL(time_to_live=60, maxsize=1024)
async def get_weather(city: str) -> dict:
    # External API call
    weather = await weather_api.get_data(city)
    return weatherThe cache works seamlessly with custom objects and ORM models:
from dataclasses import dataclass
from cache import AsyncLRU
@dataclass
class UserFilter:
    age: int
    country: str
    status: str
@AsyncLRU(maxsize=128)
async def filter_users(filter_params: UserFilter) -> list:
    # Complex filtering operation
    users = await db.filter_users(
        age=filter_params.age,
        country=filter_params.country,
        status=filter_params.status
    )
    return usersUseful for methods where certain arguments shouldn't affect the cache key:
from cache import AsyncTTL
class UserService:
    @AsyncTTL(time_to_live=300, maxsize=1000, skip_args=1)
    async def get_user_preferences(self, user_id: int) -> dict:
        # 'self' is skipped in cache key generation
        return await self.db.get_preferences(user_id)# Normal cached call
result = await get_user_data(123)
# Force fresh data
fresh_result = await get_user_data(123, use_cache=False)# Clear the entire cache
get_user_data.cache_clear()- The LRU cache is ideal for frequently accessed data with no expiration requirements
- The TTL cache is perfect for data that becomes stale after a certain period
- Choose maxsizebased on your memory constraints and data access patterns
- Consider using skip_argswhen caching class methods to avoid instance-specific caching
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
This project is licensed under the MIT License - see the LICENSE file for details.