django-cachex 0.4.2__tar.gz → 0.5.1__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.
Files changed (85) hide show
  1. {django_cachex-0.4.2 → django_cachex-0.5.1}/.gitignore +1 -5
  2. {django_cachex-0.4.2 → django_cachex-0.5.1}/PKG-INFO +4 -15
  3. {django_cachex-0.4.2 → django_cachex-0.5.1}/README.md +3 -12
  4. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/__init__.py +4 -9
  5. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/adapters/__init__.py +2 -22
  6. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/adapters/pipeline.py +5 -7
  7. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/adapters/protocols.py +2 -3
  8. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/adapters/valkey_py.py +6 -6
  9. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/helpers.py +2 -1
  10. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/models.py +1 -1
  11. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/queryset.py +4 -4
  12. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/templates/admin/django_cachex/cache/change_form.html +18 -17
  13. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/templates/admin/django_cachex/key/add_form.html +14 -13
  14. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/templates/admin/django_cachex/key/change_form.html +14 -13
  15. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/templates/admin/django_cachex/key/change_list.html +6 -6
  16. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/cache/__init__.py +0 -8
  17. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/cache/resp.py +4 -5
  18. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/cache/stream.py +4 -4
  19. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/cache/tiered.py +51 -4
  20. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/exceptions.py +2 -4
  21. django_cachex-0.5.1/django_cachex/lock.py +11 -0
  22. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/semaphore.py +1 -1
  23. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/stampede.py +2 -1
  24. {django_cachex-0.4.2 → django_cachex-0.5.1}/pyproject.toml +16 -19
  25. django_cachex-0.4.2/benchmarks/README.md +0 -257
  26. django_cachex-0.4.2/crates/django-cachex-redis-rs/LICENSE +0 -21
  27. django_cachex-0.4.2/crates/django-cachex-redis-rs/README.md +0 -23
  28. django_cachex-0.4.2/crates/django-cachex-redis-rs/pyproject.toml +0 -45
  29. django_cachex-0.4.2/django_cachex/adapters/_async_helpers.py +0 -150
  30. django_cachex-0.4.2/django_cachex/adapters/_pipeline_parsers.py +0 -143
  31. django_cachex-0.4.2/django_cachex/adapters/redis_rs.py +0 -196
  32. django_cachex-0.4.2/django_cachex/cache/redis_rs.py +0 -38
  33. django_cachex-0.4.2/django_cachex/lock.py +0 -291
  34. django_cachex-0.4.2/examples/README.md +0 -50
  35. django_cachex-0.4.2/examples/full/README.md +0 -92
  36. django_cachex-0.4.2/examples/full/pyproject.toml +0 -16
  37. django_cachex-0.4.2/examples/simple/README.md +0 -45
  38. {django_cachex-0.4.2 → django_cachex-0.5.1}/LICENSE +0 -0
  39. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/adapters/redis_py.py +0 -0
  40. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/adapters/valkey_glide.py +0 -0
  41. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/__init__.py +0 -0
  42. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/admin.py +0 -0
  43. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/apps.py +0 -0
  44. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/cas.py +0 -0
  45. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/templates/admin/django_cachex/cache/change_list.html +0 -0
  46. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/templates/admin/django_cachex/cache/styles.css +0 -0
  47. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/templates/admin/django_cachex/key/_key_detail_actions.html +0 -0
  48. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/templates/admin/django_cachex/key/key_detail_hash.html +0 -0
  49. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/templates/admin/django_cachex/key/key_detail_list.html +0 -0
  50. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/templates/admin/django_cachex/key/key_detail_pagination.html +0 -0
  51. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/templates/admin/django_cachex/key/key_detail_set.html +0 -0
  52. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/templates/admin/django_cachex/key/key_detail_stream.html +0 -0
  53. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/templates/admin/django_cachex/key/key_detail_string.html +0 -0
  54. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/templates/admin/django_cachex/key/key_detail_value_input.html +0 -0
  55. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/templates/admin/django_cachex/key/key_detail_zset.html +0 -0
  56. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/views/__init__.py +0 -0
  57. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/views/base.py +0 -0
  58. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/views/cache_detail.py +0 -0
  59. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/views/key_add.py +0 -0
  60. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/views/key_detail.py +0 -0
  61. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/cache/_semaphore_lua.py +0 -0
  62. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/cache/base.py +0 -0
  63. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/cache/database.py +0 -0
  64. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/cache/locmem.py +0 -0
  65. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/cache/redis_py.py +0 -0
  66. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/cache/valkey_glide.py +0 -0
  67. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/cache/valkey_py.py +0 -0
  68. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/compressors/__init__.py +0 -0
  69. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/compressors/base.py +0 -0
  70. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/compressors/gzip.py +0 -0
  71. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/compressors/lz4.py +0 -0
  72. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/compressors/lzma.py +0 -0
  73. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/compressors/zlib.py +0 -0
  74. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/compressors/zstd.py +0 -0
  75. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/py.typed +0 -0
  76. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/script.py +0 -0
  77. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/serializers/__init__.py +0 -0
  78. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/serializers/base.py +0 -0
  79. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/serializers/json.py +0 -0
  80. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/serializers/msgpack.py +0 -0
  81. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/serializers/orjson.py +0 -0
  82. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/serializers/ormsgpack.py +0 -0
  83. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/serializers/pickle.py +0 -0
  84. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/types.py +0 -0
  85. {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/utils.py +0 -0
@@ -35,8 +35,4 @@ CLAUDE.md
35
35
  site/
36
36
  *.sqlite3
37
37
  docs/superpowers/
38
-
39
- # Rust build artifacts
40
- target/
41
- django_cachex/adapters/_redis_rs*.so
42
- crates/django-cachex-redis-rs/python/django_cachex/adapters/_redis_rs*.so
38
+ .bench-runs/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: django-cachex
3
- Version: 0.4.2
3
+ Version: 0.5.1
4
4
  Summary: Full featured Valkey and Redis cache backend for Django
5
5
  Project-URL: Homepage, https://github.com/oliverhaas/django-cachex
6
6
  Project-URL: Documentation, https://oliverhaas.github.io/django-cachex/
@@ -43,8 +43,6 @@ Provides-Extra: ormsgpack
43
43
  Requires-Dist: ormsgpack>=1.10.0; extra == 'ormsgpack'
44
44
  Provides-Extra: redis-py
45
45
  Requires-Dist: redis<9,>=6; extra == 'redis-py'
46
- Provides-Extra: redis-rs
47
- Requires-Dist: django-cachex-redis-rs==0.4.2; extra == 'redis-rs'
48
46
  Provides-Extra: valkey-glide
49
47
  Requires-Dist: valkey-glide-sync<3,>=2.3; extra == 'valkey-glide'
50
48
  Requires-Dist: valkey-glide<3,>=2.3; extra == 'valkey-glide'
@@ -90,7 +88,6 @@ CACHES = {
90
88
  - Cache stampede prevention (TTL-based XFetch).
91
89
  - Two composite backends: `StreamCache` (cross-pod stream-synchronized in-memory cache) and `TieredCache` (L1/L2 with TTL propagation).
92
90
  - Django `LocMemCache` and `DatabaseCache` extensions with the same data-structure ops and admin support.
93
- - Optional Rust I/O driver (PyO3 + tokio + redis-rs) under the same `RespCache` API. Free-threaded CPython (3.14t) supported. Experimental.
94
91
  - Optional `valkey-glide` adapter: Valkey's official Rust-cored client, exposed as `ValkeyGlideCache`. Experimental.
95
92
  - Django admin UI for browsing keys, inspecting values, editing, and flushing. See below.
96
93
 
@@ -132,17 +129,9 @@ Full documentation at [oliverhaas.github.io/django-cachex](https://oliverhaas.gi
132
129
  - Valkey 7.0+ or Redis 6.0+ on the server (the admin's compare-and-swap
133
130
  edits use `SET ... KEEPTTL`, which lands in Redis 6.0)
134
131
 
135
- The Rust I/O driver is optional and experimental: interfaces and
132
+ The `valkey-glide` adapter is optional and experimental: interfaces and
136
133
  behavior may still change, and it has seen less production testing than
137
- the redis-py/valkey-py paths. To opt in, install with the `redis-rs`
138
- extra (`pip install django-cachex[redis-rs]`); this pulls in the
139
- `django-cachex-redis-rs` companion package. Prebuilt wheels are published
140
- for Linux x86_64, Linux aarch64, macOS arm64, and Windows amd64, on
141
- both cp314 and cp314t (free-threaded). Without the extra, the
142
- `RedisRsCache` backends are unavailable but everything else works.
143
-
144
- The `valkey-glide` adapter is also optional and experimental, with the
145
- same caveats. Install with the `valkey-glide` extra
134
+ the redis-py/valkey-py paths. Install with the `valkey-glide` extra
146
135
  (`pip install django-cachex[valkey-glide]`) to enable
147
136
  `ValkeyGlideCache`; it pulls in `valkey-glide-sync` and `valkey-glide`,
148
137
  the official Rust-cored Valkey client. cp314 GIL only; no free-threaded
@@ -154,7 +143,7 @@ client).
154
143
 
155
144
  This project started from [django-redis](https://github.com/jazzband/django-redis) and Django's official [Redis cache backend](https://docs.djangoproject.com/en/stable/topics/cache/#redis). Some serializer and compressor utility code is derived from django-redis, licensed under BSD-3-Clause. The admin UI was inspired by [django-redisboard](https://github.com/ionelmc/django-redisboard).
156
145
 
157
- The Rust I/O driver and async bridge are heavily inspired by, and in places directly adapted from, [django-vcache](https://gitlab.com/glitchtip/django-vcache) (MIT, by David Burke / GlitchTip). The fork-safe tokio runtime, the `RedisRsAwaitable` deferred-loop-binding pattern, and the multiplexed-connection design all originate there.
146
+ The ASGI benchmark follows the shape of [django-vcache](https://gitlab.com/glitchtip/django-vcache)'s `bench_compare.py` (MIT, by David Burke / GlitchTip), so the numbers are directly comparable.
158
147
 
159
148
  I also want to mention [django-valkey](https://github.com/django-commons/django-valkey) and [dj-cache-panel](https://github.com/yassi/dj-cache-panel), which I never really used, but are newer and interesting efforts of similar goals as this package has.
160
149
 
@@ -36,7 +36,6 @@ CACHES = {
36
36
  - Cache stampede prevention (TTL-based XFetch).
37
37
  - Two composite backends: `StreamCache` (cross-pod stream-synchronized in-memory cache) and `TieredCache` (L1/L2 with TTL propagation).
38
38
  - Django `LocMemCache` and `DatabaseCache` extensions with the same data-structure ops and admin support.
39
- - Optional Rust I/O driver (PyO3 + tokio + redis-rs) under the same `RespCache` API. Free-threaded CPython (3.14t) supported. Experimental.
40
39
  - Optional `valkey-glide` adapter: Valkey's official Rust-cored client, exposed as `ValkeyGlideCache`. Experimental.
41
40
  - Django admin UI for browsing keys, inspecting values, editing, and flushing. See below.
42
41
 
@@ -78,17 +77,9 @@ Full documentation at [oliverhaas.github.io/django-cachex](https://oliverhaas.gi
78
77
  - Valkey 7.0+ or Redis 6.0+ on the server (the admin's compare-and-swap
79
78
  edits use `SET ... KEEPTTL`, which lands in Redis 6.0)
80
79
 
81
- The Rust I/O driver is optional and experimental: interfaces and
80
+ The `valkey-glide` adapter is optional and experimental: interfaces and
82
81
  behavior may still change, and it has seen less production testing than
83
- the redis-py/valkey-py paths. To opt in, install with the `redis-rs`
84
- extra (`pip install django-cachex[redis-rs]`); this pulls in the
85
- `django-cachex-redis-rs` companion package. Prebuilt wheels are published
86
- for Linux x86_64, Linux aarch64, macOS arm64, and Windows amd64, on
87
- both cp314 and cp314t (free-threaded). Without the extra, the
88
- `RedisRsCache` backends are unavailable but everything else works.
89
-
90
- The `valkey-glide` adapter is also optional and experimental, with the
91
- same caveats. Install with the `valkey-glide` extra
82
+ the redis-py/valkey-py paths. Install with the `valkey-glide` extra
92
83
  (`pip install django-cachex[valkey-glide]`) to enable
93
84
  `ValkeyGlideCache`; it pulls in `valkey-glide-sync` and `valkey-glide`,
94
85
  the official Rust-cored Valkey client. cp314 GIL only; no free-threaded
@@ -100,7 +91,7 @@ client).
100
91
 
101
92
  This project started from [django-redis](https://github.com/jazzband/django-redis) and Django's official [Redis cache backend](https://docs.djangoproject.com/en/stable/topics/cache/#redis). Some serializer and compressor utility code is derived from django-redis, licensed under BSD-3-Clause. The admin UI was inspired by [django-redisboard](https://github.com/ionelmc/django-redisboard).
102
93
 
103
- The Rust I/O driver and async bridge are heavily inspired by, and in places directly adapted from, [django-vcache](https://gitlab.com/glitchtip/django-vcache) (MIT, by David Burke / GlitchTip). The fork-safe tokio runtime, the `RedisRsAwaitable` deferred-loop-binding pattern, and the multiplexed-connection design all originate there.
94
+ The ASGI benchmark follows the shape of [django-vcache](https://gitlab.com/glitchtip/django-vcache)'s `bench_compare.py` (MIT, by David Burke / GlitchTip), so the numbers are directly comparable.
104
95
 
105
96
  I also want to mention [django-valkey](https://github.com/django-commons/django-valkey) and [dj-cache-panel](https://github.com/yassi/dj-cache-panel), which I never really used, but are newer and interesting efforts of similar goals as this package has.
106
97
 
@@ -1,10 +1,4 @@
1
1
  from importlib.metadata import PackageNotFoundError, version
2
- from pkgutil import extend_path
3
-
4
- # Extend the package path so the optional django-cachex-redis-rs binary package
5
- # (which ships ``adapters/_redis_rs*`` files into this namespace) is
6
- # discovered when both packages are installed side by side.
7
- __path__ = extend_path(__path__, __name__)
8
2
 
9
3
  try:
10
4
  __version__ = version("django-cachex")
@@ -19,7 +13,7 @@ from django_cachex.exceptions import (
19
13
  SerializerError,
20
14
  WrongTypeError,
21
15
  )
22
- from django_cachex.lock import AsyncLock, Lock, LockError, LockNotOwnedError
16
+ from django_cachex.lock import LockError, LockNotOwnedError
23
17
  from django_cachex.script import (
24
18
  ScriptHelpers,
25
19
  decode_list_post,
@@ -35,11 +29,9 @@ from django_cachex.semaphore import (
35
29
  from django_cachex.stampede import StampedeConfig
36
30
 
37
31
  __all__ = [
38
- "AsyncLock",
39
32
  "AsyncPipeline",
40
33
  "CachexError",
41
34
  "CompressorError",
42
- "Lock",
43
35
  "LockError",
44
36
  "LockNotOwnedError",
45
37
  "NotSupportedError",
@@ -57,3 +49,6 @@ __all__ = [
57
49
  "full_encode_pre",
58
50
  "keys_only_pre",
59
51
  ]
52
+
53
+ # Keep the metadata helpers out of ``django_cachex``'s public namespace.
54
+ del PackageNotFoundError, version
@@ -1,18 +1,10 @@
1
1
  """Adapter layer: low-level Redis/Valkey ops per driver.
2
2
 
3
3
  Each adapter wraps a specific underlying client library (redis-py,
4
- valkey-py, our Rust ``redis-rs`` driver, valkey-glide) and exposes the
5
- operation surface that ``RespCache`` delegates to.
4
+ valkey-py, valkey-glide) and exposes the operation surface that
5
+ ``RespCache`` delegates to.
6
6
  """
7
7
 
8
- from pkgutil import extend_path
9
-
10
- # Extend the sub-package path so the optional ``django-cachex-redis-rs``
11
- # binary package (which ships ``_redis_rs*`` files into this namespace)
12
- # is discovered when the two packages are installed under different
13
- # prefixes.
14
- __path__ = extend_path(__path__, __name__)
15
-
16
8
  from django_cachex.adapters.pipeline import AsyncPipeline, Pipeline
17
9
  from django_cachex.adapters.protocols import (
18
10
  RespAdapterProtocol,
@@ -26,13 +18,6 @@ from django_cachex.adapters.redis_py import (
26
18
  RedisPyPipelineAdapter,
27
19
  RedisPySentinelAdapter,
28
20
  )
29
- from django_cachex.adapters.redis_rs import (
30
- RedisRsAdapter,
31
- RedisRsAsyncPipelineAdapter,
32
- RedisRsClusterAdapter,
33
- RedisRsPipelineAdapter,
34
- RedisRsSentinelAdapter,
35
- )
36
21
  from django_cachex.adapters.valkey_glide import (
37
22
  ValkeyGlideAdapter,
38
23
  ValkeyGlideAsyncPipelineAdapter,
@@ -55,11 +40,6 @@ __all__ = [
55
40
  "RedisPyClusterAdapter",
56
41
  "RedisPyPipelineAdapter",
57
42
  "RedisPySentinelAdapter",
58
- "RedisRsAdapter",
59
- "RedisRsAsyncPipelineAdapter",
60
- "RedisRsClusterAdapter",
61
- "RedisRsPipelineAdapter",
62
- "RedisRsSentinelAdapter",
63
43
  "RespAdapterProtocol",
64
44
  "RespAsyncPipelineProtocol",
65
45
  "RespPipelineProtocol",
@@ -8,8 +8,6 @@ implementation, one per driver:
8
8
  - :class:`~django_cachex.adapters.valkey_py.ValkeyPyPipelineAdapter` /
9
9
  :class:`~django_cachex.adapters.redis_py.RedisPyPipelineAdapter`: wrap a
10
10
  redis-py / valkey-py / cluster ``Pipeline`` object.
11
- - :class:`~django_cachex.adapters.redis_rs.RedisRsPipelineAdapter`:
12
- buffers RESP wire commands for the Rust driver's ``pipeline_exec``.
13
11
  - :class:`~django_cachex.adapters.valkey_glide.ValkeyGlidePipelineAdapter`:
14
12
  drives ``valkey-glide``'s ``Batch``.
15
13
 
@@ -143,7 +141,7 @@ class Pipeline:
143
141
  """Decode sorted set members with scores."""
144
142
  return [(self._cache.decode(member), score) for member, score in value]
145
143
 
146
- def _make_zset_decoder(self, *, withscores: bool) -> Callable[[list[tuple[bytes, float]]], list]:
144
+ def _make_zset_decoder(self, *, withscores: bool) -> Callable[[list[tuple[bytes, float]]], list[Any]]:
147
145
  """Create decoder based on whether scores are included."""
148
146
  if withscores:
149
147
  return self._decode_zset_with_scores
@@ -1531,7 +1529,7 @@ class Pipeline:
1531
1529
  self,
1532
1530
  *,
1533
1531
  justid: bool,
1534
- ) -> Callable[[Any], tuple[str, list, list[str]]]:
1532
+ ) -> Callable[[Any], tuple[str, list[Any], list[str]]]:
1535
1533
  """Create decoder for XAUTOCLAIM result.
1536
1534
 
1537
1535
  redis-py returns different formats based on justid:
@@ -1539,7 +1537,7 @@ class Pipeline:
1539
1537
  - justid=True: [id1, id2, ...] (flat list of claimed IDs)
1540
1538
  """
1541
1539
 
1542
- def decode(result: Any) -> tuple[str, list, list[str]]:
1540
+ def decode(result: Any) -> tuple[str, list[Any], list[str]]:
1543
1541
  if justid:
1544
1542
  # redis-py returns flat list of claimed IDs (strips next_id/deleted)
1545
1543
  claimed = [r.decode() if isinstance(r, bytes) else r for r in result]
@@ -1606,8 +1604,8 @@ class Pipeline:
1606
1604
  class AsyncPipeline(Pipeline):
1607
1605
  """Async sibling of :class:`Pipeline`: same chainable API, awaitable ``execute()``.
1608
1606
 
1609
- Driver async pipelines (``redis.asyncio`` ``Pipeline``, glide async ``Batch``,
1610
- redis-rs ``apipeline_exec``) all expose the same chainable command surface
1607
+ Driver async pipelines (``redis.asyncio`` ``Pipeline``, glide async ``Batch``)
1608
+ all expose the same chainable command surface
1611
1609
  as their sync counterparts; only execution does I/O. So this subclass
1612
1610
  inherits every queueing method from :class:`Pipeline` and only overrides
1613
1611
  the lifecycle (``__aenter__/__aexit__``) and ``execute()`` to be async.
@@ -11,7 +11,6 @@ pipeline layers rely on.
11
11
  :class:`~django_cachex.cache.resp.RespCache` calls on its
12
12
  underlying adapter. Concrete adapters
13
13
  (:class:`~django_cachex.adapters.valkey_py.ValkeyPyAdapter`,
14
- :class:`~django_cachex.adapters.redis_rs.RedisRsAdapter`,
15
14
  :class:`~django_cachex.adapters.valkey_glide.ValkeyGlideAdapter`)
16
15
  inherit from this Protocol so the contract is explicit at the class
17
16
  declaration; the inherited method bodies (``...``) are shadowed by each
@@ -467,14 +466,14 @@ class RespAdapterProtocol(Protocol):
467
466
  timeout: int | None,
468
467
  *,
469
468
  stampede_prevention: bool | StampedeConfig | None = None,
470
- ) -> list: ...
469
+ ) -> list[Any]: ...
471
470
  async def aset_many(
472
471
  self,
473
472
  data: Mapping[str, bytes | int],
474
473
  timeout: int | None,
475
474
  *,
476
475
  stampede_prevention: bool | StampedeConfig | None = None,
477
- ) -> list: ...
476
+ ) -> list[Any]: ...
478
477
  def delete_many(self, keys: Sequence[str]) -> int: ...
479
478
  async def adelete_many(self, keys: Sequence[str]) -> int: ...
480
479
  def clear(self) -> bool: ...
@@ -67,7 +67,7 @@ _set = set
67
67
  # process-wide registry every async cache call would open a brand-new
68
68
  # TCP connection, which is slow on the hot path and noisy on the server. Sharing
69
69
  # pools at the module level by event loop + config keeps connections
70
- # reused across tasks, in line with the multiplexed redis-rs adapter.
70
+ # reused across tasks.
71
71
  #
72
72
  # The registry itself lives on each driver-specific adapter class as the
73
73
  # ``_async_pools`` class attribute (see :mod:`~django_cachex.adapters.redis_py`
@@ -375,7 +375,7 @@ class ValkeyPyAdapter(RespAdapterProtocol):
375
375
  """Get an async client connection.
376
376
 
377
377
  ``async def`` for Protocol uniformity: adapters whose async-client
378
- construction is genuinely async (glide, redis-rs) ``await`` here;
378
+ construction is genuinely async (glide) ``await`` here;
379
379
  for redis-py / valkey-py the body is sync (pool lookup +
380
380
  ``Redis(connection_pool=...)``) since the connection opens
381
381
  lazily on the first awaited command.
@@ -709,7 +709,7 @@ class ValkeyPyAdapter(RespAdapterProtocol):
709
709
  timeout: int | None,
710
710
  *,
711
711
  stampede_prevention: bool | StampedeConfig | None = None,
712
- ) -> list:
712
+ ) -> list[Any]:
713
713
  """Set multiple values. timeout=0 deletes keys, None sets without expiry."""
714
714
  if not data:
715
715
  return []
@@ -736,7 +736,7 @@ class ValkeyPyAdapter(RespAdapterProtocol):
736
736
  timeout: int | None,
737
737
  *,
738
738
  stampede_prevention: bool | StampedeConfig | None = None,
739
- ) -> list:
739
+ ) -> list[Any]:
740
740
  """Set multiple values asynchronously."""
741
741
  if not data:
742
742
  return []
@@ -3343,7 +3343,7 @@ class ValkeyPyClusterAdapter(ValkeyPyAdapter):
3343
3343
  timeout: int | None,
3344
3344
  *,
3345
3345
  stampede_prevention: bool | StampedeConfig | None = None,
3346
- ) -> list:
3346
+ ) -> list[Any]:
3347
3347
  """Set multiple values, handling cross-slot keys."""
3348
3348
  if not data:
3349
3349
  return []
@@ -3517,7 +3517,7 @@ class ValkeyPyClusterAdapter(ValkeyPyAdapter):
3517
3517
  timeout: int | None,
3518
3518
  *,
3519
3519
  stampede_prevention: bool | StampedeConfig | None = None,
3520
- ) -> list:
3520
+ ) -> list[Any]:
3521
3521
  """Set multiple values asynchronously, handling cross-slot keys."""
3522
3522
  if not data:
3523
3523
  return []
@@ -366,7 +366,8 @@ def get_size(cache: Any, key: str, key_type: str | None = None) -> int | None:
366
366
 
367
367
  method = size_methods.get(key_type)
368
368
  return method() if method else None
369
- except Exception: # noqa: BLE001
369
+ except Exception:
370
+ logger.exception("get_size: size lookup failed for key %r (type=%s)", key, key_type)
370
371
  return None
371
372
 
372
373
 
@@ -42,7 +42,7 @@ class Cache(models.Model):
42
42
  return None
43
43
 
44
44
  @property
45
- def config(self) -> dict:
45
+ def config(self) -> dict[str, Any]:
46
46
  """Get the cache configuration dict."""
47
47
  return dict(settings.CACHES.get(self.name, {}))
48
48
 
@@ -129,7 +129,7 @@ class SupportLevelFilter(admin.SimpleListFilter):
129
129
  def lookups(
130
130
  self,
131
131
  request: HttpRequest,
132
- model_admin: admin.ModelAdmin,
132
+ model_admin: admin.ModelAdmin[Any],
133
133
  ) -> list[tuple[str, str]]:
134
134
  return [
135
135
  ("cachex", "cachex"),
@@ -409,7 +409,7 @@ class CacheFilter(admin.SimpleListFilter):
409
409
  def lookups(
410
410
  self,
411
411
  request: HttpRequest,
412
- model_admin: admin.ModelAdmin,
412
+ model_admin: admin.ModelAdmin[Any],
413
413
  ) -> list[tuple[str, str]]:
414
414
  return [(name, name) for name in settings.CACHES]
415
415
 
@@ -445,7 +445,7 @@ class TypeFilter(admin.SimpleListFilter):
445
445
  def lookups(
446
446
  self,
447
447
  request: HttpRequest,
448
- model_admin: admin.ModelAdmin,
448
+ model_admin: admin.ModelAdmin[Any],
449
449
  ) -> list[tuple[str, str]]:
450
450
  return [(t, t) for t in KeyType]
451
451
 
@@ -480,7 +480,7 @@ class KeyAdminMixin:
480
480
  show_facets = ShowFacets.NEVER
481
481
  show_full_result_count: ClassVar[bool] = False
482
482
 
483
- def get_actions(self, request: HttpRequest, action_location: Any = None) -> dict:
483
+ def get_actions(self, request: HttpRequest, action_location: Any = None) -> dict[str, Any]:
484
484
  """Remove Django's built-in delete_selected (KeyQuerySet doesn't support it).
485
485
 
486
486
  ``action_location`` must appear literally in the signature: Django
@@ -13,27 +13,28 @@
13
13
  {% block bodyclass %}{{ block.super }} app-django_cachex model-cache change-form{% endblock %}
14
14
 
15
15
  {% block breadcrumbs %}
16
- <div class="breadcrumbs">
17
- <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
18
- &rsaquo; <a href="{% url 'admin:django_cachex_cache_changelist' %}">{% trans 'Caches' %}</a>
19
- &rsaquo; {{ cache_name }}
20
- </div>
16
+ <ol class="breadcrumbs">
17
+ <li><a href="{% url 'admin:index' %}">{% trans 'Home' %}</a></li>
18
+ <li><a href="{% url 'admin:django_cachex_cache_changelist' %}">{% trans 'Caches' %}</a></li>
19
+ <li aria-current="page">{{ cache_name }}</li>
20
+ </ol>
21
+ {% endblock %}
22
+
23
+ {% block object-tools %}
24
+ <ul class="object-tools">
25
+ {% if cache_obj.support_level == "cachex" %}
26
+ <li>
27
+ <a href="{% url 'admin:django_cachex_key_changelist' %}?cache={{ cache_name|urlencode }}">{% trans 'List Keys' %}</a>
28
+ </li>
29
+ {% endif %}
30
+ <li>
31
+ <a href="?{% if not help_active %}help=1{% endif %}">{% trans 'Help' %}</a>
32
+ </li>
33
+ </ul>
21
34
  {% endblock %}
22
35
 
23
36
  {% block content %}
24
37
  <div id="content-main">
25
- <!-- Object tools -->
26
- <ul class="object-tools">
27
- {% if cache_obj.support_level == "cachex" %}
28
- <li>
29
- <a href="{% url 'admin:django_cachex_key_changelist' %}?cache={{ cache_name|urlencode }}">{% trans 'List Keys' %}</a>
30
- </li>
31
- {% endif %}
32
- <li>
33
- <a href="?{% if not help_active %}help=1{% endif %}">{% trans 'Help' %}</a>
34
- </li>
35
- </ul>
36
-
37
38
  {% if cache_obj.support_level != "cachex" %}
38
39
  <fieldset class="module aligned info-section">
39
40
  <h2>{% trans 'Limited backend' %}</h2>
@@ -12,23 +12,24 @@
12
12
  {% block bodyclass %}{{ block.super }} app-django_cachex model-cache change-form{% endblock %}
13
13
 
14
14
  {% block breadcrumbs %}
15
- <div class="breadcrumbs">
16
- <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
17
- &rsaquo; <a href="{% url 'admin:django_cachex_cache_changelist' %}">{% trans 'Caches' %}</a>
18
- &rsaquo; <a href="{% url 'admin:django_cachex_key_changelist' %}?cache={{ cache_name|urlencode }}">{{ cache_name }}</a>
19
- &rsaquo; {% trans 'Add Key' %}
20
- </div>
15
+ <ol class="breadcrumbs">
16
+ <li><a href="{% url 'admin:index' %}">{% trans 'Home' %}</a></li>
17
+ <li><a href="{% url 'admin:django_cachex_cache_changelist' %}">{% trans 'Caches' %}</a></li>
18
+ <li><a href="{% url 'admin:django_cachex_key_changelist' %}?cache={{ cache_name|urlencode }}">{{ cache_name }}</a></li>
19
+ <li aria-current="page">{% trans 'Add Key' %}</li>
20
+ </ol>
21
+ {% endblock %}
22
+
23
+ {% block object-tools %}
24
+ <ul class="object-tools">
25
+ <li>
26
+ <a href="?cache={{ cache_name|urlencode }}{% if not help_active %}&help=1{% endif %}">{% trans 'Help' %}</a>
27
+ </li>
28
+ </ul>
21
29
  {% endblock %}
22
30
 
23
31
  {% block content %}
24
32
  <div id="content-main">
25
- <!-- Object tools -->
26
- <ul class="object-tools">
27
- <li>
28
- <a href="?cache={{ cache_name|urlencode }}{% if not help_active %}&help=1{% endif %}">{% trans 'Help' %}</a>
29
- </li>
30
- </ul>
31
-
32
33
  <!-- Add Key Form -->
33
34
  <form method="post" id="key-form">
34
35
  {% csrf_token %}
@@ -13,23 +13,24 @@
13
13
  {% block bodyclass %}{{ block.super }} app-django_cachex model-key change-form{% endblock %}
14
14
 
15
15
  {% block breadcrumbs %}
16
- <div class="breadcrumbs">
17
- <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
18
- &rsaquo; <a href="{% url 'admin:django_cachex_cache_changelist' %}">{% trans 'Caches' %}</a>
19
- &rsaquo; <a href="{% url 'admin:django_cachex_key_changelist' %}?cache={{ cache_name|urlencode }}">{{ cache_name }}</a>
20
- &rsaquo; {{ key }}
21
- </div>
16
+ <ol class="breadcrumbs">
17
+ <li><a href="{% url 'admin:index' %}">{% trans 'Home' %}</a></li>
18
+ <li><a href="{% url 'admin:django_cachex_cache_changelist' %}">{% trans 'Caches' %}</a></li>
19
+ <li><a href="{% url 'admin:django_cachex_key_changelist' %}?cache={{ cache_name|urlencode }}">{{ cache_name }}</a></li>
20
+ <li aria-current="page">{{ key }}</li>
21
+ </ol>
22
+ {% endblock %}
23
+
24
+ {% block object-tools %}
25
+ <ul class="object-tools">
26
+ <li>
27
+ <a href="?{% if not help_active %}help=1{% endif %}">{% trans 'Help' %}</a>
28
+ </li>
29
+ </ul>
22
30
  {% endblock %}
23
31
 
24
32
  {% block content %}
25
33
  <div id="content-main">
26
- <!-- Object tools -->
27
- <ul class="object-tools">
28
- <li>
29
- <a href="?{% if not help_active %}help=1{% endif %}">{% trans 'Help' %}</a>
30
- </li>
31
- </ul>
32
-
33
34
  <!-- Key Information -->
34
35
  <fieldset class="module aligned">
35
36
  <h2>{% trans 'Key Information' %}</h2>
@@ -2,12 +2,12 @@
2
2
  {% load i18n admin_urls %}
3
3
 
4
4
  {% block breadcrumbs %}
5
- <div class="breadcrumbs">
6
- <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
7
- &rsaquo; <a href="{% url 'admin:django_cachex_cache_changelist' %}">{% trans 'Caches' %}</a>
8
- &rsaquo; <a href="{% url 'admin:django_cachex_cache_change' cache_name|admin_urlquote %}">{{ cache_name }}</a>
9
- &rsaquo; {% trans 'Keys' %}
10
- </div>
5
+ <ol class="breadcrumbs">
6
+ <li><a href="{% url 'admin:index' %}">{% trans 'Home' %}</a></li>
7
+ <li><a href="{% url 'admin:django_cachex_cache_changelist' %}">{% trans 'Caches' %}</a></li>
8
+ <li><a href="{% url 'admin:django_cachex_cache_change' cache_name|admin_urlquote %}">{{ cache_name }}</a></li>
9
+ <li aria-current="page">{% trans 'Keys' %}</li>
10
+ </ol>
11
11
  {% endblock %}
12
12
 
13
13
  {% block object-tools %}
@@ -10,11 +10,6 @@ from django_cachex.cache.redis_py import (
10
10
  RedisClusterCache,
11
11
  RedisSentinelCache,
12
12
  )
13
- from django_cachex.cache.redis_rs import (
14
- RedisRsCache,
15
- RedisRsClusterCache,
16
- RedisRsSentinelCache,
17
- )
18
13
  from django_cachex.cache.resp import RespCache, RespClusterCache, RespSentinelCache
19
14
  from django_cachex.cache.stream import StreamCache
20
15
  from django_cachex.cache.tiered import TieredCache
@@ -30,9 +25,6 @@ __all__ = [
30
25
  "LocMemCache",
31
26
  "RedisCache",
32
27
  "RedisClusterCache",
33
- "RedisRsCache",
34
- "RedisRsClusterCache",
35
- "RedisRsSentinelCache",
36
28
  "RedisSentinelCache",
37
29
  "RespCache",
38
30
  "RespClusterCache",
@@ -7,7 +7,6 @@ concrete subclasses live in:
7
7
 
8
8
  - :mod:`django_cachex.cache.valkey_py`: ``valkey-py``
9
9
  - :mod:`django_cachex.cache.redis_py`: ``redis-py``
10
- - :mod:`django_cachex.cache.redis_rs`: Rust ``redis-rs`` driver
11
10
  - :mod:`django_cachex.cache.valkey_glide`: ``valkey-glide``
12
11
  """
13
12
 
@@ -137,7 +136,7 @@ class RespCache(BaseCachex):
137
136
  def _create_serializers(config: Any) -> list[Any]:
138
137
  if config is None:
139
138
  config = "django_cachex.serializers.pickle.PickleSerializer"
140
- items: list = config if isinstance(config, list) else [config]
139
+ items: list[Any] = config if isinstance(config, list) else [config]
141
140
  if not items:
142
141
  msg = "OPTIONS['serializer'] must not be an empty list; configure at least one serializer or omit it"
143
142
  raise ImproperlyConfigured(msg)
@@ -147,7 +146,7 @@ class RespCache(BaseCachex):
147
146
  def _create_compressors(config: Any) -> list[Any]:
148
147
  if config is None:
149
148
  return []
150
- items: list = config if isinstance(config, list) else [config]
149
+ items: list[Any] = config if isinstance(config, list) else [config]
151
150
  return [_load_codec(item) for item in items]
152
151
 
153
152
  def _decompress(self, value: bytes) -> bytes:
@@ -558,7 +557,7 @@ class RespCache(BaseCachex):
558
557
  version: int | None = None,
559
558
  *,
560
559
  stampede_prevention: bool | StampedeConfig | None = None,
561
- ) -> list:
560
+ ) -> list[Any]:
562
561
  """Set multiple values."""
563
562
  if not data:
564
563
  return []
@@ -576,7 +575,7 @@ class RespCache(BaseCachex):
576
575
  version: int | None = None,
577
576
  *,
578
577
  stampede_prevention: bool | StampedeConfig | None = None,
579
- ) -> list:
578
+ ) -> list[Any]:
580
579
  """Set multiple values asynchronously."""
581
580
  if not data:
582
581
  return []
@@ -12,7 +12,7 @@ Configuration::
12
12
 
13
13
  CACHES = {
14
14
  "redis": {
15
- "BACKEND": "django_cachex.cache.RedisCache", # or RedisRsCache, etc.
15
+ "BACKEND": "django_cachex.cache.RedisCache", # or ValkeyCache, etc.
16
16
  "LOCATION": "redis://127.0.0.1:6379/0",
17
17
  },
18
18
  "default": {
@@ -26,8 +26,8 @@ Configuration::
26
26
  },
27
27
  }
28
28
 
29
- ``transport`` is the alias of any cachex ``RespCache`` subclass (pure-Python
30
- or Rust-driver-backed) used for stream I/O.
29
+ ``transport`` is the alias of any cachex ``RespCache`` subclass used for
30
+ stream I/O.
31
31
  ``stream_key`` is the Redis Stream key shared by all pods (default ``cache:sync``).
32
32
  ``maxlen`` caps stream length via approximate trimming (default 10000).
33
33
  ``block_timeout`` is the XREAD BLOCK timeout in milliseconds (default 1000).
@@ -106,7 +106,7 @@ class StreamCache(LocMemCache):
106
106
  from collections import OrderedDict
107
107
  from threading import Lock
108
108
 
109
- _cache: OrderedDict
109
+ _cache: OrderedDict[str, bytes]
110
110
  _expire_info: dict[str, float | None]
111
111
  _lock: Lock
112
112