coredis 4.24.0__tar.gz → 5.0.0__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.

Potentially problematic release.


This version of coredis might be problematic. Click here for more details.

Files changed (119) hide show
  1. {coredis-4.24.0 → coredis-5.0.0}/HISTORY.rst +60 -0
  2. {coredis-4.24.0/coredis.egg-info → coredis-5.0.0}/PKG-INFO +4 -9
  3. {coredis-4.24.0 → coredis-5.0.0}/README.md +1 -5
  4. {coredis-4.24.0 → coredis-5.0.0}/coredis/__init__.py +1 -3
  5. {coredis-4.24.0 → coredis-5.0.0}/coredis/_packer.py +10 -10
  6. coredis-5.0.0/coredis/_protocols.py +50 -0
  7. coredis-5.0.0/coredis/_py_311_typing.py +20 -0
  8. coredis-5.0.0/coredis/_py_312_typing.py +17 -0
  9. {coredis-4.24.0 → coredis-5.0.0}/coredis/_utils.py +49 -55
  10. {coredis-4.24.0 → coredis-5.0.0}/coredis/_version.py +3 -3
  11. {coredis-4.24.0 → coredis-5.0.0}/coredis/cache.py +57 -82
  12. coredis-5.0.0/coredis/client/__init__.py +6 -0
  13. {coredis-4.24.0 → coredis-5.0.0}/coredis/client/basic.py +129 -56
  14. {coredis-4.24.0 → coredis-5.0.0}/coredis/client/cluster.py +147 -70
  15. {coredis-4.24.0 → coredis-5.0.0}/coredis/commands/__init__.py +27 -7
  16. {coredis-4.24.0 → coredis-5.0.0}/coredis/commands/_key_spec.py +11 -10
  17. {coredis-4.24.0 → coredis-5.0.0}/coredis/commands/_utils.py +1 -1
  18. {coredis-4.24.0 → coredis-5.0.0}/coredis/commands/_validators.py +30 -20
  19. {coredis-4.24.0 → coredis-5.0.0}/coredis/commands/_wrappers.py +19 -99
  20. {coredis-4.24.0 → coredis-5.0.0}/coredis/commands/bitfield.py +10 -2
  21. {coredis-4.24.0 → coredis-5.0.0}/coredis/commands/constants.py +20 -3
  22. {coredis-4.24.0 → coredis-5.0.0}/coredis/commands/core.py +1674 -1251
  23. {coredis-4.24.0 → coredis-5.0.0}/coredis/commands/function.py +21 -19
  24. {coredis-4.24.0 → coredis-5.0.0}/coredis/commands/monitor.py +0 -71
  25. {coredis-4.24.0 → coredis-5.0.0}/coredis/commands/pubsub.py +7 -142
  26. coredis-5.0.0/coredis/commands/request.py +108 -0
  27. {coredis-4.24.0 → coredis-5.0.0}/coredis/commands/script.py +21 -22
  28. {coredis-4.24.0 → coredis-5.0.0}/coredis/commands/sentinel.py +60 -49
  29. {coredis-4.24.0 → coredis-5.0.0}/coredis/connection.py +14 -15
  30. {coredis-4.24.0 → coredis-5.0.0}/coredis/exceptions.py +2 -2
  31. coredis-5.0.0/coredis/experimental/__init__.py +1 -0
  32. {coredis-4.24.0 → coredis-5.0.0}/coredis/globals.py +3 -0
  33. {coredis-4.24.0 → coredis-5.0.0}/coredis/modules/autocomplete.py +28 -30
  34. {coredis-4.24.0 → coredis-5.0.0}/coredis/modules/base.py +15 -31
  35. {coredis-4.24.0 → coredis-5.0.0}/coredis/modules/filters.py +269 -245
  36. {coredis-4.24.0 → coredis-5.0.0}/coredis/modules/graph.py +61 -62
  37. {coredis-4.24.0 → coredis-5.0.0}/coredis/modules/json.py +172 -140
  38. {coredis-4.24.0 → coredis-5.0.0}/coredis/modules/response/_callbacks/autocomplete.py +5 -4
  39. {coredis-4.24.0 → coredis-5.0.0}/coredis/modules/response/_callbacks/graph.py +34 -29
  40. {coredis-4.24.0 → coredis-5.0.0}/coredis/modules/response/_callbacks/json.py +5 -3
  41. {coredis-4.24.0 → coredis-5.0.0}/coredis/modules/response/_callbacks/search.py +49 -53
  42. {coredis-4.24.0 → coredis-5.0.0}/coredis/modules/response/_callbacks/timeseries.py +18 -30
  43. {coredis-4.24.0 → coredis-5.0.0}/coredis/modules/response/types.py +1 -5
  44. {coredis-4.24.0 → coredis-5.0.0}/coredis/modules/search.py +186 -169
  45. {coredis-4.24.0 → coredis-5.0.0}/coredis/modules/timeseries.py +184 -164
  46. {coredis-4.24.0 → coredis-5.0.0}/coredis/parser.py +6 -19
  47. {coredis-4.24.0 → coredis-5.0.0}/coredis/pipeline.py +477 -521
  48. {coredis-4.24.0 → coredis-5.0.0}/coredis/pool/basic.py +7 -7
  49. {coredis-4.24.0 → coredis-5.0.0}/coredis/pool/cluster.py +3 -3
  50. {coredis-4.24.0 → coredis-5.0.0}/coredis/pool/nodemanager.py +10 -3
  51. {coredis-4.24.0 → coredis-5.0.0}/coredis/response/_callbacks/__init__.py +76 -57
  52. {coredis-4.24.0 → coredis-5.0.0}/coredis/response/_callbacks/acl.py +0 -3
  53. {coredis-4.24.0 → coredis-5.0.0}/coredis/response/_callbacks/cluster.py +25 -16
  54. {coredis-4.24.0 → coredis-5.0.0}/coredis/response/_callbacks/command.py +8 -6
  55. {coredis-4.24.0 → coredis-5.0.0}/coredis/response/_callbacks/connection.py +4 -3
  56. {coredis-4.24.0 → coredis-5.0.0}/coredis/response/_callbacks/geo.py +17 -13
  57. {coredis-4.24.0 → coredis-5.0.0}/coredis/response/_callbacks/hash.py +13 -11
  58. {coredis-4.24.0 → coredis-5.0.0}/coredis/response/_callbacks/keys.py +9 -5
  59. {coredis-4.24.0 → coredis-5.0.0}/coredis/response/_callbacks/module.py +2 -3
  60. {coredis-4.24.0 → coredis-5.0.0}/coredis/response/_callbacks/script.py +6 -8
  61. {coredis-4.24.0 → coredis-5.0.0}/coredis/response/_callbacks/sentinel.py +21 -17
  62. {coredis-4.24.0 → coredis-5.0.0}/coredis/response/_callbacks/server.py +36 -14
  63. {coredis-4.24.0 → coredis-5.0.0}/coredis/response/_callbacks/sets.py +3 -4
  64. {coredis-4.24.0 → coredis-5.0.0}/coredis/response/_callbacks/sorted_set.py +27 -24
  65. {coredis-4.24.0 → coredis-5.0.0}/coredis/response/_callbacks/streams.py +22 -13
  66. {coredis-4.24.0 → coredis-5.0.0}/coredis/response/_callbacks/strings.py +7 -6
  67. coredis-5.0.0/coredis/response/_callbacks/vector_sets.py +159 -0
  68. {coredis-4.24.0 → coredis-5.0.0}/coredis/response/types.py +13 -4
  69. {coredis-4.24.0 → coredis-5.0.0}/coredis/retry.py +12 -13
  70. {coredis-4.24.0 → coredis-5.0.0}/coredis/sentinel.py +11 -1
  71. {coredis-4.24.0 → coredis-5.0.0}/coredis/stream.py +4 -3
  72. {coredis-4.24.0 → coredis-5.0.0}/coredis/tokens.py +348 -16
  73. coredis-5.0.0/coredis/typing.py +580 -0
  74. {coredis-4.24.0 → coredis-5.0.0/coredis.egg-info}/PKG-INFO +4 -9
  75. {coredis-4.24.0 → coredis-5.0.0}/coredis.egg-info/SOURCES.txt +4 -2
  76. {coredis-4.24.0 → coredis-5.0.0}/coredis.egg-info/requires.txt +2 -2
  77. {coredis-4.24.0 → coredis-5.0.0}/pyproject.toml +3 -2
  78. {coredis-4.24.0 → coredis-5.0.0}/requirements/dev.txt +1 -1
  79. {coredis-4.24.0 → coredis-5.0.0}/requirements/docs.txt +1 -1
  80. {coredis-4.24.0 → coredis-5.0.0}/requirements/main.txt +2 -2
  81. {coredis-4.24.0 → coredis-5.0.0}/setup.py +0 -1
  82. coredis-4.24.0/coredis/_protocols.py +0 -82
  83. coredis-4.24.0/coredis/client/__init__.py +0 -7
  84. coredis-4.24.0/coredis/client/keydb.py +0 -336
  85. coredis-4.24.0/coredis/experimental/__init__.py +0 -5
  86. coredis-4.24.0/coredis/pipeline.pyi +0 -2103
  87. coredis-4.24.0/coredis/typing.py +0 -229
  88. {coredis-4.24.0 → coredis-5.0.0}/LICENSE +0 -0
  89. {coredis-4.24.0 → coredis-5.0.0}/MANIFEST.in +0 -0
  90. {coredis-4.24.0 → coredis-5.0.0}/coredis/_json.py +0 -0
  91. {coredis-4.24.0 → coredis-5.0.0}/coredis/_sidecar.py +0 -0
  92. {coredis-4.24.0 → coredis-5.0.0}/coredis/config.py +0 -0
  93. {coredis-4.24.0 → coredis-5.0.0}/coredis/constants.py +0 -0
  94. {coredis-4.24.0 → coredis-5.0.0}/coredis/credentials.py +0 -0
  95. {coredis-4.24.0 → coredis-5.0.0}/coredis/modules/__init__.py +0 -0
  96. {coredis-4.24.0 → coredis-5.0.0}/coredis/modules/response/__init__.py +0 -0
  97. {coredis-4.24.0 → coredis-5.0.0}/coredis/modules/response/_callbacks/__init__.py +0 -0
  98. {coredis-4.24.0 → coredis-5.0.0}/coredis/pool/__init__.py +0 -0
  99. {coredis-4.24.0 → coredis-5.0.0}/coredis/py.typed +0 -0
  100. {coredis-4.24.0 → coredis-5.0.0}/coredis/recipes/__init__.py +0 -0
  101. {coredis-4.24.0 → coredis-5.0.0}/coredis/recipes/credentials/__init__.py +0 -0
  102. {coredis-4.24.0 → coredis-5.0.0}/coredis/recipes/credentials/iam_provider.py +0 -0
  103. {coredis-4.24.0 → coredis-5.0.0}/coredis/recipes/locks/__init__.py +0 -0
  104. {coredis-4.24.0 → coredis-5.0.0}/coredis/recipes/locks/extend.lua +0 -0
  105. {coredis-4.24.0 → coredis-5.0.0}/coredis/recipes/locks/lua_lock.py +0 -0
  106. {coredis-4.24.0 → coredis-5.0.0}/coredis/recipes/locks/release.lua +0 -0
  107. {coredis-4.24.0 → coredis-5.0.0}/coredis/response/__init__.py +0 -0
  108. {coredis-4.24.0 → coredis-5.0.0}/coredis/response/_utils.py +0 -0
  109. {coredis-4.24.0 → coredis-5.0.0}/coredis/speedups.c +0 -0
  110. {coredis-4.24.0 → coredis-5.0.0}/coredis/speedups.pyi +0 -0
  111. {coredis-4.24.0 → coredis-5.0.0}/coredis.egg-info/dependency_links.txt +0 -0
  112. {coredis-4.24.0 → coredis-5.0.0}/coredis.egg-info/top_level.txt +0 -0
  113. {coredis-4.24.0 → coredis-5.0.0}/requirements/ci.txt +0 -0
  114. {coredis-4.24.0 → coredis-5.0.0}/requirements/dev_extra.txt +0 -0
  115. {coredis-4.24.0 → coredis-5.0.0}/requirements/publishing.txt +0 -0
  116. {coredis-4.24.0 → coredis-5.0.0}/requirements/recipes.txt +0 -0
  117. {coredis-4.24.0 → coredis-5.0.0}/requirements/test.txt +0 -0
  118. {coredis-4.24.0 → coredis-5.0.0}/setup.cfg +0 -0
  119. {coredis-4.24.0 → coredis-5.0.0}/versioneer.py +0 -0
@@ -3,6 +3,63 @@
3
3
  Changelog
4
4
  =========
5
5
 
6
+ v5.0.0
7
+ ------
8
+ Release Date: 2025-07-16
9
+
10
+ * Features
11
+
12
+ * Add support for using custom types with redis commands
13
+ by registering serializers and deserializers
14
+ * Allow stacking pipeline commands synchronously
15
+ * Expose statically typed responses for pipeline commands
16
+
17
+
18
+ * Compatibility
19
+
20
+ * Redis command methods are no longer coroutines and instead
21
+ synchronous methods that return subclasses of ``Awaitable``
22
+ (``CommandRequest``) which can be awaited as before.
23
+ * Add support for redis 8.0 vector set commands
24
+ * Add support for redis 8.0 hash expiry commands
25
+ * Remove deprecated pubsub ``listen`` and threaded worker APIs
26
+ * Remove support for KeyDB
27
+
28
+ * Performance
29
+
30
+ * Streamline client side cache shrinking
31
+
32
+ v5.0.0rc2
33
+ ---------
34
+ Release Date: 2025-07-10
35
+
36
+ * Bug Fix
37
+
38
+ * Fix duplicate command error in using ``transform`` with pipeline
39
+
40
+ v5.0.0rc1
41
+ ---------
42
+ Release Date: 2025-07-07
43
+
44
+ * Features
45
+
46
+ * Add support for using custom types with redis commands
47
+ by registering serializers and deserializers
48
+ * Allow stacking pipeline commands syncronously
49
+ * Expose statically types responses for pipeline commands
50
+
51
+
52
+ * Compatibility
53
+
54
+ * Add support for redis 8.0 vector set commands
55
+ * Add support for redis 8.0 hash expiry commands
56
+ * Remove deprecated pubsub ``listen`` and threaded worker APIs
57
+ * Remove support for KeyDB
58
+
59
+ * Performance
60
+
61
+ * Streamline client side cache shrinking
62
+
6
63
  v4.24.0
7
64
  -------
8
65
  Release Date: 2025-07-05
@@ -1939,3 +1996,6 @@ v1.0.1
1939
1996
 
1940
1997
 
1941
1998
 
1999
+
2000
+
2001
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: coredis
3
- Version: 4.24.0
3
+ Version: 5.0.0
4
4
  Summary: Python async client for Redis key-value store
5
5
  Home-page: https://github.com/alisaifee/coredis
6
6
  Author: Ali-Akber Saifee
@@ -14,7 +14,6 @@ Project-URL: Documentation, https://coredis.readthedocs.org
14
14
  Keywords: Redis,key-value store,asyncio
15
15
  Classifier: Development Status :: 5 - Production/Stable
16
16
  Classifier: Intended Audience :: Developers
17
- Classifier: License :: OSI Approved :: MIT License
18
17
  Classifier: Operating System :: OS Independent
19
18
  Classifier: Programming Language :: Python
20
19
  Classifier: Programming Language :: Python :: 3.10
@@ -26,11 +25,11 @@ Requires-Python: >=3.10
26
25
  Description-Content-Type: text/markdown
27
26
  License-File: LICENSE
28
27
  Requires-Dist: async_timeout<6,>4
28
+ Requires-Dist: beartype>=0.20
29
29
  Requires-Dist: deprecated>=1.2
30
- Requires-Dist: typing_extensions>=4.3
30
+ Requires-Dist: typing_extensions>=4.13
31
31
  Requires-Dist: packaging<26,>=21
32
32
  Requires-Dist: pympler<2,>1
33
- Requires-Dist: wrapt<2,>=1.1.0
34
33
  Provides-Extra: recipes
35
34
  Requires-Dist: aiobotocore>=2.15.2; extra == "recipes"
36
35
  Requires-Dist: asyncache>=0.3.1; extra == "recipes"
@@ -80,9 +79,6 @@ coredis is an async redis client with support for redis server, cluster & sentin
80
79
  and the [API Documentation](https://coredis.readthedocs.io/en/latest/api/index.html)
81
80
  for more details.
82
81
 
83
- > **Warning**
84
- > The command API does NOT mirror the official python [redis client](https://github.com/redis/redis-py). For details about the high level differences refer to [Divergence from aredis & redis-py](https://coredis.readthedocs.io/en/latest/history.html#divergence-from-aredis-redis-py)
85
-
86
82
  ______________________________________________________________________
87
83
 
88
84
  <!-- TOC depthFrom:2 depthTo:6 withLinks:1 updateOnSave:1 orderedList:0 -->
@@ -201,7 +197,7 @@ Details about supported Redis modules and their commands can be found
201
197
 
202
198
  ## Compatibility
203
199
 
204
- coredis is tested against redis versions >= `6.4`
200
+ coredis is tested against redis versions >= `7.0`
205
201
  The test matrix status can be reviewed
206
202
  [here](https://github.com/alisaifee/coredis/actions/workflows/main.yml)
207
203
 
@@ -221,7 +217,6 @@ coredis is additionally tested against:
221
217
 
222
218
  **coredis** is known to work with the following databases that have redis protocol compatibility:
223
219
 
224
- - [KeyDB](https://docs.keydb.dev/)
225
220
  - [Dragonfly](https://dragonflydb.io/)
226
221
  - [Redict](https://redict.io/)
227
222
  - [Valkey](https://github.com/valkey-io/valkey)
@@ -27,9 +27,6 @@ coredis is an async redis client with support for redis server, cluster & sentin
27
27
  and the [API Documentation](https://coredis.readthedocs.io/en/latest/api/index.html)
28
28
  for more details.
29
29
 
30
- > **Warning**
31
- > The command API does NOT mirror the official python [redis client](https://github.com/redis/redis-py). For details about the high level differences refer to [Divergence from aredis & redis-py](https://coredis.readthedocs.io/en/latest/history.html#divergence-from-aredis-redis-py)
32
-
33
30
  ______________________________________________________________________
34
31
 
35
32
  <!-- TOC depthFrom:2 depthTo:6 withLinks:1 updateOnSave:1 orderedList:0 -->
@@ -148,7 +145,7 @@ Details about supported Redis modules and their commands can be found
148
145
 
149
146
  ## Compatibility
150
147
 
151
- coredis is tested against redis versions >= `6.4`
148
+ coredis is tested against redis versions >= `7.0`
152
149
  The test matrix status can be reviewed
153
150
  [here](https://github.com/alisaifee/coredis/actions/workflows/main.yml)
154
151
 
@@ -168,7 +165,6 @@ coredis is additionally tested against:
168
165
 
169
166
  **coredis** is known to work with the following databases that have redis protocol compatibility:
170
167
 
171
- - [KeyDB](https://docs.keydb.dev/)
172
168
  - [Dragonfly](https://dragonflydb.io/)
173
169
  - [Redict](https://redict.io/)
174
170
  - [Valkey](https://github.com/valkey-io/valkey)
@@ -10,7 +10,7 @@ from __future__ import annotations
10
10
 
11
11
  from typing import cast
12
12
 
13
- from coredis.client import KeyDB, KeyDBCluster, Redis, RedisCluster
13
+ from coredis.client import Redis, RedisCluster
14
14
  from coredis.config import Config
15
15
  from coredis.connection import (
16
16
  BaseConnection,
@@ -30,8 +30,6 @@ from . import _version
30
30
 
31
31
  __all__ = [
32
32
  "Config",
33
- "KeyDB",
34
- "KeyDBCluster",
35
33
  "Redis",
36
34
  "RedisCluster",
37
35
  "BaseConnection",
@@ -1,14 +1,14 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from coredis.constants import SYM_CRLF, SYM_DOLLAR, SYM_EMPTY, SYM_STAR
4
- from coredis.typing import ValueT
4
+ from coredis.typing import RedisValueT
5
5
 
6
6
 
7
7
  class Packer:
8
8
  def __init__(self, encoding: str):
9
9
  self.encoding = encoding
10
10
 
11
- def encode(self, value: ValueT) -> bytes:
11
+ def encode(self, value: RedisValueT) -> bytes:
12
12
  """Returns a bytestring representation of the value"""
13
13
  if isinstance(value, str):
14
14
  return value.encode(self.encoding)
@@ -18,7 +18,7 @@ class Packer:
18
18
  return b"%.15g" % value
19
19
  return value
20
20
 
21
- def pack_command(self, command: bytes, *args: ValueT) -> list[bytes]:
21
+ def pack_command(self, command: bytes, *args: RedisValueT) -> list[bytes]:
22
22
  "Pack a series of arguments into the Redis protocol"
23
23
  output: list[bytes] = []
24
24
  # the client might have included 1 or more literal arguments in
@@ -50,22 +50,22 @@ class Packer:
50
50
  output.append(buff)
51
51
  return output
52
52
 
53
- def pack_commands(self, commands: list[tuple[ValueT, ...]]) -> list[bytes]:
53
+ def pack_commands(self, commands: list[tuple[RedisValueT, ...]]) -> list[bytes]:
54
54
  output: list[bytes] = []
55
- pieces: list[bytes] = []
55
+ command_arguments: list[bytes] = []
56
56
  buffer_length = 0
57
57
 
58
58
  for cmd in commands:
59
59
  for chunk in self.pack_command(self.encode(cmd[0]), *cmd[1:]):
60
- pieces.append(chunk)
60
+ command_arguments.append(chunk)
61
61
  buffer_length += len(chunk)
62
62
 
63
63
  if buffer_length > 6000:
64
- output.append(SYM_EMPTY.join(pieces))
64
+ output.append(SYM_EMPTY.join(command_arguments))
65
65
  buffer_length = 0
66
- pieces = []
66
+ command_arguments = []
67
67
 
68
- if pieces:
69
- output.append(SYM_EMPTY.join(pieces))
68
+ if command_arguments:
69
+ output.append(SYM_EMPTY.join(command_arguments))
70
70
 
71
71
  return output
@@ -0,0 +1,50 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+
5
+ from typing_extensions import runtime_checkable
6
+
7
+ from coredis.response._callbacks import NoopCallback
8
+ from coredis.typing import (
9
+ TYPE_CHECKING,
10
+ Awaitable,
11
+ Callable,
12
+ ExecutionParameters,
13
+ Protocol,
14
+ R,
15
+ RedisCommandP,
16
+ ResponseType,
17
+ TypeVar,
18
+ Unpack,
19
+ ValueT,
20
+ )
21
+
22
+ T_co = TypeVar("T_co", covariant=True)
23
+
24
+
25
+ if TYPE_CHECKING:
26
+ from coredis.commands import CommandRequest
27
+
28
+
29
+ class AbstractExecutor(Protocol):
30
+ def execute_command(
31
+ self,
32
+ command: RedisCommandP,
33
+ callback: Callable[..., R] = NoopCallback(),
34
+ **options: Unpack[ExecutionParameters],
35
+ ) -> Awaitable[R]: ...
36
+
37
+ def create_request(
38
+ self,
39
+ name: bytes,
40
+ *arguments: ValueT,
41
+ callback: Callable[..., R],
42
+ execution_parameters: ExecutionParameters | None = None,
43
+ ) -> CommandRequest[R]: ...
44
+
45
+
46
+ @runtime_checkable
47
+ class ConnectionP(Protocol):
48
+ decode_responses: bool
49
+ encoding: str
50
+ push_messages: asyncio.Queue[ResponseType]
@@ -0,0 +1,20 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Hashable
4
+ from typing import Any, TypeAlias
5
+
6
+ from .typing import MutableSet, RedisError, ResponsePrimitive
7
+
8
+ #: Represents the total structure of any response for any redis command.
9
+ ResponseType: TypeAlias = (
10
+ ResponsePrimitive
11
+ | list[Any]
12
+ | MutableSet[Hashable]
13
+ | dict[
14
+ Hashable,
15
+ Any,
16
+ ]
17
+ | RedisError
18
+ )
19
+ #: Type alias for valid python types that can be represented as json
20
+ JsonType: TypeAlias = str | int | float | bool | dict[str, Any] | list[Any] | None
@@ -0,0 +1,17 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Hashable
4
+
5
+ from .typing import MutableSet, RedisError, ResponsePrimitive
6
+
7
+ #: Type alias for valid python types that can be represented as json
8
+ type JsonType = str | int | float | bool | dict[str, JsonType] | list[JsonType] | None
9
+
10
+ #: Represents the total structure of any response for any redis command.
11
+ type ResponseType = (
12
+ ResponsePrimitive
13
+ | RedisError
14
+ | list[ResponseType]
15
+ | MutableSet[Hashable]
16
+ | dict[Hashable, ResponseType]
17
+ )
@@ -1,14 +1,14 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import enum
4
+ from collections import UserDict
4
5
  from typing import Any
5
6
 
6
- from wrapt import ObjectProxy
7
-
8
7
  from coredis.typing import (
9
8
  Hashable,
10
9
  Iterable,
11
10
  Mapping,
11
+ MutableMapping,
12
12
  ResponseType,
13
13
  StringT,
14
14
  TypeVar,
@@ -18,61 +18,59 @@ T = TypeVar("T")
18
18
  U = TypeVar("U")
19
19
 
20
20
 
21
- class EncodingInsensitiveDict(ObjectProxy): # type: ignore
21
+ class EncodingInsensitiveDict(UserDict[Any, Any]):
22
22
  def __init__(
23
23
  self,
24
- dict: Mapping[Any, Any] | ResponseType | None = None,
24
+ initial: MutableMapping[Any, Any] | None = None,
25
25
  encoding: str = "utf-8",
26
26
  ):
27
- d = dict or {}
28
- super().__init__(d)
29
- self._self_encoding = encoding
30
-
31
- def __getitem__(self, item: StringT) -> Any:
32
- if isinstance(item, str) and item not in self.__wrapped__:
33
- return self.__wrapped__.get(
34
- item, self.__wrapped__.get(item.encode(self._self_encoding))
35
- )
36
- elif isinstance(item, bytes) and item not in self.__wrapped__:
37
- return self.__wrapped__.get(
38
- item, self.__wrapped__.get(item.decode(self._self_encoding))
39
- )
40
- return self.__wrapped__[item]
41
-
42
- def get(self, item: StringT, default: object | None = None) -> Any:
43
- return self.__getitem__(item) or default
44
-
45
- def pop(self, item: StringT, default: object | None = None) -> Any:
46
- if item in self.__wrapped__:
47
- return self.__wrapped__.pop(item)
48
- if isinstance(item, str):
49
- return self.__wrapped__.pop(item.encode(self._self_encoding), default)
50
-
51
- def clear(self) -> None:
52
- self.__wrapped__.clear()
53
-
54
- def update(self, updates: Mapping[Any, Any]) -> None:
55
- self.__wrapped__.update(updates)
56
-
57
- def __setitem__(self, item: StringT, value: object) -> None:
58
- if item in self.__wrapped__:
59
- self.__wrapped__[item] = value
60
- elif isinstance(item, str) and item.encode(self._self_encoding) in self.__wrapped__:
61
- self.__wrapped__[item.encode(self._self_encoding)] = value
62
- elif isinstance(item, bytes) and item.decode(self._self_encoding) in self.__wrapped__:
63
- self.__wrapped__[item.decode(self._self_encoding)] = value
64
- else:
65
- self.__wrapped__[item] = value
66
-
67
- def __contains__(self, key: StringT) -> bool:
27
+ self._encoding = encoding
28
+ super().__init__(initial or {})
29
+
30
+ def _alt_key(self, key: StringT) -> StringT:
68
31
  if isinstance(key, str):
69
- return key in self.__wrapped__ or key.encode(self._self_encoding) in self.__wrapped__
32
+ try:
33
+ byte_alt = key.encode(self._encoding)
34
+ if byte_alt in self.data:
35
+ return byte_alt
36
+ except UnicodeEncodeError:
37
+ pass
70
38
  elif isinstance(key, bytes):
71
- return key in self.__wrapped__ or key.decode(self._self_encoding) in self.__wrapped__
72
- return key in self.__wrapped__
73
-
74
- def __repr__(self) -> str:
75
- return repr(self.__wrapped__)
39
+ try:
40
+ str_alt = key.decode(self._encoding)
41
+ if str_alt in self.data:
42
+ return str_alt
43
+ except UnicodeDecodeError:
44
+ pass
45
+ return key
46
+
47
+ def __getitem__(self, key: StringT) -> Any:
48
+ if key in self.data:
49
+ return self.data[key]
50
+ alt = self._alt_key(key)
51
+ if alt in self.data:
52
+ return self.data[alt]
53
+ raise KeyError(key)
54
+
55
+ def __setitem__(self, key: StringT, value: Any) -> None:
56
+ alt = self._alt_key(key)
57
+ self.data[alt] = value
58
+
59
+ def __delitem__(self, key: StringT) -> None:
60
+ alt = self._alt_key(key)
61
+ del self.data[alt]
62
+
63
+ def __contains__(self, key: Any) -> bool:
64
+ return key in self.data or self._alt_key(key) in self.data
65
+
66
+ def get(self, key: StringT, default: Any = None) -> Any:
67
+ return self.data.get(key, self.data.get(self._alt_key(key), default))
68
+
69
+ def pop(self, key: StringT, default: Any = None) -> Any:
70
+ if key in self.data:
71
+ return self.data.pop(key)
72
+ alt = self._alt_key(key)
73
+ return self.data.pop(alt, default)
76
74
 
77
75
 
78
76
  @enum.unique
@@ -122,10 +120,6 @@ def b(x: ResponseType, encoding: str | None = None) -> bytes:
122
120
  return _v.encode(encoding) if encoding else _v.encode()
123
121
 
124
122
 
125
- def defaultvalue(value: U | None, default: T) -> U | T:
126
- return default if value is None else value
127
-
128
-
129
123
  def nativestr(x: ResponseType, encoding: str = "utf-8") -> str:
130
124
  if isinstance(x, (str, bytes)):
131
125
  return x if isinstance(x, str) else x.decode(encoding, "replace")
@@ -8,11 +8,11 @@ import json
8
8
 
9
9
  version_json = '''
10
10
  {
11
- "date": "2025-07-05T19:34:23-0700",
11
+ "date": "2025-07-16T17:47:22-0700",
12
12
  "dirty": false,
13
13
  "error": null,
14
- "full-revisionid": "cd4583e1ad0eb6d8ca23e80203ab230efe1e3b2e",
15
- "version": "4.24.0"
14
+ "full-revisionid": "ac290229e2b463e1643d9829542cb1a59083b600",
15
+ "version": "5.0.0"
16
16
  }
17
17
  ''' # END VERSION_JSON
18
18