CacheToolsUtils 8.3__py3-none-any.whl → 8.5__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.
- {CacheToolsUtils-8.3.dist-info → CacheToolsUtils-8.5.dist-info}/METADATA +6 -4
- CacheToolsUtils-8.5.dist-info/RECORD +6 -0
- {CacheToolsUtils-8.3.dist-info → CacheToolsUtils-8.5.dist-info}/WHEEL +1 -1
- CacheToolsUtils.py +64 -48
- CacheToolsUtils-8.3.dist-info/RECORD +0 -6
- {CacheToolsUtils-8.3.dist-info → CacheToolsUtils-8.5.dist-info}/LICENSE +0 -0
- {CacheToolsUtils-8.3.dist-info → CacheToolsUtils-8.5.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: CacheToolsUtils
|
|
3
|
-
Version: 8.
|
|
3
|
+
Version: 8.5
|
|
4
4
|
Summary: Cachetools Utilities
|
|
5
5
|
Author-email: Fabien Coelho <cachetools.utils@coelho.net>
|
|
6
6
|
License: CC0
|
|
@@ -19,6 +19,7 @@ License-File: LICENSE
|
|
|
19
19
|
Requires-Dist: cachetools
|
|
20
20
|
Provides-Extra: dev
|
|
21
21
|
Requires-Dist: mypy ; extra == 'dev'
|
|
22
|
+
Requires-Dist: pyright ; extra == 'dev'
|
|
22
23
|
Requires-Dist: black ; extra == 'dev'
|
|
23
24
|
Requires-Dist: flake8 ; extra == 'dev'
|
|
24
25
|
Requires-Dist: pytest ; extra == 'dev'
|
|
@@ -51,9 +52,10 @@ and other cache-related utils.
|
|
|
51
52
|

|
|
52
53
|

|
|
53
54
|

|
|
55
|
+

|
|
54
56
|

|
|
55
57
|

|
|
56
|
-

|
|
57
59
|

|
|
58
60
|
|
|
59
61
|
## Module Contents
|
|
@@ -70,7 +72,7 @@ with `cachetools`.
|
|
|
70
72
|
- `MemCached` does the same for a Memcached server.
|
|
71
73
|
The utility class `JsonSerde` is a convenient JSON serializer-deserializer
|
|
72
74
|
class for Memcached.
|
|
73
|
-
- `DictCache` a `dict` cache.
|
|
75
|
+
- `DictCache` a very simple `dict` cache.
|
|
74
76
|
|
|
75
77
|
### Other wrappers to extend cache capabilities
|
|
76
78
|
|
|
@@ -84,7 +86,7 @@ with `cachetools`.
|
|
|
84
86
|
|
|
85
87
|
### Cache utilities
|
|
86
88
|
|
|
87
|
-
- `cached` decorator: a cachetools replacement which allows to test
|
|
89
|
+
- `cached` decorator: a cachetools replacement which allows to test if a
|
|
88
90
|
function result is in cache, and to delete such an entry.
|
|
89
91
|
- `cacheFunctions` and `cacheMethods`: add caching to functions or methods.
|
|
90
92
|
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
CacheToolsUtils.py,sha256=kqZNczVcgP_F8oioXBDCqEA5Ux9FovbO_VhlJ67pjiE,18135
|
|
2
|
+
CacheToolsUtils-8.5.dist-info/LICENSE,sha256=y_yFW1bmBAUFCF-ZDyDiq10Ykns_19If5pFnZUzYgeU,33
|
|
3
|
+
CacheToolsUtils-8.5.dist-info/METADATA,sha256=MEAFq8ImCNmiSk49N5yWM3uZCBfHrOLmkQ5b5yVacho,4110
|
|
4
|
+
CacheToolsUtils-8.5.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
|
5
|
+
CacheToolsUtils-8.5.dist-info/top_level.txt,sha256=qCyE4jGot5mOmvIQrZueCnPtbYtRe2hqke4sGojm3zI,16
|
|
6
|
+
CacheToolsUtils-8.5.dist-info/RECORD,,
|
CacheToolsUtils.py
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
CacheTools Utilities. This code is public domain.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
from typing import Any, Callable, MutableMapping
|
|
5
|
+
from typing import Any, Callable, MutableMapping
|
|
6
|
+
import abc
|
|
6
7
|
|
|
7
8
|
import cachetools
|
|
8
9
|
import json
|
|
@@ -15,7 +16,7 @@ log = logging.getLogger(__name__)
|
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
#
|
|
18
|
-
# UTILS
|
|
19
|
+
# UTILS: Abstract Classes and Mixins
|
|
19
20
|
#
|
|
20
21
|
|
|
21
22
|
_NO_DEFAULT = object()
|
|
@@ -24,6 +25,8 @@ _NO_DEFAULT = object()
|
|
|
24
25
|
class _MutMapMix:
|
|
25
26
|
"""Convenient MutableMapping Mixin, forward to _cache."""
|
|
26
27
|
|
|
28
|
+
_cache: MutableMapping
|
|
29
|
+
|
|
27
30
|
def __contains__(self, key):
|
|
28
31
|
return self._cache.__contains__(key)
|
|
29
32
|
|
|
@@ -46,16 +49,20 @@ class _MutMapMix:
|
|
|
46
49
|
class _KeyMutMapMix(_MutMapMix):
|
|
47
50
|
"""Convenient MutableMapping Mixin with a key filter, forward to _cache."""
|
|
48
51
|
|
|
49
|
-
|
|
52
|
+
@abc.abstractmethod
|
|
53
|
+
def _key(self, key: Any) -> Any: # pragma: no cover
|
|
54
|
+
return None
|
|
55
|
+
|
|
56
|
+
def __contains__(self, key: Any):
|
|
50
57
|
return self._cache.__contains__(self._key(key))
|
|
51
58
|
|
|
52
|
-
def __getitem__(self, key):
|
|
59
|
+
def __getitem__(self, key: Any):
|
|
53
60
|
return self._cache.__getitem__(self._key(key))
|
|
54
61
|
|
|
55
|
-
def __setitem__(self, key, val):
|
|
62
|
+
def __setitem__(self, key: Any, val: Any):
|
|
56
63
|
return self._cache.__setitem__(self._key(key), val)
|
|
57
64
|
|
|
58
|
-
def __delitem__(self, key):
|
|
65
|
+
def __delitem__(self, key: Any):
|
|
59
66
|
return self._cache.__delitem__(self._key(key))
|
|
60
67
|
|
|
61
68
|
|
|
@@ -63,36 +70,39 @@ class _StatsMix:
|
|
|
63
70
|
"""Convenient Mixin to forward stats methods to _cache."""
|
|
64
71
|
|
|
65
72
|
def hits(self):
|
|
66
|
-
return self._cache.hits()
|
|
73
|
+
return self._cache.hits() # type: ignore
|
|
67
74
|
|
|
68
75
|
def reset(self):
|
|
69
|
-
return self._cache.reset()
|
|
76
|
+
return self._cache.reset() # type: ignore
|
|
70
77
|
|
|
71
78
|
|
|
72
79
|
class _RedisMix: # pragma: no cover
|
|
73
80
|
"""Convenient mixin to forward redis methods."""
|
|
74
81
|
|
|
82
|
+
# NOTE declaring _cache would conflict with _MutMapMix
|
|
83
|
+
# probably there is a clever way to do that, let us not bother
|
|
84
|
+
|
|
75
85
|
def set(self, *args, **kwargs):
|
|
76
|
-
return self._cache.set(*args, **kwargs)
|
|
86
|
+
return self._cache.set(*args, **kwargs) # type: ignore
|
|
77
87
|
|
|
78
88
|
def get(self, *args, **kwargs):
|
|
79
|
-
return self._cache.get(*args, **kwargs)
|
|
89
|
+
return self._cache.get(*args, **kwargs) # type: ignore
|
|
80
90
|
|
|
81
91
|
def delete(self, *args, **kwargs):
|
|
82
|
-
return self._cache.delete(*args, **kwargs)
|
|
92
|
+
return self._cache.delete(*args, **kwargs) # type: ignore
|
|
83
93
|
|
|
84
94
|
def info(self, *args, **kwargs):
|
|
85
|
-
return self._cache.info(*args, **kwargs)
|
|
95
|
+
return self._cache.info(*args, **kwargs) # type: ignore
|
|
86
96
|
|
|
87
97
|
def dbsize(self, *args, **kwargs):
|
|
88
|
-
return self._cache.dbsize(*args, **kwargs)
|
|
98
|
+
return self._cache.dbsize(*args, **kwargs) # type: ignore
|
|
99
|
+
|
|
89
100
|
|
|
90
101
|
#
|
|
91
102
|
# CACHETOOLS EXTENSIONS
|
|
92
103
|
#
|
|
93
104
|
|
|
94
|
-
|
|
95
|
-
class DebugCache:
|
|
105
|
+
class DebugCache(MutableMapping):
|
|
96
106
|
"""Debug class.
|
|
97
107
|
|
|
98
108
|
:param cache: actual cache
|
|
@@ -100,7 +110,7 @@ class DebugCache:
|
|
|
100
110
|
:param name: name of instance for output
|
|
101
111
|
"""
|
|
102
112
|
|
|
103
|
-
def __init__(self, cache, log, name="cache"):
|
|
113
|
+
def __init__(self, cache: MutableMapping, log: logging.Logger, name="cache"):
|
|
104
114
|
self._cache = cache
|
|
105
115
|
self._log = log
|
|
106
116
|
self._name = name
|
|
@@ -139,10 +149,10 @@ class DebugCache:
|
|
|
139
149
|
|
|
140
150
|
def reset(self): # pragma: no cover
|
|
141
151
|
self._debug("reset")
|
|
142
|
-
return self._cache.reset()
|
|
152
|
+
return self._cache.reset() # type: ignore
|
|
143
153
|
|
|
144
154
|
|
|
145
|
-
class DictCache(_MutMapMix):
|
|
155
|
+
class DictCache(_MutMapMix, MutableMapping):
|
|
146
156
|
"""Cache class based on dict."""
|
|
147
157
|
|
|
148
158
|
def __init__(self):
|
|
@@ -152,7 +162,7 @@ class DictCache(_MutMapMix):
|
|
|
152
162
|
self._cache.clear()
|
|
153
163
|
|
|
154
164
|
|
|
155
|
-
class LockedCache(_MutMapMix, _StatsMix, _RedisMix,
|
|
165
|
+
class LockedCache(_MutMapMix, _StatsMix, _RedisMix, MutableMapping):
|
|
156
166
|
"""Cache class with a lock.
|
|
157
167
|
|
|
158
168
|
:param cache: actual cache.
|
|
@@ -168,7 +178,7 @@ class LockedCache(_MutMapMix, _StatsMix, _RedisMix, MutMap):
|
|
|
168
178
|
cache = ctu.LockedCache(ct.LFUCache(), threading.RLock())
|
|
169
179
|
"""
|
|
170
180
|
|
|
171
|
-
def __init__(self, cache:
|
|
181
|
+
def __init__(self, cache: MutableMapping, lock):
|
|
172
182
|
self._cache = cache
|
|
173
183
|
self._lock = lock
|
|
174
184
|
|
|
@@ -189,22 +199,28 @@ class LockedCache(_MutMapMix, _StatsMix, _RedisMix, MutMap):
|
|
|
189
199
|
return self._cache.__delitem__(key)
|
|
190
200
|
|
|
191
201
|
|
|
192
|
-
class PrefixedCache(_KeyMutMapMix, _StatsMix,
|
|
202
|
+
class PrefixedCache(_KeyMutMapMix, _StatsMix, MutableMapping):
|
|
193
203
|
"""Cache class to add a key prefix.
|
|
194
204
|
|
|
195
205
|
:param cache: actual cache.
|
|
196
206
|
:param prefix: prefix to prepend to keys.
|
|
197
207
|
"""
|
|
198
208
|
|
|
199
|
-
def __init__(self, cache:
|
|
209
|
+
def __init__(self, cache: MutableMapping, prefix: str|bytes = ""):
|
|
200
210
|
self._prefix = prefix
|
|
201
211
|
self._cache = cache
|
|
212
|
+
# dynamic cast
|
|
213
|
+
self._cast: Callable[[Any], str]|Callable[[Any], bytes]
|
|
214
|
+
if isinstance(prefix, str):
|
|
215
|
+
self._cast = lambda v: str(v)
|
|
216
|
+
else: # pragma: no cover
|
|
217
|
+
self._cast = lambda v: bytes(v)
|
|
202
218
|
|
|
203
|
-
def _key(self, key):
|
|
204
|
-
return self._prefix +
|
|
219
|
+
def _key(self, key: Any) -> Any:
|
|
220
|
+
return self._prefix + self._cast(key) # type: ignore
|
|
205
221
|
|
|
206
222
|
|
|
207
|
-
class StatsCache(_MutMapMix,
|
|
223
|
+
class StatsCache(_MutMapMix, MutableMapping):
|
|
208
224
|
"""Cache class to keep stats.
|
|
209
225
|
|
|
210
226
|
:param cache: actual cache.
|
|
@@ -221,7 +237,7 @@ class StatsCache(_MutMapMix, MutMap):
|
|
|
221
237
|
However, this only works for its own classes.
|
|
222
238
|
"""
|
|
223
239
|
|
|
224
|
-
def __init__(self, cache:
|
|
240
|
+
def __init__(self, cache: MutableMapping):
|
|
225
241
|
self._cache = cache
|
|
226
242
|
self.reset()
|
|
227
243
|
|
|
@@ -251,7 +267,7 @@ class StatsCache(_MutMapMix, MutMap):
|
|
|
251
267
|
return self._cache.clear()
|
|
252
268
|
|
|
253
269
|
|
|
254
|
-
class TwoLevelCache(_MutMapMix,
|
|
270
|
+
class TwoLevelCache(_MutMapMix, MutableMapping):
|
|
255
271
|
"""Two-Level Cache class for CacheTools.
|
|
256
272
|
|
|
257
273
|
:param cache: first (smaller, shorter TTL) cache
|
|
@@ -259,7 +275,7 @@ class TwoLevelCache(_MutMapMix, MutMap):
|
|
|
259
275
|
:param resilient: whether to ignore cache2 failures
|
|
260
276
|
"""
|
|
261
277
|
|
|
262
|
-
def __init__(self, cache:
|
|
278
|
+
def __init__(self, cache: MutableMapping, cache2: MutableMapping, resilient=False):
|
|
263
279
|
self._resilient = resilient
|
|
264
280
|
self._cache = cache
|
|
265
281
|
self._cache2 = cache2
|
|
@@ -309,8 +325,8 @@ class TwoLevelCache(_MutMapMix, MutMap):
|
|
|
309
325
|
return self._cache.clear()
|
|
310
326
|
|
|
311
327
|
def reset(self): # pragma: no cover
|
|
312
|
-
self._cache.reset()
|
|
313
|
-
self._cache2.reset()
|
|
328
|
+
self._cache.reset() # type: ignore
|
|
329
|
+
self._cache2.reset() # type: ignore
|
|
314
330
|
|
|
315
331
|
|
|
316
332
|
def cached(cache, *args, **kwargs):
|
|
@@ -332,17 +348,17 @@ def cached(cache, *args, **kwargs):
|
|
|
332
348
|
fun = cachetools.cached(cache, *args, **kwargs)(fun)
|
|
333
349
|
|
|
334
350
|
# extend
|
|
335
|
-
def cache_in(*args, **kwargs):
|
|
351
|
+
def cache_in(*args, **kwargs) -> bool:
|
|
336
352
|
"""Tell whether key is already in cache."""
|
|
337
|
-
key = fun.cache_key(*args, **kwargs)
|
|
338
|
-
return key in fun.cache
|
|
353
|
+
key = fun.cache_key(*args, **kwargs) # type: ignore
|
|
354
|
+
return key in fun.cache # type: ignore
|
|
339
355
|
|
|
340
356
|
def cache_del(*args, **kwargs):
|
|
341
357
|
"""Delete key from cache, return if it was there."""
|
|
342
|
-
key = fun.cache_key(*args, **kwargs)
|
|
343
|
-
key_in = key in fun.cache
|
|
358
|
+
key = fun.cache_key(*args, **kwargs) # type: ignore
|
|
359
|
+
key_in = key in fun.cache # type: ignore
|
|
344
360
|
if key_in:
|
|
345
|
-
del fun.cache[key]
|
|
361
|
+
del fun.cache[key] # type: ignore
|
|
346
362
|
return key_in
|
|
347
363
|
|
|
348
364
|
fun.cache_in = cache_in # type: ignore
|
|
@@ -354,10 +370,10 @@ def cached(cache, *args, **kwargs):
|
|
|
354
370
|
|
|
355
371
|
|
|
356
372
|
# short generator type name
|
|
357
|
-
MapGen = Callable[[
|
|
373
|
+
MapGen = Callable[[MutableMapping, str], MutableMapping]
|
|
358
374
|
|
|
359
375
|
|
|
360
|
-
def cacheMethods(cache:
|
|
376
|
+
def cacheMethods(cache: MutableMapping, obj: Any, gen: MapGen = PrefixedCache, **funs):
|
|
361
377
|
"""Cache some object methods.
|
|
362
378
|
|
|
363
379
|
:param cache: cache to use.
|
|
@@ -378,7 +394,7 @@ def cacheMethods(cache: MutMap, obj: Any, gen: MapGen = PrefixedCache, **funs):
|
|
|
378
394
|
|
|
379
395
|
|
|
380
396
|
def cacheFunctions(
|
|
381
|
-
cache:
|
|
397
|
+
cache: MutableMapping, globs: MutableMapping[str, Any], gen: MapGen = PrefixedCache, **funs
|
|
382
398
|
):
|
|
383
399
|
"""Cache some global functions, with a prefix.
|
|
384
400
|
|
|
@@ -429,7 +445,7 @@ class JsonSerde:
|
|
|
429
445
|
raise Exception("Unknown serialization format")
|
|
430
446
|
|
|
431
447
|
|
|
432
|
-
class MemCached(_KeyMutMapMix,
|
|
448
|
+
class MemCached(_KeyMutMapMix, MutableMapping):
|
|
433
449
|
"""MemCached-compatible wrapper class for cachetools with key encoding.
|
|
434
450
|
|
|
435
451
|
:param cache: actual memcached cache.
|
|
@@ -451,26 +467,26 @@ class MemCached(_KeyMutMapMix, MutMap):
|
|
|
451
467
|
|
|
452
468
|
# memcached keys are constrained bytes, we need some encoding…
|
|
453
469
|
# short (250 bytes) ASCII without control chars nor spaces
|
|
454
|
-
# we do not use hashing which might be costly
|
|
470
|
+
# we do not use hashing which might be costly or induce collisions
|
|
455
471
|
def _key(self, key):
|
|
456
472
|
import base64
|
|
457
473
|
|
|
458
474
|
return base64.b85encode(str(key).encode("utf-8"))
|
|
459
475
|
|
|
460
476
|
def __len__(self):
|
|
461
|
-
return self._cache.stats()[b"curr_items"]
|
|
477
|
+
return self._cache.stats()[b"curr_items"] # type: ignore
|
|
462
478
|
|
|
463
|
-
def stats(self):
|
|
479
|
+
def stats(self) -> dict[str, Any]:
|
|
464
480
|
"""Return MemCached stats."""
|
|
465
|
-
return self._cache.stats()
|
|
481
|
+
return self._cache.stats() # type: ignore
|
|
466
482
|
|
|
467
483
|
def clear(self): # pragma: no cover
|
|
468
484
|
"""Flush MemCached contents."""
|
|
469
|
-
return self._cache.flush_all()
|
|
485
|
+
return self._cache.flush_all() # type: ignore
|
|
470
486
|
|
|
471
|
-
def hits(self):
|
|
487
|
+
def hits(self) -> float:
|
|
472
488
|
"""Return overall cache hit ratio."""
|
|
473
|
-
stats = self._cache.stats()
|
|
489
|
+
stats = self._cache.stats() # type: ignore
|
|
474
490
|
return float(stats[b"get_hits"]) / max(stats[b"cmd_get"], 1)
|
|
475
491
|
|
|
476
492
|
|
|
@@ -512,7 +528,7 @@ class StatsMemCached(MemCached):
|
|
|
512
528
|
#
|
|
513
529
|
|
|
514
530
|
|
|
515
|
-
class RedisCache(
|
|
531
|
+
class RedisCache(MutableMapping):
|
|
516
532
|
"""Redis TTL-ed wrapper for cachetools (``redis``).
|
|
517
533
|
|
|
518
534
|
:param cache: actual redis cache.
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
CacheToolsUtils.py,sha256=0_ftipxNt0SOtA4EJThnoX8M7ma1QS3huxKLb9MQcDM,17015
|
|
2
|
-
CacheToolsUtils-8.3.dist-info/LICENSE,sha256=y_yFW1bmBAUFCF-ZDyDiq10Ykns_19If5pFnZUzYgeU,33
|
|
3
|
-
CacheToolsUtils-8.3.dist-info/METADATA,sha256=XhGZ8w4A7MDcitjZE3lJ2NPr88R_j5ysatzqCfHer58,3979
|
|
4
|
-
CacheToolsUtils-8.3.dist-info/WHEEL,sha256=Xo9-1PvkuimrydujYJAjF7pCkriuXBpUPEjma1nZyJ0,92
|
|
5
|
-
CacheToolsUtils-8.3.dist-info/top_level.txt,sha256=qCyE4jGot5mOmvIQrZueCnPtbYtRe2hqke4sGojm3zI,16
|
|
6
|
-
CacheToolsUtils-8.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|