cachu 0.1.1__py3-none-any.whl → 0.1.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cachu/__init__.py +1 -1
- cachu/backends/file.py +2 -2
- cachu/decorator.py +1 -6
- cachu/operations.py +24 -16
- {cachu-0.1.1.dist-info → cachu-0.1.3.dist-info}/METADATA +27 -10
- {cachu-0.1.1.dist-info → cachu-0.1.3.dist-info}/RECORD +8 -8
- {cachu-0.1.1.dist-info → cachu-0.1.3.dist-info}/WHEEL +0 -0
- {cachu-0.1.1.dist-info → cachu-0.1.3.dist-info}/top_level.txt +0 -0
cachu/__init__.py
CHANGED
cachu/backends/file.py
CHANGED
|
@@ -115,7 +115,7 @@ class FileBackend(Backend):
|
|
|
115
115
|
|
|
116
116
|
with dbm.open(self._filepath, 'c') as db:
|
|
117
117
|
keys_to_delete = [
|
|
118
|
-
k for k in db
|
|
118
|
+
k for k in db.keys()
|
|
119
119
|
if fnmatch.fnmatch(k.decode(), pattern)
|
|
120
120
|
]
|
|
121
121
|
for key in keys_to_delete:
|
|
@@ -131,7 +131,7 @@ class FileBackend(Backend):
|
|
|
131
131
|
with self._lock:
|
|
132
132
|
try:
|
|
133
133
|
with dbm.open(self._filepath, 'c') as db:
|
|
134
|
-
all_keys = [k.decode() for k in db]
|
|
134
|
+
all_keys = [k.decode() for k in db.keys()]
|
|
135
135
|
except Exception:
|
|
136
136
|
return
|
|
137
137
|
|
cachu/decorator.py
CHANGED
|
@@ -220,12 +220,7 @@ def get_cache_info(fn: Callable[..., Any]) -> CacheInfo:
|
|
|
220
220
|
Returns
|
|
221
221
|
CacheInfo with hits, misses, and currsize
|
|
222
222
|
"""
|
|
223
|
-
|
|
224
|
-
actual_fn = fn
|
|
225
|
-
else:
|
|
226
|
-
actual_fn = fn
|
|
227
|
-
|
|
228
|
-
fn_id = id(actual_fn)
|
|
223
|
+
fn_id = id(fn)
|
|
229
224
|
|
|
230
225
|
with _stats_lock:
|
|
231
226
|
hits, misses = _stats.get(fn_id, (0, 0))
|
cachu/operations.py
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"""Cache CRUD operations.
|
|
2
2
|
"""
|
|
3
3
|
import logging
|
|
4
|
-
from typing import Any
|
|
5
4
|
from collections.abc import Callable
|
|
5
|
+
from typing import Any
|
|
6
6
|
|
|
7
7
|
from .backends import NO_VALUE
|
|
8
8
|
from .config import _get_caller_package, get_config
|
|
@@ -124,8 +124,6 @@ def cache_clear(
|
|
|
124
124
|
if package is None:
|
|
125
125
|
package = _get_caller_package()
|
|
126
126
|
|
|
127
|
-
cfg = get_config(package)
|
|
128
|
-
|
|
129
127
|
if backend is not None:
|
|
130
128
|
backends_to_clear = [backend]
|
|
131
129
|
else:
|
|
@@ -141,19 +139,29 @@ def cache_clear(
|
|
|
141
139
|
|
|
142
140
|
from .decorator import _backends, _backends_lock
|
|
143
141
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
142
|
+
# When both backend and ttl are specified, directly get/create and clear that backend.
|
|
143
|
+
# This is essential for distributed caches (Redis) where cache_clear may be called
|
|
144
|
+
# from a different process than the one that populated the cache.
|
|
145
|
+
if backend is not None and ttl is not None:
|
|
146
|
+
backend_instance = _get_backend(package, backend, ttl)
|
|
147
|
+
cleared = backend_instance.clear(pattern)
|
|
148
|
+
if cleared > 0:
|
|
149
|
+
total_cleared += cleared
|
|
150
|
+
logger.debug(f'Cleared {cleared} entries from {backend} backend (ttl={ttl})')
|
|
151
|
+
else:
|
|
152
|
+
with _backends_lock:
|
|
153
|
+
for (pkg, btype, bttl), backend_instance in list(_backends.items()):
|
|
154
|
+
if pkg != package:
|
|
155
|
+
continue
|
|
156
|
+
if btype not in backends_to_clear:
|
|
157
|
+
continue
|
|
158
|
+
if ttl is not None and bttl != ttl:
|
|
159
|
+
continue
|
|
160
|
+
|
|
161
|
+
cleared = backend_instance.clear(pattern)
|
|
162
|
+
if cleared > 0:
|
|
163
|
+
total_cleared += cleared
|
|
164
|
+
logger.debug(f'Cleared {cleared} entries from {btype} backend (ttl={bttl})')
|
|
157
165
|
|
|
158
166
|
return total_cleared
|
|
159
167
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cachu
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: Flexible caching library built on dogpile.cache
|
|
5
5
|
Author: bissli
|
|
6
6
|
License-Expression: 0BSD
|
|
@@ -14,6 +14,7 @@ Requires-Dist: redis; extra == "redis"
|
|
|
14
14
|
Provides-Extra: test
|
|
15
15
|
Requires-Dist: pytest; extra == "test"
|
|
16
16
|
Requires-Dist: pytest-mock; extra == "test"
|
|
17
|
+
Requires-Dist: redis; extra == "test"
|
|
17
18
|
Requires-Dist: testcontainers[redis]; extra == "test"
|
|
18
19
|
|
|
19
20
|
# cachu
|
|
@@ -25,13 +26,13 @@ Flexible caching library with support for memory, file, and Redis backends.
|
|
|
25
26
|
**Basic installation:**
|
|
26
27
|
|
|
27
28
|
```bash
|
|
28
|
-
pip install
|
|
29
|
+
pip install cachu
|
|
29
30
|
```
|
|
30
31
|
|
|
31
32
|
**With Redis support:**
|
|
32
33
|
|
|
33
34
|
```bash
|
|
34
|
-
pip install
|
|
35
|
+
pip install cachu[redis]
|
|
35
36
|
```
|
|
36
37
|
|
|
37
38
|
## Quick Start
|
|
@@ -80,7 +81,7 @@ cachu.configure(
|
|
|
80
81
|
|
|
81
82
|
### Package Isolation
|
|
82
83
|
|
|
83
|
-
Each package automatically gets isolated configuration
|
|
84
|
+
Each package automatically gets isolated configuration, preventing conflicts when multiple libraries use cachu:
|
|
84
85
|
|
|
85
86
|
```python
|
|
86
87
|
# In library_a/config.py
|
|
@@ -91,7 +92,18 @@ cachu.configure(key_prefix='lib_a:', redis_url='redis://redis-a:6379/0')
|
|
|
91
92
|
import cachu
|
|
92
93
|
cachu.configure(key_prefix='lib_b:', redis_url='redis://redis-b:6379/0')
|
|
93
94
|
|
|
94
|
-
# Each library
|
|
95
|
+
# Each library's @cache calls use its own configuration automatically
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
To override the automatic detection, specify the `package` parameter:
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
from cachu import cache
|
|
102
|
+
|
|
103
|
+
# This function will use library_a's configuration
|
|
104
|
+
@cache(ttl=300, package='library_a')
|
|
105
|
+
def get_shared_data(id: int) -> dict:
|
|
106
|
+
return fetch(id)
|
|
95
107
|
```
|
|
96
108
|
|
|
97
109
|
Retrieve configuration:
|
|
@@ -107,7 +119,7 @@ all_configs = cachu.get_all_configs() # All configurations
|
|
|
107
119
|
### Basic Caching
|
|
108
120
|
|
|
109
121
|
```python
|
|
110
|
-
from cachu import
|
|
122
|
+
from cachu import cache
|
|
111
123
|
|
|
112
124
|
@cache(ttl=300, backend='memory')
|
|
113
125
|
def expensive_operation(param: str) -> dict:
|
|
@@ -138,6 +150,8 @@ def fetch_external_data(api_key: str) -> dict:
|
|
|
138
150
|
Tags organize cache entries into logical groups for selective clearing:
|
|
139
151
|
|
|
140
152
|
```python
|
|
153
|
+
from cachu import cache, cache_clear
|
|
154
|
+
|
|
141
155
|
@cache(ttl=300, tag='users')
|
|
142
156
|
def get_user(user_id: int) -> dict:
|
|
143
157
|
return fetch_user(user_id)
|
|
@@ -147,7 +161,7 @@ def get_product(product_id: int) -> dict:
|
|
|
147
161
|
return fetch_product(product_id)
|
|
148
162
|
|
|
149
163
|
# Clear only user caches
|
|
150
|
-
|
|
164
|
+
cache_clear(tag='users', backend='memory', ttl=300)
|
|
151
165
|
```
|
|
152
166
|
|
|
153
167
|
### Conditional Caching
|
|
@@ -214,12 +228,14 @@ result = get_data(123, _overwrite_cache=True)
|
|
|
214
228
|
Track hits and misses:
|
|
215
229
|
|
|
216
230
|
```python
|
|
231
|
+
from cachu import cache, cache_info
|
|
232
|
+
|
|
217
233
|
@cache(ttl=300)
|
|
218
234
|
def get_user(user_id: int) -> dict:
|
|
219
235
|
return fetch_user(user_id)
|
|
220
236
|
|
|
221
237
|
# After some usage
|
|
222
|
-
info =
|
|
238
|
+
info = cache_info(get_user)
|
|
223
239
|
print(f"Hits: {info.hits}, Misses: {info.misses}, Size: {info.currsize}")
|
|
224
240
|
```
|
|
225
241
|
|
|
@@ -267,7 +283,7 @@ cache_delete(get_user, user_id=123)
|
|
|
267
283
|
### Clearing Caches
|
|
268
284
|
|
|
269
285
|
```python
|
|
270
|
-
from cachu import
|
|
286
|
+
from cachu import cache_clear
|
|
271
287
|
|
|
272
288
|
# Clear specific region
|
|
273
289
|
cache_clear(backend='memory', ttl=300)
|
|
@@ -302,7 +318,8 @@ def get_data(id: int) -> dict:
|
|
|
302
318
|
return fetch(id)
|
|
303
319
|
|
|
304
320
|
# In tests/conftest.py
|
|
305
|
-
cachu
|
|
321
|
+
from cachu import cache_clear
|
|
322
|
+
cache_clear(backend='memory', ttl=300, package='myapp')
|
|
306
323
|
```
|
|
307
324
|
|
|
308
325
|
## Instance and Class Methods
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
cachu/__init__.py,sha256=
|
|
1
|
+
cachu/__init__.py,sha256=L7dzCqWbDbL3J6ZfJZ-eHu-2FNzVBuQZURpZ2u2aEBY,676
|
|
2
2
|
cachu/cache.py,sha256=UOh1hsvo5wqpf-quU0glGZi5bgjF8gkaSmYIkAwWfUA,23362
|
|
3
3
|
cachu/config.py,sha256=KtcDGpSTJmjRrcNLz9_Om3O814oJJ3p8gntB84Pd6Dk,5922
|
|
4
|
-
cachu/decorator.py,sha256=
|
|
4
|
+
cachu/decorator.py,sha256=s0ioB4A4YcZe5j2vh_VstpjIVo4lzm5PHaz92_gT-rk,8155
|
|
5
5
|
cachu/keys.py,sha256=fwwNOpnDJFCIWZoQ5UGJWhJa6xu36hsBsURI-n2NJKU,3557
|
|
6
|
-
cachu/operations.py,sha256=
|
|
6
|
+
cachu/operations.py,sha256=t42_Er-O59vrwFa5jdf4yq3Jr4li2l7php4yMVJnxPs,5588
|
|
7
7
|
cachu/types.py,sha256=FghBN5GhxnrpuT4WUL9iNnAfdoH__cw9_Ag4kHbIXq4,723
|
|
8
8
|
cachu/backends/__init__.py,sha256=dM6NfSRXMCOeTg9A9-scgiT_6r_BfzbmT1GVNqL6egU,1228
|
|
9
|
-
cachu/backends/file.py,sha256=
|
|
9
|
+
cachu/backends/file.py,sha256=pOdlyr_n7rFe2yPQLroOogTwcT7yzG7-9yhWzMrlk7k,5327
|
|
10
10
|
cachu/backends/memory.py,sha256=kIgrVU8k_3Aquyj2PDf8IPbTjCITM_0V5GU47m3fJmo,3138
|
|
11
11
|
cachu/backends/redis.py,sha256=yE5rEBgOij9QOeC1VhWdIbGCgi442q-aWfmbbG4aNSE,3858
|
|
12
|
-
cachu-0.1.
|
|
13
|
-
cachu-0.1.
|
|
14
|
-
cachu-0.1.
|
|
15
|
-
cachu-0.1.
|
|
12
|
+
cachu-0.1.3.dist-info/METADATA,sha256=r32FMKsVbwMhnOwQm4xoO_e7KlAcRUB4Mk1_b2fGgHI,9933
|
|
13
|
+
cachu-0.1.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
14
|
+
cachu-0.1.3.dist-info/top_level.txt,sha256=g80nNoMvLMzhSwQWV-JotCBqtsLAHeFMBo_g8hCK8hQ,6
|
|
15
|
+
cachu-0.1.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|