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 CHANGED
@@ -1,6 +1,6 @@
1
1
  """Flexible caching library with support for memory, file, and Redis backends.
2
2
  """
3
- __version__ = '0.1.1'
3
+ __version__ = '0.1.3'
4
4
 
5
5
  from .backends.redis import get_redis_client
6
6
  from .config import configure, disable, enable, get_all_configs, get_config
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
- if hasattr(fn, '__wrapped__'):
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
- with _backends_lock:
145
- for (pkg, btype, bttl), backend_instance in list(_backends.items()):
146
- if pkg != package:
147
- continue
148
- if btype not in backends_to_clear:
149
- continue
150
- if ttl is not None and bttl != ttl:
151
- continue
152
-
153
- cleared = backend_instance.clear(pattern)
154
- if cleared > 0:
155
- total_cleared += cleared
156
- logger.debug(f'Cleared {cleared} entries from {btype} backend (ttl={bttl})')
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.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 git+https://github.com/bissli/cachu.git
29
+ pip install cachu
29
30
  ```
30
31
 
31
32
  **With Redis support:**
32
33
 
33
34
  ```bash
34
- pip install git+https://github.com/bissli/cachu.git#egg=cachu[redis]
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. This prevents conflicts when multiple libraries use the cachu package:
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 uses its own configuration automatically
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 cachu
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
- cachu.cache_clear(tag='users', backend='memory', ttl=300)
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 = cachu.cache_info(get_user)
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 cachu_clear
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.cache_clear(backend='memory', ttl=300, package='myapp')
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=snSKE_XCc1SikF_FiyolTjTVc5E52QtXjvaXEQJqHs0,676
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=FqD-On66WYYIAOWIe-umlILFc8XcuE8IQHTV6MnFA9o,8254
4
+ cachu/decorator.py,sha256=s0ioB4A4YcZe5j2vh_VstpjIVo4lzm5PHaz92_gT-rk,8155
5
5
  cachu/keys.py,sha256=fwwNOpnDJFCIWZoQ5UGJWhJa6xu36hsBsURI-n2NJKU,3557
6
- cachu/operations.py,sha256=_hHFo9mBgsGT_45-08rprddxNhnGAezCFbQAR_CgI80,5001
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=2ssQmqvpLRDLX21joXRZKxfHekjAjb5gd_gHt52SgVA,5313
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.1.dist-info/METADATA,sha256=G8ue2kOMja2ER0KKUjKDDjVetNYS7OKJcQp1r-oWYY4,9629
13
- cachu-0.1.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
14
- cachu-0.1.1.dist-info/top_level.txt,sha256=g80nNoMvLMzhSwQWV-JotCBqtsLAHeFMBo_g8hCK8hQ,6
15
- cachu-0.1.1.dist-info/RECORD,,
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