0
# Core Caching Decorator
1
2
The `cachier` decorator is the main interface for adding persistent caching to Python functions. It provides comprehensive memoization with multiple backend support, configurable expiration, and advanced features like stale-aware caching and background refresh.
3
4
## Capabilities
5
6
### Basic Caching
7
8
Simple persistent caching with default pickle backend:
9
10
```python { .api }
11
def cachier(
12
hash_func: Optional[HashFunc] = None,
13
hash_params: Optional[HashFunc] = None, # Deprecated
14
backend: Optional[Backend] = None,
15
mongetter: Optional[Mongetter] = None,
16
sql_engine: Optional[Union[str, Any, Callable[[], Any]]] = None,
17
redis_client: Optional[RedisClient] = None,
18
stale_after: Optional[timedelta] = None,
19
next_time: Optional[bool] = None,
20
cache_dir: Optional[Union[str, os.PathLike]] = None,
21
pickle_reload: Optional[bool] = None,
22
separate_files: Optional[bool] = None,
23
wait_for_calc_timeout: Optional[int] = None,
24
allow_none: Optional[bool] = None,
25
cleanup_stale: Optional[bool] = None,
26
cleanup_interval: Optional[timedelta] = None,
27
):
28
"""
29
Wrap as a persistent, stale-free memoization decorator.
30
31
The positional and keyword arguments to the wrapped function must be
32
hashable (i.e. Python's immutable built-in objects, not mutable
33
containers).
34
35
Parameters:
36
- hash_func: A callable that gets the args and kwargs from the decorated
37
function and returns a hash key for them. Enables use with
38
functions that get arguments not automatically hashable.
39
- hash_params: Deprecated, use hash_func instead
40
- backend: Backend name ('pickle', 'mongo', 'memory', 'sql', 'redis').
41
Defaults to 'pickle' unless a core-associated parameter is provided.
42
- mongetter: A callable that takes no arguments and returns a
43
pymongo.Collection object with writing permissions.
44
If unset, local pickle cache is used.
45
- sql_engine: SQLAlchemy connection string, Engine, or callable returning
46
an Engine. Used for the SQL backend.
47
- redis_client: Redis client instance or callable returning a Redis client.
48
Used for the Redis backend.
49
- stale_after: Time delta after which a cached result is considered stale.
50
Calls made after result goes stale trigger recalculation.
51
- next_time: If True, stale result returned when finding one, not waiting
52
for fresh result calculation. Defaults to False.
53
- cache_dir: Fully qualified path to cache file directory. Process must
54
have running permissions. Defaults to XDG-compliant cache directory
55
or ~/.cachier/ as fallback
56
- pickle_reload: If True, in-memory cache reloaded on each read, enabling
57
different threads to share cache. Should be False for
58
faster reads in single-thread programs. Defaults to True.
59
- separate_files: For Pickle cores only. Instead of single cache file per
60
function, each function's cache split between several files,
61
one for each argument set. Helps with large cache files.
62
- wait_for_calc_timeout: For MongoDB only. Maximum time to wait for ongoing
63
calculation. When process starts calculation setting
64
being_calculated to True, any process trying to read
65
same entry waits maximum of seconds specified.
66
0 means wait forever.
67
- allow_none: Allows storing None values in cache. If False, functions
68
returning None not cached and recalculated every call.
69
- cleanup_stale: If True, stale cache entries periodically deleted in
70
background thread. Defaults to False.
71
- cleanup_interval: Minimum time between automatic cleanup runs.
72
Defaults to one day.
73
74
Returns:
75
Decorated function with attached cache management methods:
76
- clear_cache(): Clear all cached entries
77
- clear_being_calculated(): Mark all entries as not being calculated
78
- cache_dpath(): Return cache directory path if exists
79
- precache_value(*args, value_to_cache, **kwargs): Add initial value to cache
80
"""
81
```
82
83
Usage examples:
84
85
```python
86
from cachier import cachier
87
from datetime import timedelta
88
import os
89
90
# Basic caching with default pickle backend
91
@cachier()
92
def compute_heavy_task(data):
93
# Expensive computation
94
return sum(x**2 for x in data)
95
96
# Custom cache directory
97
@cachier(cache_dir="/tmp/my_cache")
98
def process_files(file_path):
99
with open(file_path, 'r') as f:
100
return f.read().upper()
101
102
# Stale-aware caching with background refresh
103
@cachier(
104
stale_after=timedelta(minutes=30),
105
next_time=True # Return stale while refreshing in background
106
)
107
def fetch_external_data(api_endpoint):
108
import requests
109
return requests.get(api_endpoint).json()
110
111
# Custom hash function for complex objects
112
def custom_hash(args, kwargs):
113
# Custom hashing logic for non-hashable arguments
114
import pickle
115
import hashlib
116
serialized = pickle.dumps((args, sorted(kwargs.items())))
117
return hashlib.sha256(serialized).hexdigest()
118
119
@cachier(hash_func=custom_hash)
120
def analyze_dataframe(df, options):
121
# Process pandas DataFrame (not naturally hashable)
122
return df.groupby('category').sum()
123
124
# Cleanup stale entries automatically
125
@cachier(
126
stale_after=timedelta(hours=1),
127
cleanup_stale=True,
128
cleanup_interval=timedelta(minutes=30)
129
)
130
def periodic_report(date_range):
131
# Generate reports with automatic cleanup
132
return generate_report(date_range)
133
```
134
135
### Runtime Cache Control
136
137
Functions can control caching behavior at runtime using special keyword arguments:
138
139
```python
140
# Skip cache for specific call
141
result = my_cached_function(data, cachier__skip_cache=True)
142
143
# Overwrite cached value
144
result = my_cached_function(data, cachier__overwrite_cache=True)
145
146
# Enable verbose cache logging
147
result = my_cached_function(data, cachier__verbose=True)
148
149
# Override stale_after for specific call
150
result = my_cached_function(data, cachier__stale_after=timedelta(minutes=5))
151
152
# Override next_time behavior
153
result = my_cached_function(data, cachier__next_time=False)
154
155
# Set maximum age for this specific call
156
result = my_cached_function(data, max_age=timedelta(minutes=10))
157
```
158
159
**Runtime Parameters**:
160
- `cachier__skip_cache`: Skip cache lookup and storage for this call
161
- `cachier__overwrite_cache`: Force recalculation and overwrite existing cache entry
162
- `cachier__verbose`: Enable verbose logging for this call
163
- `cachier__stale_after`: Override decorator's stale_after setting for this call
164
- `cachier__next_time`: Override decorator's next_time setting for this call
165
- `cachier__cleanup_stale`: Override decorator's cleanup_stale setting for this call
166
- `cachier__cleanup_interval`: Override decorator's cleanup_interval setting for this call
167
- `cachier__allow_none`: Override decorator's allow_none setting for this call
168
- `max_age`: Maximum allowed age for cached value (triggers recalculation if exceeded)
169
170
## Cache Management Methods
171
172
All decorated functions receive these attached methods:
173
174
### Clear Cache
175
176
```python { .api }
177
def clear_cache() -> None:
178
"""Clear all cached entries for this function."""
179
```
180
181
### Clear Being Calculated
182
183
```python { .api }
184
def clear_being_calculated() -> None:
185
"""Mark all entries in this cache as not being calculated."""
186
```
187
188
### Cache Directory Path
189
190
```python { .api }
191
def cache_dpath() -> Optional[str]:
192
"""Return the path to the cache directory, if exists; None if not."""
193
```
194
195
### Precache Value
196
197
```python { .api }
198
def precache_value(*args, value_to_cache, **kwargs):
199
"""
200
Add an initial value to the cache.
201
202
Parameters:
203
- *args, **kwargs: Function arguments to associate with cached value
204
- value_to_cache: Entry to be written into the cache
205
206
Returns:
207
The cached value
208
"""
209
```
210
211
Usage examples:
212
213
```python
214
@cachier()
215
def expensive_function(x, y):
216
return x * y + complex_calculation(x, y)
217
218
# Pre-populate cache with known values
219
expensive_function.precache_value(5, 10, value_to_cache=150)
220
221
# Clear specific function's cache
222
expensive_function.clear_cache()
223
224
# Get cache location
225
cache_path = expensive_function.cache_dpath()
226
print(f"Cache stored at: {cache_path}")
227
228
# Reset calculation locks (useful after crashes)
229
expensive_function.clear_being_calculated()
230
```