Skip to main content

Advanced Python cache system with multi-tenant support, scope hierarchies, and configurable eviction policies

Project description

Cacheado

Python 3.9+ License: MIT Test Coverage

High-performance Python cache system with hierarchical scopes, pluggable storage backends, and intelligent eviction policies

Solves critical cache problems in enterprise applications: hierarchical data isolation (organization/user/tenant), flexible storage backends (In-Memory, Redis, MongoDB), intelligent memory management with LRU/TTL policies, and thread-safe operations with high performance.

โšก Why Cacheado?

Flexible Architecture with pluggable storage providers
Zero configuration for common use cases
Production-ready with comprehensive eviction policies

Key Benefits

๐Ÿš€ Performance: Optimized for high-throughput operations with <1ms latency
๐Ÿข Multi-Tenant: Hierarchical scope isolation (global โ†’ organization โ†’ user โ†’ session)
๐Ÿ”Œ Pluggable Storage: In-Memory, Redis, MongoDB support out-of-the-box
โšก Async/Sync: Full support for synchronous and asynchronous code
๐Ÿง  Smart Eviction: LRU, TTL, and max-items policies with rule composition
๐Ÿ“Š Observability: Detailed metrics for hits, misses, evictions, and storage stats

๐Ÿš€ Quick Start

Installation

# Basic installation (in-memory only)
pip install cacheado

# With Redis support
pip install cacheado[redis]

# With MongoDB support
pip install cacheado[mongodb]

# With all backends
pip install cacheado[all]

# For development
pip install cacheado[dev]

Basic Usage (30 seconds to first result)

from cache import Cache

# Instant creation with default in-memory storage
cache = Cache()

# Simple cache with decorator
@cache.cache(ttl_seconds=300)
def expensive_calculation(x, y):
    import time
    time.sleep(2)  # Simulates expensive operation
    return x * y

# First call: 2 seconds
result = expensive_calculation(10, 20)  # 200

# Second call: <1ms (cache hit!)
result = expensive_calculation(10, 20)  # 200 (from cache)

Multi-Tenant Cache with Hierarchical Scopes

from cache import Cache
from utils.cache_scope_config import ScopeConfig, ScopeLevel

# Configure hierarchical scopes
scope_config = ScopeConfig([
    ScopeLevel("organization", "org_id", [
        ScopeLevel("user", "user_id")
    ])
])

cache = Cache(scope_config=scope_config)

# Cache isolated by organization and user
@cache.cache(ttl_seconds=600, scope="user")
def get_user_data(user_id, org_id=None):
    return fetch_from_database(user_id)

# Data automatically isolated by scope
user_data_org1 = get_user_data("123", org_id="org1")
user_data_org2 = get_user_data("123", org_id="org2")
# Different caches, same user_id!

๐Ÿ”Œ Storage Backends

Note: In-Memory storage is included by default. For Redis or MongoDB, install the respective extras.

In-Memory Storage (Default)

from cache import Cache
from storages.in_memory import InMemory

cache = Cache(storage_provider=InMemory())

Redis Storage

# Install Redis support
pip install cacheado[redis]
from cache import Cache
from storages.redis import RedisStorage

redis_storage = RedisStorage(
    connection_string="redis://localhost:6379",
    db=0
)
cache = Cache(storage_provider=redis_storage)

MongoDB Storage

# Install MongoDB support
pip install cacheado[mongodb]
from cache import Cache
from storages.mongodb import MongoDBStorage

mongo_storage = MongoDBStorage(
    connection_string="mongodb://localhost:27017",
    db_name="cache_db",
    collection_name="cache_collection"
)
cache = Cache(storage_provider=mongo_storage)

๐Ÿง  Intelligent Eviction Policies

LRU (Least Recently Used)

from cache import Cache
from storages.in_memory import InMemory
from storages.rules.lru_evict import LRUEvict

storage = InMemory()
lru_rule = LRUEvict(max_items=1000)
cache = Cache(storage_provider=storage, storage_rules=[lru_rule])

TTL (Time-To-Live)

from storages.rules.lifetime_evict import LifeTimeEvict

storage = InMemory()
ttl_rule = LifeTimeEvict()
cache = Cache(storage_provider=storage, storage_rules=[ttl_rule])

# Items expire automatically based on TTL
cache.set("key1", "value1", ttl_seconds=60)

Max Items (Hard Limit)

from storages.rules.max_items_evict import MaxItemsEvict

storage = InMemory()
max_items_rule = MaxItemsEvict(max_items=500)
cache = Cache(storage_provider=storage, storage_rules=[max_items_rule])

Combining Multiple Rules

# Combine LRU + TTL for optimal memory management
storage = InMemory()
lru_rule = LRUEvict(max_items=1000)
ttl_rule = LifeTimeEvict()

cache = Cache(
    storage_provider=storage,
    storage_rules=[lru_rule, ttl_rule]
)

๐Ÿ“Š Observability

Real-Time Metrics

stats = cache.stats()
print(stats)
# {
#     "hits": 1250,
#     "misses": 180,
#     "evictions": 45,
#     "storage_type": "in_memory",
#     "total_keys": 8934
# }

Cache Hit Rate Monitoring

# Monitor cache effectiveness
stats = cache.stats()
hit_rate = stats["hits"] / (stats["hits"] + stats["misses"]) * 100
print(f"Cache hit rate: {hit_rate:.2f}%")

๐Ÿ› ๏ธ Advanced Use Cases

Asynchronous Cache

import asyncio

# Native support for async/await
@cache.cache(ttl_seconds=180, scope="global")
async def fetch_api_data(endpoint):
    async with httpx.AsyncClient() as client:
        response = await client.get(endpoint)
        return response.json()

# Async programmatic operations
await cache.aset("key1", "value1", ttl_seconds=300)
value = await cache.aget("key1")
await cache.aevict("key1")
await cache.aclear()

Programmatic Cache Operations

# Direct cache operations
cache.set("user_settings", {"theme": "dark"}, ttl_seconds=3600, 
          scope="user", org_id="org_123", user_id="user_456")

settings = cache.get("user_settings", 
                    scope="user", org_id="org_123", user_id="user_456")

# Evict specific key
cache.evict("user_settings", scope="user", org_id="org_123", user_id="user_456")

Scope-based Eviction

# Remove all data from an organization
count = cache.evict_by_scope("organization", org_id="org_123")
print(f"Evicted {count} items")

# Remove data from a specific user
count = cache.evict_by_scope("user", org_id="org_123", user_id="user_456")

Decorator with Scope Parameters

@cache.cache(ttl_seconds=300, scope="user")
def get_user_preferences(user_id, org_id=None):
    # org_id is automatically extracted for scope resolution
    return load_preferences(user_id)

# Scope parameters extracted from kwargs
prefs = get_user_preferences("user_123", org_id="org_456")

๐Ÿ”ง Advanced Configuration

Custom Scope Hierarchies

from utils.cache_scope_config import ScopeConfig, ScopeLevel

# Configure complex hierarchies
scope_config = ScopeConfig([
    ScopeLevel("organization", "org_id", [
        ScopeLevel("department", "dept_id", [
            ScopeLevel("user", "user_id", [
                ScopeLevel("session", "session_id")
            ])
        ])
    ])
])

cache = Cache(scope_config=scope_config)

# Use nested scopes
@cache.cache(ttl_seconds=600, scope="session")
def get_session_data(session_id, org_id=None, dept_id=None, user_id=None):
    return fetch_session_data(session_id)

Custom Storage Provider

from protocols.storage_provider import IStorageProvider

class CustomStorage(IStorageProvider):
    def get(self, key: str):
        # Implement custom get logic
        pass
    
    def set(self, key: str, value: Any, ttl_seconds: float):
        # Implement custom set logic
        pass
    
    # Implement other required methods...

cache = Cache(storage_provider=CustomStorage())

Custom Eviction Rules

from protocols.storage_rule import IStorageRule
from utils.cache_types import RuleSideEffect, StorageRuleAction

class CustomRule(IStorageRule):
    def on_get(self, key: str):
        # Custom logic on get
        return None
    
    def on_set(self, key: str, value: Any, ttl_seconds: float):
        # Custom logic on set
        return None
    
    # Implement other required methods...

cache = Cache(storage_rules=[CustomRule()])

๐Ÿงช Testing

# Run all tests
make test

# Tests with coverage
make test-coverage

# Run specific test file
python -m pytest tests/test_cache.py -v

# Run with coverage report
python -m pytest --cov=. --cov-report=html --cov-report=term-missing

๐Ÿ“ Project Structure

cache/
โ”œโ”€โ”€ cache.py                    # Main Cache class
โ”œโ”€โ”€ protocols/                  # Protocol definitions
โ”‚   โ”œโ”€โ”€ storage_provider.py    # Storage backend interface
โ”‚   โ””โ”€โ”€ storage_rule.py        # Eviction rule interface
โ”œโ”€โ”€ storages/                   # Storage implementations
โ”‚   โ”œโ”€โ”€ in_memory.py           # In-memory storage
โ”‚   โ”œโ”€โ”€ redis.py               # Redis storage
โ”‚   โ”œโ”€โ”€ mongodb.py             # MongoDB storage
โ”‚   โ”œโ”€โ”€ rule_aware_storage.py  # Rule decorator
โ”‚   โ””โ”€โ”€ rules/                 # Eviction policies
โ”‚       โ”œโ”€โ”€ lifetime_evict.py  # TTL-based eviction
โ”‚       โ”œโ”€โ”€ lru_evict.py       # LRU eviction
โ”‚       โ””โ”€โ”€ max_items_evict.py # Max items eviction
โ”œโ”€โ”€ utils/                      # Utilities
โ”‚   โ”œโ”€โ”€ cache_types.py         # Type definitions
โ”‚   โ””โ”€โ”€ cache_scope_config.py  # Scope configuration
โ””โ”€โ”€ tests/                      # Test suite
    โ”œโ”€โ”€ test_cache.py
    โ”œโ”€โ”€ test_in_memory.py
    โ”œโ”€โ”€ test_redis.py
    โ”œโ”€โ”€ test_mongodb.py
    โ””โ”€โ”€ ...

๐ŸŽฏ Design Principles

1. Protocol-Based Architecture

Uses Python protocols for loose coupling and easy extensibility.

2. Dependency Injection

Storage providers and rules are injected, enabling flexible composition.

3. Separation of Concerns

  • Cache: High-level API and decorator logic
  • Storage: Data persistence and retrieval
  • Rules: Eviction policies and side effects
  • Scopes: Hierarchical key resolution

4. Thread-Safe Operations

All storage operations are atomic and thread-safe.

5. Async-First Design

Full support for async/await with non-blocking operations.

๐Ÿ“ License

This project is open source and available under the MIT license.

๐Ÿค Contributing

  1. Fork and Clone

    git clone https://github.com/GeorgeOgeorge/cacheado.git
    cd cacheado
    
  2. Install Dependencies

    pip install -r requirements.txt
    pip install -r requirements-build.txt
    
  3. Run Tests

    make test-coverage
    
  4. Code Quality

    make lint
    make format
    
  5. Submit Pull Request

    • Maintain test coverage >90%
    • Follow code standards (Black + isort + flake8)
    • Add tests for new features
    • Update documentation

๐Ÿ› Known Limitations

  • Redis and MongoDB require external services
  • Async operations use asyncio.to_thread for sync storage backends
  • Scope validation happens at runtime, not compile-time

๐Ÿ“š Useful Links


Built with โค๏ธ for high-performance Python applications

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cacheado-1.4.2.tar.gz (22.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cacheado-1.4.2-py3-none-any.whl (23.5 kB view details)

Uploaded Python 3

File details

Details for the file cacheado-1.4.2.tar.gz.

File metadata

  • Download URL: cacheado-1.4.2.tar.gz
  • Upload date:
  • Size: 22.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for cacheado-1.4.2.tar.gz
Algorithm Hash digest
SHA256 cf0e6e3786ecd5c55cdd815219659bfd8525850291c746bf01f731866936764d
MD5 2d8ba66234df14a265a220661fd5f3dd
BLAKE2b-256 81f5632d06f7bd6cc88981df782a76203576aa5cc0783f4681c10da3e7712a69

See more details on using hashes here.

Provenance

The following attestation bundles were made for cacheado-1.4.2.tar.gz:

Publisher: release.yml on GeorgeOgeorge/cacheado

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file cacheado-1.4.2-py3-none-any.whl.

File metadata

  • Download URL: cacheado-1.4.2-py3-none-any.whl
  • Upload date:
  • Size: 23.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for cacheado-1.4.2-py3-none-any.whl
Algorithm Hash digest
SHA256 8981c6ea4b1a2e01a0c303841836453d4b4079c3320f74ad6e2d2e8dbb1fea93
MD5 5b807779e60edd61fcd794639098d37f
BLAKE2b-256 d84273f6430045a22c4553c59eba23fe7e7f5a99391b534b10adaa22a295cd28

See more details on using hashes here.

Provenance

The following attestation bundles were made for cacheado-1.4.2-py3-none-any.whl:

Publisher: release.yml on GeorgeOgeorge/cacheado

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page