CacheToolsUtils 8.3__tar.gz → 8.5__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: CacheToolsUtils
3
- Version: 8.3
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
  ![Status](https://github.com/zx80/cachetools-utils/actions/workflows/cachetools-utils.yml/badge.svg?branch=main&style=flat)
52
53
  ![Tests](https://img.shields.io/badge/tests-17%20✓-success)
53
54
  ![Coverage](https://img.shields.io/badge/coverage-100%25-success)
55
+ ![Issues](https://img.shields.io/github/issues/zx80/cachetools-utils?style=flat)
54
56
  ![Python](https://img.shields.io/badge/python-3-informational)
55
57
  ![Version](https://img.shields.io/pypi/v/CacheToolsUtils)
56
- ![Badges](https://img.shields.io/badge/badges-7-informational)
58
+ ![Badges](https://img.shields.io/badge/badges-8-informational)
57
59
  ![License](https://img.shields.io/pypi/l/cachetoolsutils?style=flat)
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 e if a
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
 
@@ -2,6 +2,7 @@ cachetools
2
2
 
3
3
  [dev]
4
4
  mypy
5
+ pyright
5
6
  black
6
7
  flake8
7
8
  pytest
@@ -2,7 +2,8 @@
2
2
  CacheTools Utilities. This code is public domain.
3
3
  """
4
4
 
5
- from typing import Any, Callable, MutableMapping as MutMap
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
- def __contains__(self, key):
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, MutMap):
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: MutMap, lock):
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, MutMap):
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: MutMap, prefix: str|bytes = ""):
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 + str(key)
219
+ def _key(self, key: Any) -> Any:
220
+ return self._prefix + self._cast(key) # type: ignore
205
221
 
206
222
 
207
- class StatsCache(_MutMapMix, MutMap):
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: MutMap):
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, MutMap):
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: MutMap, cache2: MutMap, resilient=False):
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[[MutMap, str], MutMap]
373
+ MapGen = Callable[[MutableMapping, str], MutableMapping]
358
374
 
359
375
 
360
- def cacheMethods(cache: MutMap, obj: Any, gen: MapGen = PrefixedCache, **funs):
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: MutMap, globs: MutMap[str, Any], gen: MapGen = PrefixedCache, **funs
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, MutMap):
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 and induce collisions
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(MutMap):
531
+ class RedisCache(MutableMapping):
516
532
  """Redis TTL-ed wrapper for cachetools (``redis``).
517
533
 
518
534
  :param cache: actual redis cache.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: CacheToolsUtils
3
- Version: 8.3
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
  ![Status](https://github.com/zx80/cachetools-utils/actions/workflows/cachetools-utils.yml/badge.svg?branch=main&style=flat)
52
53
  ![Tests](https://img.shields.io/badge/tests-17%20✓-success)
53
54
  ![Coverage](https://img.shields.io/badge/coverage-100%25-success)
55
+ ![Issues](https://img.shields.io/github/issues/zx80/cachetools-utils?style=flat)
54
56
  ![Python](https://img.shields.io/badge/python-3-informational)
55
57
  ![Version](https://img.shields.io/pypi/v/CacheToolsUtils)
56
- ![Badges](https://img.shields.io/badge/badges-7-informational)
58
+ ![Badges](https://img.shields.io/badge/badges-8-informational)
57
59
  ![License](https://img.shields.io/pypi/l/cachetoolsutils?style=flat)
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 e if a
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
 
@@ -9,9 +9,10 @@ and other cache-related utils.
9
9
  ![Status](https://github.com/zx80/cachetools-utils/actions/workflows/cachetools-utils.yml/badge.svg?branch=main&style=flat)
10
10
  ![Tests](https://img.shields.io/badge/tests-17%20✓-success)
11
11
  ![Coverage](https://img.shields.io/badge/coverage-100%25-success)
12
+ ![Issues](https://img.shields.io/github/issues/zx80/cachetools-utils?style=flat)
12
13
  ![Python](https://img.shields.io/badge/python-3-informational)
13
14
  ![Version](https://img.shields.io/pypi/v/CacheToolsUtils)
14
- ![Badges](https://img.shields.io/badge/badges-7-informational)
15
+ ![Badges](https://img.shields.io/badge/badges-8-informational)
15
16
  ![License](https://img.shields.io/pypi/l/cachetoolsutils?style=flat)
16
17
 
17
18
  ## Module Contents
@@ -28,7 +29,7 @@ with `cachetools`.
28
29
  - `MemCached` does the same for a Memcached server.
29
30
  The utility class `JsonSerde` is a convenient JSON serializer-deserializer
30
31
  class for Memcached.
31
- - `DictCache` a `dict` cache.
32
+ - `DictCache` a very simple `dict` cache.
32
33
 
33
34
  ### Other wrappers to extend cache capabilities
34
35
 
@@ -42,7 +43,7 @@ with `cachetools`.
42
43
 
43
44
  ### Cache utilities
44
45
 
45
- - `cached` decorator: a cachetools replacement which allows to test e if a
46
+ - `cached` decorator: a cachetools replacement which allows to test if a
46
47
  function result is in cache, and to delete such an entry.
47
48
  - `cacheFunctions` and `cacheMethods`: add caching to functions or methods.
48
49
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "CacheToolsUtils"
7
- version = "8.3"
7
+ version = "8.5"
8
8
  authors = [ { name = "Fabien Coelho", email = "cachetools.utils@coelho.net" } ]
9
9
  description = "Cachetools Utilities"
10
10
  readme = "README.md"
@@ -30,7 +30,7 @@ package = "https://pypi.org/project/CacheToolsUtils/"
30
30
  py-modules = [ "CacheToolsUtils" ]
31
31
 
32
32
  [project.optional-dependencies]
33
- dev = [ "mypy", "black", "flake8", "pytest", "coverage", "pymarkdownlnt", "types-redis", "types-cachetools" ]
33
+ dev = [ "mypy", "pyright", "black", "flake8", "pytest", "coverage", "pymarkdownlnt", "types-redis", "types-cachetools" ]
34
34
  doc = [ "sphinx", "sphinx_rtd_theme", "sphinx-autoapi", "sphinx-lint", "myst_parser" ]
35
35
  tests = [ "pymemcache", "redis" ]
36
36
  pub = [ "build", "wheel", "twine" ]
File without changes
File without changes
File without changes