Skip to main content

Self-hosted caching solution for Python applications

Project description

CacheFn Python SDK

Self-hosted caching solution for Python applications

CacheFn is a developer-first caching library that provides memory caching, function memoization, and tag-based invalidation with zero external dependencies.

Status

  • Version: 0.1.0 (V0)
  • Python: ✅ Complete (Memory storage)
  • TypeScript SDK: ✅ Complete

Features

Zero Dependencies - No Redis, Memcached, or external services required
Memory Storage - In-memory cache with LRU eviction
Type-Safe - Full type hints with Pydantic models
Function Memoization - Cache expensive function results
Tag-based Invalidation - Flexible cache invalidation strategies
Analytics - Built-in hit/miss tracking and statistics
Async First - Built for modern async Python applications

Installation

pip install cachefn

Or install from source:

cd cachefn/python
pip install -e .

Quick Start

Basic Usage

from cachefn import cache_fn
import asyncio

async def main():
    # Create a cache instance
    cache = cache_fn(
        name="my-cache",
        storage="memory",
        max_size=1000,
        default_ttl=60000,  # 1 minute
    )

    # Set a value
    await cache.set("user:123", {"name": "Alice", "age": 30})

    # Get a value
    user = await cache.get("user:123")
    print(user)  # {'name': 'Alice', 'age': 30}

    # Set with TTL and tags
    await cache.set(
        "session:abc",
        {"user_id": "123", "token": "xyz"},
        ttl=3600000,  # 1 hour
        tags=["sessions", "user:123"],
    )

    # Invalidate by tag
    await cache.invalidate_by_tag("sessions")

    # Get stats
    stats = await cache.get_stats()
    print(f"Hit rate: {stats.hit_rate:.2f}%")

if __name__ == "__main__":
    asyncio.run(main())

Function Memoization

from cachefn import memoize
import asyncio

@memoize(ttl=60000, max_size=500)
async def expensive_operation(user_id: str):
    """This function's results will be cached."""
    # Simulate expensive operation
    await asyncio.sleep(1)
    return {"user_id": user_id, "data": "expensive result"}

async def main():
    # First call - takes 1 second
    result = await expensive_operation("123")
    
    # Second call - instant (cached)
    result = await expensive_operation("123")
    
    # Clear cache for this function
    await expensive_operation.clear()

if __name__ == "__main__":
    asyncio.run(main())

Synchronous Memoization

from cachefn import memoize_sync

@memoize_sync(max_size=1000)
def fibonacci(n: int) -> int:
    """Memoized fibonacci function."""
    if n <= 1:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)

# Fast computation due to memoization
print(fibonacci(100))

Cache-Aside Pattern

from cachefn import cache_fn
import asyncio

async def fetch_user_from_db(user_id: str):
    """Simulate database fetch."""
    await asyncio.sleep(0.5)
    return {"id": user_id, "name": "Alice"}

async def main():
    cache = cache_fn(name="users", max_size=100)

    # Get or fetch pattern
    user = await cache.get_or_fetch(
        f"user:{user_id}",
        fetcher=lambda: fetch_user_from_db(user_id),
        ttl=300000,  # 5 minutes
        tags=["users"],
    )

if __name__ == "__main__":
    asyncio.run(main())

API Reference

CacheFn Class

Constructor

cache_fn(
    name: str,
    storage: str = "memory",
    max_size: Optional[int] = None,
    default_ttl: Optional[int] = None,
    namespace: Optional[str] = None,
) -> CacheFn

Core Methods

  • async get(key: str) -> Optional[Any] - Get a value from cache
  • async set(key: str, value: Any, ttl: Optional[int] = None, tags: Optional[list[str]] = None) -> None - Set a value
  • async has(key: str) -> bool - Check if key exists
  • async delete(key: str) -> bool - Delete a key
  • async clear() -> None - Clear all entries

Batch Operations

  • async get_many(keys: list[str]) -> list[Optional[Any]] - Get multiple values
  • async set_many(entries: list[dict]) -> None - Set multiple values
  • async delete_many(keys: list[str]) -> None - Delete multiple keys

Utility Methods

  • async get_or_fetch(key, fetcher, ttl, tags) -> Any - Cache-aside pattern
  • async keys(pattern: Optional[str]) -> list[str] - Get keys matching pattern
  • async size() -> int - Get number of entries
  • async entries(pattern, limit) -> list[dict] - Get entries

Invalidation

  • async invalidate(key: str) -> bool - Invalidate single key
  • async invalidate_by_tag(tag: str) -> None - Invalidate by tag
  • async invalidate_by_tags(tags: list[str]) -> None - Invalidate by multiple tags
  • async invalidate_by_pattern(pattern: str) -> None - Invalidate by glob pattern

Analytics

  • async get_stats() -> CacheStats - Get cache statistics
  • on(event: str, handler: Callable) -> None - Register event handler
  • off(event: str, handler: Callable) -> None - Unregister event handler

Memoization

Async Memoization

@memoize(
    ttl: Optional[int] = None,
    max_size: Optional[int] = None,
    storage: str = "memory",
    tags: Optional[list[str]] = None,
    key_generator: Optional[Callable] = None,
)
async def my_function(...):
    ...

Sync Memoization

@memoize_sync(
    max_size: int = 1000,
    key_generator: Optional[Callable] = None,
)
def my_function(...):
    ...

Events

CacheFn emits events for monitoring:

cache = cache_fn(name="monitored")

cache.on("hit", lambda event: print(f"Cache hit: {event.key}"))
cache.on("miss", lambda event: print(f"Cache miss: {event.key}"))
cache.on("set", lambda event: print(f"Cache set: {event.key}"))
cache.on("delete", lambda event: print(f"Cache delete: {event.key}"))
cache.on("eviction", lambda event: print(f"Evicted: {event.key}"))
cache.on("invalidate", lambda event: print(f"Invalidated {event.count} keys"))

Statistics

stats = await cache.get_stats()

print(f"Hits: {stats.hits}")
print(f"Misses: {stats.misses}")
print(f"Hit Rate: {stats.hit_rate:.2f}%")
print(f"Size: {stats.size}")
print(f"Memory Usage: {stats.memory_usage} bytes")

Integration with SuperFunctions

CacheFn integrates seamlessly with other superfunctions packages:

from cachefn import cache_fn
# Future: from superfunctions.db import create_adapter

# Use with database adapter (coming soon)
cache = cache_fn(
    name="app-cache",
    storage="memory",  # Future: "db" with superfunctions adapter
)

Examples

See the examples/ directory for more examples:

  • basic_usage.py - Basic cache operations
  • memoization.py - Function memoization examples
  • patterns.py - Common caching patterns

Development

Setup

cd cachefn/python
pip install -e ".[dev]"

Run Tests

pytest
pytest --cov=cachefn

Type Checking

mypy cachefn

Linting

ruff check cachefn
black cachefn

Architecture

cachefn/
├── core/
│   ├── cache.py          # Main CacheFn class
│   ├── types.py          # Type definitions
│   └── events.py         # Event emitter
├── storage/
│   └── memory_storage.py # Memory storage backend
├── memoization/
│   └── memoize.py        # Function memoization
├── analytics/
│   └── stats.py          # Statistics tracking
└── utils/
    ├── hash.py           # Key hashing
    ├── pattern.py        # Pattern matching
    ├── serialize.py      # Serialization
    └── ttl.py            # TTL utilities

Roadmap

  • Memory storage with LRU eviction
  • Function memoization
  • Tag-based invalidation
  • Analytics and events
  • IndexedDB-like storage (file-based)
  • Integration with superfunctions.db adapters
  • FastAPI middleware
  • Flask middleware
  • Compression support

License

Apache-2.0

Contributing

Contributions are welcome! Please see the main superfunctions repository for contribution guidelines.

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

cachefn-0.0.1.tar.gz (19.5 kB view details)

Uploaded Source

Built Distribution

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

cachefn-0.0.1-py3-none-any.whl (17.9 kB view details)

Uploaded Python 3

File details

Details for the file cachefn-0.0.1.tar.gz.

File metadata

  • Download URL: cachefn-0.0.1.tar.gz
  • Upload date:
  • Size: 19.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for cachefn-0.0.1.tar.gz
Algorithm Hash digest
SHA256 c1b87836b686f4660339aa7db2441e70afd38718b3eb022ae5114396c883aa8b
MD5 58b7d0b22d2f4c1af147bded8a57507d
BLAKE2b-256 021a657c2b82c45a89a3644eff66fd66b79dd5a9818e968785599645c59ae975

See more details on using hashes here.

File details

Details for the file cachefn-0.0.1-py3-none-any.whl.

File metadata

  • Download URL: cachefn-0.0.1-py3-none-any.whl
  • Upload date:
  • Size: 17.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for cachefn-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 0b380c04d71f0d56d9254d1f6fc6b9b5c4b137b2024f6b934f96eb0637a71bf7
MD5 d87e133614a7363b5aade31b135c2545
BLAKE2b-256 0040f5b98074c967fc7c7fe0fe8762360a809c5862b7def63528d0beb8db21a3

See more details on using hashes here.

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