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.
- {django_cachex-0.4.2 → django_cachex-0.5.1}/.gitignore +1 -5
- {django_cachex-0.4.2 → django_cachex-0.5.1}/PKG-INFO +4 -15
- {django_cachex-0.4.2 → django_cachex-0.5.1}/README.md +3 -12
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/__init__.py +4 -9
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/adapters/__init__.py +2 -22
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/adapters/pipeline.py +5 -7
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/adapters/protocols.py +2 -3
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/adapters/valkey_py.py +6 -6
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/helpers.py +2 -1
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/models.py +1 -1
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/queryset.py +4 -4
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/templates/admin/django_cachex/cache/change_form.html +18 -17
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/templates/admin/django_cachex/key/add_form.html +14 -13
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/templates/admin/django_cachex/key/change_form.html +14 -13
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/templates/admin/django_cachex/key/change_list.html +6 -6
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/cache/__init__.py +0 -8
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/cache/resp.py +4 -5
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/cache/stream.py +4 -4
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/cache/tiered.py +51 -4
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/exceptions.py +2 -4
- django_cachex-0.5.1/django_cachex/lock.py +11 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/semaphore.py +1 -1
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/stampede.py +2 -1
- {django_cachex-0.4.2 → django_cachex-0.5.1}/pyproject.toml +16 -19
- django_cachex-0.4.2/benchmarks/README.md +0 -257
- django_cachex-0.4.2/crates/django-cachex-redis-rs/LICENSE +0 -21
- django_cachex-0.4.2/crates/django-cachex-redis-rs/README.md +0 -23
- django_cachex-0.4.2/crates/django-cachex-redis-rs/pyproject.toml +0 -45
- django_cachex-0.4.2/django_cachex/adapters/_async_helpers.py +0 -150
- django_cachex-0.4.2/django_cachex/adapters/_pipeline_parsers.py +0 -143
- django_cachex-0.4.2/django_cachex/adapters/redis_rs.py +0 -196
- django_cachex-0.4.2/django_cachex/cache/redis_rs.py +0 -38
- django_cachex-0.4.2/django_cachex/lock.py +0 -291
- django_cachex-0.4.2/examples/README.md +0 -50
- django_cachex-0.4.2/examples/full/README.md +0 -92
- django_cachex-0.4.2/examples/full/pyproject.toml +0 -16
- django_cachex-0.4.2/examples/simple/README.md +0 -45
- {django_cachex-0.4.2 → django_cachex-0.5.1}/LICENSE +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/adapters/redis_py.py +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/adapters/valkey_glide.py +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/__init__.py +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/admin.py +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/apps.py +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/cas.py +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/templates/admin/django_cachex/cache/change_list.html +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/templates/admin/django_cachex/cache/styles.css +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/templates/admin/django_cachex/key/_key_detail_actions.html +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/templates/admin/django_cachex/key/key_detail_hash.html +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/templates/admin/django_cachex/key/key_detail_list.html +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/templates/admin/django_cachex/key/key_detail_pagination.html +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/templates/admin/django_cachex/key/key_detail_set.html +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/templates/admin/django_cachex/key/key_detail_stream.html +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/templates/admin/django_cachex/key/key_detail_string.html +0 -0
- {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
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/templates/admin/django_cachex/key/key_detail_zset.html +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/views/__init__.py +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/views/base.py +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/views/cache_detail.py +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/views/key_add.py +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/admin/views/key_detail.py +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/cache/_semaphore_lua.py +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/cache/base.py +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/cache/database.py +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/cache/locmem.py +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/cache/redis_py.py +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/cache/valkey_glide.py +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/cache/valkey_py.py +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/compressors/__init__.py +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/compressors/base.py +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/compressors/gzip.py +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/compressors/lz4.py +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/compressors/lzma.py +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/compressors/zlib.py +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/compressors/zstd.py +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/py.typed +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/script.py +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/serializers/__init__.py +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/serializers/base.py +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/serializers/json.py +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/serializers/msgpack.py +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/serializers/orjson.py +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/serializers/ormsgpack.py +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/serializers/pickle.py +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/types.py +0 -0
- {django_cachex-0.4.2 → django_cachex-0.5.1}/django_cachex/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: django-cachex
|
|
3
|
-
Version: 0.
|
|
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
|
|
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.
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
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
|
|
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,
|
|
5
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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:
|
|
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
|
|
|
@@ -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
|
-
<
|
|
17
|
-
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
</
|
|
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
|
-
<
|
|
16
|
-
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
</
|
|
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
|
-
<
|
|
17
|
-
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
</
|
|
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
|
-
<
|
|
6
|
-
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
</
|
|
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
|
|
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
|
|
30
|
-
|
|
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
|
|