A simple cache library with sync/async support, Memory and Redis backend
Project description
Python Cachify Library
A simple and robust caching library for Python functions, supporting both synchronous and asynchronous code.
Table of Contents
Features
- Cache function results based on function ID and arguments
- Supports both synchronous and asynchronous functions
- Thread-safe locking to prevent duplicate cached function calls
- Configurable Time-To-Live (TTL) for cached items
- "Never Die" mode for functions that should keep cache refreshed automatically
- Skip cache functionality to force fresh function execution while updating cache
- Redis cache for distributed caching across multiple processes/machines
Installation
# Using pip
pip install cachify
# Using poetry
poetry add cachify
# Using uv
uv add cachify
Usage
Basic Usage
from cachify import cache
# Cache function in sync functions
@cache(ttl=60) # ttl in seconds
def expensive_calculation(a, b):
# Some expensive operation
return a + b
# And async functions
@cache(ttl=3600) # ttl in seconds
async def another_calculation(url):
# Some expensive IO call
return await httpx.get(url).json()
Decorator Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
ttl |
int | float |
300 |
Time to live for cached items in seconds |
never_die |
bool |
False |
If True, cache refreshes automatically in background |
cache_key_func |
Callable |
None |
Custom function to generate cache keys |
ignore_fields |
tuple[str, ...] |
() |
Function parameters to exclude from cache key |
Custom Cache Key Function
Use cache_key_func when you need custom control over how cache keys are generated:
from cachify import cache
def custom_key(args: tuple, kwargs: dict) -> str:
user_id = kwargs.get("user_id") or args[0]
return f"user:{user_id}"
@cache(ttl=60, cache_key_func=custom_key)
def get_user_profile(user_id: int):
return fetch_from_database(user_id)
Ignore Fields
Use ignore_fields to exclude specific parameters from the cache key. Useful when some arguments don't affect the result:
from cachify import cache
@cache(ttl=300, ignore_fields=("logger", "request_id"))
def fetch_data(query: str, logger: Logger, request_id: str):
# Cache key only uses 'query', ignoring logger and request_id
logger.info(f"Fetching data for request {request_id}")
return database.execute(query)
Redis Cache
For distributed caching across multiple processes or machines, use rcache:
import redis
from cachify import setup_redis_config, rcache
# Configure Redis (call once at startup)
setup_redis_config(
sync_client=redis.from_url("redis://localhost:6379/0"),
key_prefix="myapp", # default: "cachify", prefix searchable on redis "PREFIX:*"
lock_timeout=10, # default: 10, maximum lock lifetime in seconds
on_error="silent", # "silent" (default) or "raise" in case of redis errors
)
@rcache(ttl=300)
def get_user(user_id: int) -> dict:
return fetch_from_database(user_id)
# Async version
import redis.asyncio as aredis
setup_redis_config(async_client=aredis.from_url("redis://localhost:6379/0"))
@rcache(ttl=300)
async def get_user_async(user_id: int) -> dict:
return await fetch_from_database(user_id)
Never Die Cache
The never_die feature ensures that cached values never expire by automatically refreshing them in the background:
# Cache with never_die (automatic refresh)
@cache(ttl=300, never_die=True)
def critical_operation(data_id: str):
# Expensive operation that should always be available from cache
return fetch_data_from_database(data_id)
How Never Die Works:
- When a function with
never_die=Trueis first called, the result is cached - A background thread monitors all
never_diefunctions - On cache expiration (TTL), the function is automatically called again
- The cache is updated with the new result
- If the refresh operation fails, the existing cached value is preserved
- Clients always get fast response times by reading from cache
Benefits:
- Cache is always "warm" and ready to serve
- No user request ever has to wait for the expensive operation
- If a dependency service from the cached function goes down temporarily, the last successful result is still available
- Perfect for critical operations where latency must be minimized
Skip Cache
The skip_cache feature allows you to bypass reading from cache while still updating it with fresh results:
@cache(ttl=300)
def get_user_data(user_id):
# Expensive operation to fetch user data
return fetch_from_database(user_id)
# Normal call - uses cache if available
user = get_user_data(123)
# Force fresh execution while updating cache
fresh_user = get_user_data(123, skip_cache=True)
# Next normal call will get the updated cached value
updated_user = get_user_data(123)
How Skip Cache Works:
- When
skip_cache=Trueis passed, the function bypasses reading from cache - The function executes normally and returns fresh results
- The fresh result is stored in the cache, updating any existing cached value
- Subsequent calls without
skip_cache=Truewill use the updated cached value - The TTL timer resets from when the cache last was updated
Benefits:
- Force refresh of potentially stale data while keeping cache warm
- Ensuring fresh data for critical operations while maintaining cache for other calls
Testing
Run the test scripts
poetry run python -m pytest
Contributing
Contributions are welcome! Feel free to open an issue or submit a pull request.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cachify-0.2.1.tar.gz.
File metadata
- Download URL: cachify-0.2.1.tar.gz
- Upload date:
- Size: 15.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9718025b9f750ee8194aea300fd047cc9126aacaa1e280631d9b0b192045d031
|
|
| MD5 |
bdec79640ba758e9fe0e98b8714e8e05
|
|
| BLAKE2b-256 |
0606a38c8385d7e4e1854425ade9aa85010bccb1e5e7917d60e26abeebf09f4a
|
Provenance
The following attestation bundles were made for cachify-0.2.1.tar.gz:
Publisher:
publish.yml on PulsarDataSolutions/cachify
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cachify-0.2.1.tar.gz -
Subject digest:
9718025b9f750ee8194aea300fd047cc9126aacaa1e280631d9b0b192045d031 - Sigstore transparency entry: 789380052
- Sigstore integration time:
-
Permalink:
PulsarDataSolutions/cachify@02a0a2fcc7053038a24d8de28899de3069056e60 -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/PulsarDataSolutions
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@02a0a2fcc7053038a24d8de28899de3069056e60 -
Trigger Event:
release
-
Statement type:
File details
Details for the file cachify-0.2.1-py3-none-any.whl.
File metadata
- Download URL: cachify-0.2.1-py3-none-any.whl
- Upload date:
- Size: 19.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
be9155d20f8726a8a206b6cd7fef80f96aae771dc9ee96b92f701fff68b9e029
|
|
| MD5 |
e207c8c83b7a225e6e77c8df287c33aa
|
|
| BLAKE2b-256 |
739e17e55d699796a3122812e74f25fcbe8d498f109fcd4afa2ba77761d20e42
|
Provenance
The following attestation bundles were made for cachify-0.2.1-py3-none-any.whl:
Publisher:
publish.yml on PulsarDataSolutions/cachify
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cachify-0.2.1-py3-none-any.whl -
Subject digest:
be9155d20f8726a8a206b6cd7fef80f96aae771dc9ee96b92f701fff68b9e029 - Sigstore transparency entry: 789380058
- Sigstore integration time:
-
Permalink:
PulsarDataSolutions/cachify@02a0a2fcc7053038a24d8de28899de3069056e60 -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/PulsarDataSolutions
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@02a0a2fcc7053038a24d8de28899de3069056e60 -
Trigger Event:
release
-
Statement type: