coredis 4.24.0__py3-none-any.whl → 5.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of coredis might be problematic. Click here for more details.
- coredis/__init__.py +1 -3
- coredis/_packer.py +10 -10
- coredis/_protocols.py +19 -51
- coredis/_py_311_typing.py +20 -0
- coredis/_py_312_typing.py +17 -0
- coredis/_utils.py +49 -55
- coredis/_version.py +3 -3
- coredis/cache.py +57 -82
- coredis/client/__init__.py +1 -2
- coredis/client/basic.py +129 -56
- coredis/client/cluster.py +147 -70
- coredis/commands/__init__.py +27 -7
- coredis/commands/_key_spec.py +11 -10
- coredis/commands/_utils.py +1 -1
- coredis/commands/_validators.py +30 -20
- coredis/commands/_wrappers.py +19 -99
- coredis/commands/bitfield.py +10 -2
- coredis/commands/constants.py +20 -3
- coredis/commands/core.py +1674 -1251
- coredis/commands/function.py +21 -19
- coredis/commands/monitor.py +0 -71
- coredis/commands/pubsub.py +7 -142
- coredis/commands/request.py +108 -0
- coredis/commands/script.py +21 -22
- coredis/commands/sentinel.py +60 -49
- coredis/connection.py +14 -15
- coredis/exceptions.py +2 -2
- coredis/experimental/__init__.py +0 -4
- coredis/globals.py +3 -0
- coredis/modules/autocomplete.py +28 -30
- coredis/modules/base.py +15 -31
- coredis/modules/filters.py +269 -245
- coredis/modules/graph.py +61 -62
- coredis/modules/json.py +172 -140
- coredis/modules/response/_callbacks/autocomplete.py +5 -4
- coredis/modules/response/_callbacks/graph.py +34 -29
- coredis/modules/response/_callbacks/json.py +5 -3
- coredis/modules/response/_callbacks/search.py +49 -53
- coredis/modules/response/_callbacks/timeseries.py +18 -30
- coredis/modules/response/types.py +1 -5
- coredis/modules/search.py +186 -169
- coredis/modules/timeseries.py +184 -164
- coredis/parser.py +6 -19
- coredis/pipeline.py +477 -521
- coredis/pool/basic.py +7 -7
- coredis/pool/cluster.py +3 -3
- coredis/pool/nodemanager.py +10 -3
- coredis/response/_callbacks/__init__.py +76 -57
- coredis/response/_callbacks/acl.py +0 -3
- coredis/response/_callbacks/cluster.py +25 -16
- coredis/response/_callbacks/command.py +8 -6
- coredis/response/_callbacks/connection.py +4 -3
- coredis/response/_callbacks/geo.py +17 -13
- coredis/response/_callbacks/hash.py +13 -11
- coredis/response/_callbacks/keys.py +9 -5
- coredis/response/_callbacks/module.py +2 -3
- coredis/response/_callbacks/script.py +6 -8
- coredis/response/_callbacks/sentinel.py +21 -17
- coredis/response/_callbacks/server.py +36 -14
- coredis/response/_callbacks/sets.py +3 -4
- coredis/response/_callbacks/sorted_set.py +27 -24
- coredis/response/_callbacks/streams.py +22 -13
- coredis/response/_callbacks/strings.py +7 -6
- coredis/response/_callbacks/vector_sets.py +159 -0
- coredis/response/types.py +13 -4
- coredis/retry.py +12 -13
- coredis/sentinel.py +11 -1
- coredis/stream.py +4 -3
- coredis/tokens.py +348 -16
- coredis/typing.py +432 -81
- {coredis-4.24.0.dist-info → coredis-5.0.0.dist-info}/METADATA +4 -9
- coredis-5.0.0.dist-info/RECORD +95 -0
- coredis/client/keydb.py +0 -336
- coredis/pipeline.pyi +0 -2103
- coredis-4.24.0.dist-info/RECORD +0 -93
- {coredis-4.24.0.dist-info → coredis-5.0.0.dist-info}/WHEEL +0 -0
- {coredis-4.24.0.dist-info → coredis-5.0.0.dist-info}/licenses/LICENSE +0 -0
- {coredis-4.24.0.dist-info → coredis-5.0.0.dist-info}/top_level.txt +0 -0
coredis/pool/basic.py
CHANGED
|
@@ -20,7 +20,7 @@ from coredis.connection import (
|
|
|
20
20
|
UnixDomainSocketConnection,
|
|
21
21
|
)
|
|
22
22
|
from coredis.exceptions import ConnectionError
|
|
23
|
-
from coredis.typing import Callable, ClassVar,
|
|
23
|
+
from coredis.typing import Callable, ClassVar, RedisValueT, TypeVar
|
|
24
24
|
|
|
25
25
|
_CPT = TypeVar("_CPT", bound="ConnectionPool")
|
|
26
26
|
|
|
@@ -250,9 +250,9 @@ class ConnectionPool:
|
|
|
250
250
|
async def get_connection(
|
|
251
251
|
self,
|
|
252
252
|
command_name: bytes | None = None,
|
|
253
|
-
*args:
|
|
253
|
+
*args: RedisValueT,
|
|
254
254
|
acquire: bool = True,
|
|
255
|
-
**kwargs:
|
|
255
|
+
**kwargs: RedisValueT | None,
|
|
256
256
|
) -> Connection:
|
|
257
257
|
"""Gets a connection from the pool"""
|
|
258
258
|
self.checkpid()
|
|
@@ -290,7 +290,7 @@ class ConnectionPool:
|
|
|
290
290
|
connection.disconnect()
|
|
291
291
|
self._created_connections -= 1
|
|
292
292
|
|
|
293
|
-
def _make_connection(self, **options:
|
|
293
|
+
def _make_connection(self, **options: RedisValueT | None) -> Connection:
|
|
294
294
|
"""
|
|
295
295
|
Creates a new connection
|
|
296
296
|
"""
|
|
@@ -347,7 +347,7 @@ class BlockingConnectionPool(ConnectionPool):
|
|
|
347
347
|
timeout: int = 20,
|
|
348
348
|
max_idle_time: int = 0,
|
|
349
349
|
idle_check_interval: int = 1,
|
|
350
|
-
**connection_kwargs:
|
|
350
|
+
**connection_kwargs: RedisValueT | None,
|
|
351
351
|
):
|
|
352
352
|
self.timeout = timeout
|
|
353
353
|
self.queue_class = queue_class
|
|
@@ -394,9 +394,9 @@ class BlockingConnectionPool(ConnectionPool):
|
|
|
394
394
|
async def get_connection(
|
|
395
395
|
self,
|
|
396
396
|
command_name: bytes | None = None,
|
|
397
|
-
*args:
|
|
397
|
+
*args: RedisValueT,
|
|
398
398
|
acquire: bool = True,
|
|
399
|
-
**kwargs:
|
|
399
|
+
**kwargs: RedisValueT | None,
|
|
400
400
|
) -> Connection:
|
|
401
401
|
"""Gets a connection from the pool"""
|
|
402
402
|
self.checkpid()
|
coredis/pool/cluster.py
CHANGED
|
@@ -21,8 +21,8 @@ from coredis.typing import (
|
|
|
21
21
|
ClassVar,
|
|
22
22
|
Iterable,
|
|
23
23
|
Node,
|
|
24
|
+
RedisValueT,
|
|
24
25
|
StringT,
|
|
25
|
-
ValueT,
|
|
26
26
|
)
|
|
27
27
|
|
|
28
28
|
|
|
@@ -205,9 +205,9 @@ class ClusterConnectionPool(ConnectionPool):
|
|
|
205
205
|
async def get_connection(
|
|
206
206
|
self,
|
|
207
207
|
command_name: bytes | None = None,
|
|
208
|
-
*keys:
|
|
208
|
+
*keys: RedisValueT,
|
|
209
209
|
acquire: bool = True,
|
|
210
|
-
**options:
|
|
210
|
+
**options: RedisValueT | None,
|
|
211
211
|
) -> Connection:
|
|
212
212
|
# Only pubsub command/connection should be allowed here
|
|
213
213
|
|
coredis/pool/nodemanager.py
CHANGED
|
@@ -17,8 +17,8 @@ from coredis.typing import (
|
|
|
17
17
|
Iterator,
|
|
18
18
|
Literal,
|
|
19
19
|
Node,
|
|
20
|
+
RedisValueT,
|
|
20
21
|
StringT,
|
|
21
|
-
ValueT,
|
|
22
22
|
)
|
|
23
23
|
|
|
24
24
|
HASH_SLOTS = 16384
|
|
@@ -85,8 +85,8 @@ class NodeManager:
|
|
|
85
85
|
self.nodemanager_follow_cluster = nodemanager_follow_cluster
|
|
86
86
|
self.replicas_per_shard = 0
|
|
87
87
|
|
|
88
|
-
def keys_to_nodes_by_slot(self, *keys:
|
|
89
|
-
mapping: dict[str, dict[int, list[
|
|
88
|
+
def keys_to_nodes_by_slot(self, *keys: RedisValueT) -> dict[str, dict[int, list[RedisValueT]]]:
|
|
89
|
+
mapping: dict[str, dict[int, list[RedisValueT]]] = {}
|
|
90
90
|
for k in keys:
|
|
91
91
|
node = self.node_from_slot(hash_slot(b(k)))
|
|
92
92
|
if node:
|
|
@@ -99,6 +99,13 @@ class NodeManager:
|
|
|
99
99
|
return node
|
|
100
100
|
return None # noqa
|
|
101
101
|
|
|
102
|
+
def nodes_from_slots(self, *slots: int) -> dict[str, list[int]]:
|
|
103
|
+
mapping: dict[str, list[int]] = {}
|
|
104
|
+
for slot in slots:
|
|
105
|
+
if node := self.node_from_slot(slot):
|
|
106
|
+
mapping.setdefault(node.name, []).append(slot)
|
|
107
|
+
return mapping
|
|
108
|
+
|
|
102
109
|
def all_nodes(self) -> Iterator[ManagedNode]:
|
|
103
110
|
yield from self.nodes.values()
|
|
104
111
|
|
|
@@ -10,7 +10,7 @@ import itertools
|
|
|
10
10
|
from abc import ABC, ABCMeta, abstractmethod
|
|
11
11
|
from typing import TYPE_CHECKING, Any, cast
|
|
12
12
|
|
|
13
|
-
from coredis._utils import b
|
|
13
|
+
from coredis._utils import b, nativestr
|
|
14
14
|
from coredis.exceptions import ClusterResponseError, ResponseError
|
|
15
15
|
from coredis.typing import (
|
|
16
16
|
AnyStr,
|
|
@@ -22,12 +22,12 @@ from coredis.typing import (
|
|
|
22
22
|
Mapping,
|
|
23
23
|
ParamSpec,
|
|
24
24
|
Protocol,
|
|
25
|
+
RedisValueT,
|
|
25
26
|
ResponsePrimitive,
|
|
26
27
|
ResponseType,
|
|
27
28
|
Sequence,
|
|
28
29
|
StringT,
|
|
29
30
|
TypeVar,
|
|
30
|
-
ValueT,
|
|
31
31
|
add_runtime_checks,
|
|
32
32
|
runtime_checkable,
|
|
33
33
|
)
|
|
@@ -69,11 +69,13 @@ class ClusterCallbackMeta(ABCMeta):
|
|
|
69
69
|
class ResponseCallback(ABC, Generic[RESP, RESP3, R], metaclass=ResponseCallbackMeta):
|
|
70
70
|
version: Literal[2, 3]
|
|
71
71
|
|
|
72
|
+
def __init__(self, **options: Any) -> None:
|
|
73
|
+
self.options = options
|
|
74
|
+
|
|
72
75
|
def __call__(
|
|
73
76
|
self,
|
|
74
77
|
response: RESP | RESP3 | ResponseError,
|
|
75
78
|
version: Literal[2, 3] = 2,
|
|
76
|
-
**options: ValueT | None,
|
|
77
79
|
) -> R:
|
|
78
80
|
self.version = version
|
|
79
81
|
if isinstance(response, ResponseError):
|
|
@@ -81,15 +83,15 @@ class ResponseCallback(ABC, Generic[RESP, RESP3, R], metaclass=ResponseCallbackM
|
|
|
81
83
|
if exc_to_response:
|
|
82
84
|
return exc_to_response
|
|
83
85
|
if version == 3:
|
|
84
|
-
return self.transform_3(cast(RESP3, response)
|
|
85
|
-
return self.transform(cast(RESP, response)
|
|
86
|
+
return self.transform_3(cast(RESP3, response))
|
|
87
|
+
return self.transform(cast(RESP, response))
|
|
86
88
|
|
|
87
89
|
@abstractmethod
|
|
88
|
-
def transform(self, response: RESP
|
|
90
|
+
def transform(self, response: RESP) -> R:
|
|
89
91
|
pass
|
|
90
92
|
|
|
91
|
-
def transform_3(self, response: RESP3
|
|
92
|
-
return self.transform(cast(RESP, response)
|
|
93
|
+
def transform_3(self, response: RESP3) -> R:
|
|
94
|
+
return self.transform(cast(RESP, response))
|
|
93
95
|
|
|
94
96
|
def handle_exception(self, exc: BaseException) -> R | None:
|
|
95
97
|
return exc # type: ignore
|
|
@@ -97,13 +99,11 @@ class ResponseCallback(ABC, Generic[RESP, RESP3, R], metaclass=ResponseCallbackM
|
|
|
97
99
|
|
|
98
100
|
@runtime_checkable
|
|
99
101
|
class AsyncPreProcessingCallback(Protocol):
|
|
100
|
-
async def pre_process(
|
|
101
|
-
self, client: Client[Any], response: ResponseType, **options: ValueT | None
|
|
102
|
-
) -> None: ...
|
|
102
|
+
async def pre_process(self, client: Client[Any], response: ResponseType) -> None: ...
|
|
103
103
|
|
|
104
104
|
|
|
105
105
|
class NoopCallback(ResponseCallback[R, R, R]):
|
|
106
|
-
def transform(self, response: R
|
|
106
|
+
def transform(self, response: R) -> R:
|
|
107
107
|
return response
|
|
108
108
|
|
|
109
109
|
|
|
@@ -112,22 +112,21 @@ class ClusterMultiNodeCallback(ABC, Generic[R], metaclass=ClusterCallbackMeta):
|
|
|
112
112
|
self,
|
|
113
113
|
responses: Mapping[str, R | ResponseError],
|
|
114
114
|
version: int = 2,
|
|
115
|
-
**kwargs: ValueT | None,
|
|
116
115
|
) -> R:
|
|
117
116
|
if version == 3:
|
|
118
|
-
return self.combine_3(responses
|
|
119
|
-
return self.combine(responses
|
|
117
|
+
return self.combine_3(responses)
|
|
118
|
+
return self.combine(responses)
|
|
120
119
|
|
|
121
120
|
@property
|
|
122
121
|
@abstractmethod
|
|
123
122
|
def response_policy(self) -> str: ...
|
|
124
123
|
|
|
125
124
|
@abstractmethod
|
|
126
|
-
def combine(self, responses: Mapping[str, R], **
|
|
125
|
+
def combine(self, responses: Mapping[str, R], **options: Any) -> R:
|
|
127
126
|
pass
|
|
128
127
|
|
|
129
|
-
def combine_3(self, responses: Mapping[str, R], **
|
|
130
|
-
return self.combine(responses, **
|
|
128
|
+
def combine_3(self, responses: Mapping[str, R], **options: Any) -> R:
|
|
129
|
+
return self.combine(responses, **options)
|
|
131
130
|
|
|
132
131
|
@classmethod
|
|
133
132
|
def raise_any(cls, values: Iterable[R]) -> None:
|
|
@@ -140,7 +139,7 @@ class ClusterBoolCombine(ClusterMultiNodeCallback[bool]):
|
|
|
140
139
|
def __init__(self, any: bool = False):
|
|
141
140
|
self.any = any
|
|
142
141
|
|
|
143
|
-
def combine(self, responses: Mapping[str, bool], **
|
|
142
|
+
def combine(self, responses: Mapping[str, bool], **options: Any) -> bool:
|
|
144
143
|
values = tuple(responses.values())
|
|
145
144
|
self.raise_any(values)
|
|
146
145
|
assert (isinstance(value, bool) for value in values)
|
|
@@ -157,7 +156,7 @@ class ClusterBoolCombine(ClusterMultiNodeCallback[bool]):
|
|
|
157
156
|
|
|
158
157
|
class ClusterAlignedBoolsCombine(ClusterMultiNodeCallback[tuple[bool, ...]]):
|
|
159
158
|
def combine(
|
|
160
|
-
self, responses: Mapping[str, tuple[bool, ...]], **
|
|
159
|
+
self, responses: Mapping[str, tuple[bool, ...]], **options: Any
|
|
161
160
|
) -> tuple[bool, ...]:
|
|
162
161
|
return tuple(all(k) for k in zip(*responses.values()))
|
|
163
162
|
|
|
@@ -170,7 +169,7 @@ class ClusterEnsureConsistent(ClusterMultiNodeCallback[R | None]):
|
|
|
170
169
|
def __init__(self, ensure_consistent: bool = True):
|
|
171
170
|
self.ensure_consistent = ensure_consistent
|
|
172
171
|
|
|
173
|
-
def combine(self, responses: Mapping[str, R | None], **
|
|
172
|
+
def combine(self, responses: Mapping[str, R | None], **options: Any) -> R | None:
|
|
174
173
|
values = tuple(responses.values())
|
|
175
174
|
self.raise_any(values)
|
|
176
175
|
if self.ensure_consistent and len(set(values)) != 1:
|
|
@@ -189,7 +188,7 @@ class ClusterEnsureConsistent(ClusterMultiNodeCallback[R | None]):
|
|
|
189
188
|
|
|
190
189
|
|
|
191
190
|
class ClusterFirstNonException(ClusterMultiNodeCallback[R | None]):
|
|
192
|
-
def combine(self, responses: Mapping[str, R | None], **
|
|
191
|
+
def combine(self, responses: Mapping[str, R | None], **options: Any) -> R | None:
|
|
193
192
|
for r in responses.values():
|
|
194
193
|
if not isinstance(r, BaseException):
|
|
195
194
|
return r
|
|
@@ -203,7 +202,7 @@ class ClusterFirstNonException(ClusterMultiNodeCallback[R | None]):
|
|
|
203
202
|
|
|
204
203
|
|
|
205
204
|
class ClusterMergeSets(ClusterMultiNodeCallback[set[R]]):
|
|
206
|
-
def combine(self, responses: Mapping[str, set[R]], **
|
|
205
|
+
def combine(self, responses: Mapping[str, set[R]], **options: Any) -> set[R]:
|
|
207
206
|
self.raise_any(responses.values())
|
|
208
207
|
return set(itertools.chain(*responses.values()))
|
|
209
208
|
|
|
@@ -213,11 +212,7 @@ class ClusterMergeSets(ClusterMultiNodeCallback[set[R]]):
|
|
|
213
212
|
|
|
214
213
|
|
|
215
214
|
class ClusterSum(ClusterMultiNodeCallback[int]):
|
|
216
|
-
def combine(
|
|
217
|
-
self,
|
|
218
|
-
responses: Mapping[str, int | ResponseError],
|
|
219
|
-
**kwargs: ValueT | None,
|
|
220
|
-
) -> int:
|
|
215
|
+
def combine(self, responses: Mapping[str, int | ResponseError], **options: Any) -> int:
|
|
221
216
|
self.raise_any(responses.values())
|
|
222
217
|
return sum(responses.values())
|
|
223
218
|
|
|
@@ -231,7 +226,7 @@ class ClusterMergeMapping(ClusterMultiNodeCallback[dict[CK_co, CR_co]]):
|
|
|
231
226
|
self.value_combine = value_combine
|
|
232
227
|
|
|
233
228
|
def combine(
|
|
234
|
-
self, responses: Mapping[str, dict[CK_co, CR_co]], **
|
|
229
|
+
self, responses: Mapping[str, dict[CK_co, CR_co]], **options: Any
|
|
235
230
|
) -> dict[CK_co, CR_co]:
|
|
236
231
|
self.raise_any(responses.values())
|
|
237
232
|
response: dict[CK_co, CR_co] = {}
|
|
@@ -246,9 +241,7 @@ class ClusterMergeMapping(ClusterMultiNodeCallback[dict[CK_co, CR_co]]):
|
|
|
246
241
|
|
|
247
242
|
|
|
248
243
|
class ClusterConcatenateTuples(ClusterMultiNodeCallback[tuple[R, ...]]):
|
|
249
|
-
def combine(
|
|
250
|
-
self, responses: Mapping[str, tuple[R, ...]], **kwargs: ValueT | None
|
|
251
|
-
) -> tuple[R, ...]:
|
|
244
|
+
def combine(self, responses: Mapping[str, tuple[R, ...]], **options: Any) -> tuple[R, ...]:
|
|
252
245
|
self.raise_any(responses.values())
|
|
253
246
|
return tuple(itertools.chain(*responses.values()))
|
|
254
247
|
|
|
@@ -263,12 +256,14 @@ class SimpleStringCallback(ResponseCallback[StringT | None, StringT | None, bool
|
|
|
263
256
|
raise_on_error: type[Exception] | None = None,
|
|
264
257
|
prefix_match: bool = False,
|
|
265
258
|
ok_values: set[str] = {"OK"},
|
|
259
|
+
**options: Any,
|
|
266
260
|
):
|
|
267
261
|
self.raise_on_error = raise_on_error
|
|
268
262
|
self.prefix_match = prefix_match
|
|
269
263
|
self.ok_values = {b(v) for v in ok_values}
|
|
264
|
+
super().__init__(**options)
|
|
270
265
|
|
|
271
|
-
def transform(self, response: StringT | None, **options:
|
|
266
|
+
def transform(self, response: StringT | None, **options: Any) -> bool:
|
|
272
267
|
if response:
|
|
273
268
|
if not self.prefix_match:
|
|
274
269
|
success = b(response) in self.ok_values
|
|
@@ -282,14 +277,14 @@ class SimpleStringCallback(ResponseCallback[StringT | None, StringT | None, bool
|
|
|
282
277
|
|
|
283
278
|
|
|
284
279
|
class IntCallback(ResponseCallback[int, int, int]):
|
|
285
|
-
def transform(self, response: ResponsePrimitive, **options:
|
|
280
|
+
def transform(self, response: ResponsePrimitive, **options: Any) -> int:
|
|
286
281
|
if isinstance(response, int):
|
|
287
282
|
return response
|
|
288
283
|
raise ValueError(f"Unable to map {response!r} to int")
|
|
289
284
|
|
|
290
285
|
|
|
291
286
|
class AnyStrCallback(ResponseCallback[StringT, StringT, AnyStr]):
|
|
292
|
-
def transform(self, response: StringT, **options:
|
|
287
|
+
def transform(self, response: StringT, **options: Any) -> AnyStr:
|
|
293
288
|
if isinstance(response, (bytes, str)):
|
|
294
289
|
return cast(AnyStr, response)
|
|
295
290
|
|
|
@@ -297,7 +292,7 @@ class AnyStrCallback(ResponseCallback[StringT, StringT, AnyStr]):
|
|
|
297
292
|
|
|
298
293
|
|
|
299
294
|
class FloatCallback(ResponseCallback[StringT | int | float, StringT | int | float, float]):
|
|
300
|
-
def transform(self, response: ResponseType, **options:
|
|
295
|
+
def transform(self, response: ResponseType, **options: Any) -> float:
|
|
301
296
|
if isinstance(response, float):
|
|
302
297
|
return response
|
|
303
298
|
if isinstance(response, (int, bytes, str)):
|
|
@@ -307,14 +302,14 @@ class FloatCallback(ResponseCallback[StringT | int | float, StringT | int | floa
|
|
|
307
302
|
|
|
308
303
|
|
|
309
304
|
class BoolCallback(ResponseCallback[int | bool, int | bool, bool]):
|
|
310
|
-
def transform(self, response: ResponseType, **options:
|
|
305
|
+
def transform(self, response: ResponseType, **options: Any) -> bool:
|
|
311
306
|
if isinstance(response, bool):
|
|
312
307
|
return response
|
|
313
308
|
return bool(response)
|
|
314
309
|
|
|
315
310
|
|
|
316
|
-
class SimpleStringOrIntCallback(ResponseCallback[
|
|
317
|
-
def transform(self, response:
|
|
311
|
+
class SimpleStringOrIntCallback(ResponseCallback[RedisValueT, RedisValueT, bool | int]):
|
|
312
|
+
def transform(self, response: RedisValueT, **options: Any) -> bool | int:
|
|
318
313
|
if isinstance(response, (int, bool)):
|
|
319
314
|
return response
|
|
320
315
|
elif isinstance(response, (str, bytes)):
|
|
@@ -323,28 +318,46 @@ class SimpleStringOrIntCallback(ResponseCallback[ValueT, ValueT, bool | int]):
|
|
|
323
318
|
|
|
324
319
|
|
|
325
320
|
class TupleCallback(ResponseCallback[list[ResponseType], list[ResponseType], tuple[CR_co, ...]]):
|
|
326
|
-
def transform(self, response: ResponseType, **options:
|
|
321
|
+
def transform(self, response: ResponseType, **options: Any) -> tuple[CR_co, ...]:
|
|
327
322
|
if isinstance(response, list):
|
|
328
323
|
return cast(tuple[CR_co, ...], tuple(response))
|
|
329
324
|
raise ValueError(f"Unable to map {response!r} to tuple")
|
|
330
325
|
|
|
331
326
|
|
|
327
|
+
class ItemOrTupleCallback(
|
|
328
|
+
ResponseCallback[
|
|
329
|
+
list[ResponseType] | ResponsePrimitive,
|
|
330
|
+
list[ResponseType] | ResponsePrimitive,
|
|
331
|
+
tuple[CR_co, ...] | CR_co,
|
|
332
|
+
]
|
|
333
|
+
):
|
|
334
|
+
def transform(
|
|
335
|
+
self, response: list[ResponseType] | ResponsePrimitive, **options: Any
|
|
336
|
+
) -> tuple[CR_co, ...] | CR_co:
|
|
337
|
+
if isinstance(response, list):
|
|
338
|
+
return cast(tuple[CR_co, ...], tuple(response))
|
|
339
|
+
return cast(CR_co, response)
|
|
340
|
+
|
|
341
|
+
|
|
332
342
|
class MixedTupleCallback(ResponseCallback[list[ResponseType], list[ResponseType], tuple[R, S]]):
|
|
333
|
-
def transform(self, response: ResponseType, **options:
|
|
343
|
+
def transform(self, response: ResponseType, **options: Any) -> tuple[R, S]:
|
|
334
344
|
if isinstance(response, list):
|
|
335
345
|
return cast(tuple[R, S], tuple(response))
|
|
336
346
|
raise ValueError(f"Unable to map {response!r} to tuple")
|
|
337
347
|
|
|
338
348
|
|
|
339
349
|
class ListCallback(ResponseCallback[list[ResponseType], list[ResponseType], list[CR_co]]):
|
|
340
|
-
def transform(self, response: list[ResponseType], **options:
|
|
350
|
+
def transform(self, response: list[ResponseType], **options: Any) -> list[CR_co]:
|
|
341
351
|
return cast(list[CR_co], response)
|
|
342
352
|
|
|
343
353
|
|
|
344
354
|
class DateTimeCallback(ResponseCallback[int | float, int | float, datetime.datetime]):
|
|
345
|
-
def transform(
|
|
355
|
+
def transform(
|
|
356
|
+
self,
|
|
357
|
+
response: int | float,
|
|
358
|
+
) -> datetime.datetime:
|
|
346
359
|
ts = float(response) if not isinstance(response, float) else response
|
|
347
|
-
if
|
|
360
|
+
if self.options.get("unit") == "milliseconds":
|
|
348
361
|
ts = ts / 1000.0
|
|
349
362
|
return datetime.datetime.fromtimestamp(ts)
|
|
350
363
|
|
|
@@ -360,14 +373,16 @@ class DictCallback(
|
|
|
360
373
|
self,
|
|
361
374
|
flat: bool = True,
|
|
362
375
|
recursive: list[str] | None = None,
|
|
376
|
+
**options: Any,
|
|
363
377
|
):
|
|
364
378
|
self.flat = flat
|
|
365
379
|
self.recursive = recursive or []
|
|
380
|
+
super().__init__(**options)
|
|
366
381
|
|
|
367
382
|
def transform(
|
|
368
383
|
self,
|
|
369
384
|
response: Sequence[ResponseType] | dict[ResponsePrimitive, ResponseType],
|
|
370
|
-
**options:
|
|
385
|
+
**options: Any,
|
|
371
386
|
) -> dict[CK_co, CR_co]:
|
|
372
387
|
if isinstance(response, list):
|
|
373
388
|
if self.flat:
|
|
@@ -383,7 +398,7 @@ class DictCallback(
|
|
|
383
398
|
def transform_3(
|
|
384
399
|
self,
|
|
385
400
|
response: Sequence[ResponseType] | dict[ResponsePrimitive, ResponseType],
|
|
386
|
-
**options:
|
|
401
|
+
**options: Any,
|
|
387
402
|
) -> dict[CK_co, CR_co]:
|
|
388
403
|
if isinstance(response, dict):
|
|
389
404
|
return cast(dict[CK_co, CR_co], response)
|
|
@@ -397,7 +412,11 @@ class DictCallback(
|
|
|
397
412
|
dct = []
|
|
398
413
|
for i in range(0, 2 * (len(item) // 2), 2):
|
|
399
414
|
key, value = item[i], item[i + 1]
|
|
400
|
-
value =
|
|
415
|
+
value = (
|
|
416
|
+
self.recursive_transformer(value)
|
|
417
|
+
if (nativestr(key) in self.recursive)
|
|
418
|
+
else value
|
|
419
|
+
)
|
|
401
420
|
dct.append((key, value))
|
|
402
421
|
return dict(dct)
|
|
403
422
|
else:
|
|
@@ -417,7 +436,7 @@ class SetCallback(
|
|
|
417
436
|
def transform(
|
|
418
437
|
self,
|
|
419
438
|
response: list[ResponsePrimitive] | set[ResponsePrimitive],
|
|
420
|
-
**options:
|
|
439
|
+
**options: Any,
|
|
421
440
|
) -> set[CR_co]:
|
|
422
441
|
if isinstance(response, list):
|
|
423
442
|
return cast(set[CR_co], set(response))
|
|
@@ -426,7 +445,7 @@ class SetCallback(
|
|
|
426
445
|
def transform_3(
|
|
427
446
|
self,
|
|
428
447
|
response: list[ResponsePrimitive] | set[ResponsePrimitive],
|
|
429
|
-
**options:
|
|
448
|
+
**options: Any,
|
|
430
449
|
) -> set[CR_co]:
|
|
431
450
|
if isinstance(response, set):
|
|
432
451
|
return cast(set[CR_co], response)
|
|
@@ -444,20 +463,20 @@ class OneOrManyCallback(
|
|
|
444
463
|
def transform(
|
|
445
464
|
self,
|
|
446
465
|
response: CR_co | list[CR_co | None] | None,
|
|
447
|
-
**options:
|
|
466
|
+
**options: Any,
|
|
448
467
|
) -> CR_co | list[CR_co | None] | None:
|
|
449
468
|
return response
|
|
450
469
|
|
|
451
470
|
|
|
452
471
|
class BoolsCallback(ResponseCallback[ResponseType, ResponseType, tuple[bool, ...]]):
|
|
453
|
-
def transform(self, response: ResponseType, **options:
|
|
472
|
+
def transform(self, response: ResponseType, **options: Any) -> tuple[bool, ...]:
|
|
454
473
|
if isinstance(response, list):
|
|
455
474
|
return tuple(BoolCallback()(r) for r in response)
|
|
456
475
|
return ()
|
|
457
476
|
|
|
458
477
|
|
|
459
478
|
class FloatsCallback(ResponseCallback[ResponseType, ResponseType, tuple[float, ...]]):
|
|
460
|
-
def transform(self, response: ResponseType, **options:
|
|
479
|
+
def transform(self, response: ResponseType, **options: Any) -> tuple[float, ...]:
|
|
461
480
|
if isinstance(response, list):
|
|
462
481
|
return tuple(FloatCallback()(r) for r in response)
|
|
463
482
|
return ()
|
|
@@ -473,7 +492,7 @@ class OptionalFloatCallback(
|
|
|
473
492
|
def transform(
|
|
474
493
|
self,
|
|
475
494
|
response: StringT | int | float | None,
|
|
476
|
-
**options:
|
|
495
|
+
**options: Any,
|
|
477
496
|
) -> float | None:
|
|
478
497
|
if response is None:
|
|
479
498
|
return None
|
|
@@ -481,7 +500,7 @@ class OptionalFloatCallback(
|
|
|
481
500
|
|
|
482
501
|
|
|
483
502
|
class OptionalIntCallback(ResponseCallback[int | None, int | None, int | None]):
|
|
484
|
-
def transform(self, response: int | None, **options:
|
|
503
|
+
def transform(self, response: int | None, **options: Any) -> int | None:
|
|
485
504
|
if response is None:
|
|
486
505
|
return None
|
|
487
506
|
if isinstance(response, int):
|
|
@@ -496,7 +515,7 @@ class OptionalAnyStrCallback(
|
|
|
496
515
|
AnyStr | None,
|
|
497
516
|
]
|
|
498
517
|
):
|
|
499
|
-
def transform(self, response: StringT | None, **options:
|
|
518
|
+
def transform(self, response: StringT | None, **options: Any) -> AnyStr | None:
|
|
500
519
|
if response is None:
|
|
501
520
|
return None
|
|
502
521
|
if isinstance(response, (bytes, str)):
|
|
@@ -507,12 +526,12 @@ class OptionalAnyStrCallback(
|
|
|
507
526
|
class OptionalListCallback(
|
|
508
527
|
ResponseCallback[list[ResponseType], list[ResponseType], list[CR_co] | None]
|
|
509
528
|
):
|
|
510
|
-
def transform(self, response: ResponseType, **options:
|
|
529
|
+
def transform(self, response: ResponseType, **options: Any) -> list[CR_co] | None:
|
|
511
530
|
return cast(list[CR_co], response)
|
|
512
531
|
|
|
513
532
|
|
|
514
533
|
class FirstValueCallback(ResponseCallback[list[CR_co], list[CR_co], CR_co]):
|
|
515
|
-
def transform(self, response: list[CR_co], **options:
|
|
534
|
+
def transform(self, response: list[CR_co], **options: Any) -> CR_co:
|
|
516
535
|
if response:
|
|
517
536
|
return response[0]
|
|
518
537
|
else:
|
|
@@ -5,7 +5,6 @@ from coredis.typing import (
|
|
|
5
5
|
AnyStr,
|
|
6
6
|
ResponsePrimitive,
|
|
7
7
|
Sequence,
|
|
8
|
-
ValueT,
|
|
9
8
|
)
|
|
10
9
|
|
|
11
10
|
|
|
@@ -19,7 +18,6 @@ class ACLLogCallback(
|
|
|
19
18
|
def transform(
|
|
20
19
|
self,
|
|
21
20
|
response: list[Sequence[ResponsePrimitive] | None],
|
|
22
|
-
**options: ValueT | None,
|
|
23
21
|
) -> tuple[dict[AnyStr, ResponsePrimitive] | None, ...]:
|
|
24
22
|
return tuple(
|
|
25
23
|
DictCallback[AnyStr, ResponsePrimitive]()(r, version=self.version)
|
|
@@ -30,6 +28,5 @@ class ACLLogCallback(
|
|
|
30
28
|
def transform_3(
|
|
31
29
|
self,
|
|
32
30
|
response: list[dict[AnyStr, ResponsePrimitive] | None],
|
|
33
|
-
**options: ValueT | None,
|
|
34
31
|
) -> tuple[dict[AnyStr, ResponsePrimitive] | None, ...]:
|
|
35
32
|
return tuple(response)
|
|
@@ -7,9 +7,9 @@ from coredis.response.types import ClusterNode, ClusterNodeDetail
|
|
|
7
7
|
from coredis.typing import (
|
|
8
8
|
AnyStr,
|
|
9
9
|
Mapping,
|
|
10
|
+
RedisValueT,
|
|
10
11
|
ResponsePrimitive,
|
|
11
12
|
ResponseType,
|
|
12
|
-
ValueT,
|
|
13
13
|
)
|
|
14
14
|
|
|
15
15
|
|
|
@@ -17,7 +17,8 @@ class ClusterLinksCallback(
|
|
|
17
17
|
ResponseCallback[ResponseType, ResponseType, list[dict[AnyStr, ResponsePrimitive]]]
|
|
18
18
|
):
|
|
19
19
|
def transform(
|
|
20
|
-
self,
|
|
20
|
+
self,
|
|
21
|
+
response: ResponseType,
|
|
21
22
|
) -> list[dict[AnyStr, ResponsePrimitive]]:
|
|
22
23
|
transformed: list[dict[AnyStr, ResponsePrimitive]] = []
|
|
23
24
|
|
|
@@ -26,13 +27,17 @@ class ClusterLinksCallback(
|
|
|
26
27
|
return transformed
|
|
27
28
|
|
|
28
29
|
def transform_3(
|
|
29
|
-
self,
|
|
30
|
+
self,
|
|
31
|
+
response: ResponseType,
|
|
30
32
|
) -> list[dict[AnyStr, ResponsePrimitive]]:
|
|
31
33
|
return response
|
|
32
34
|
|
|
33
35
|
|
|
34
36
|
class ClusterInfoCallback(ResponseCallback[ResponseType, ResponseType, dict[str, str]]):
|
|
35
|
-
def transform(
|
|
37
|
+
def transform(
|
|
38
|
+
self,
|
|
39
|
+
response: ResponseType,
|
|
40
|
+
) -> dict[str, str]:
|
|
36
41
|
response_str = nativestr(response)
|
|
37
42
|
return dict([line.split(":") for line in response_str.splitlines() if line])
|
|
38
43
|
|
|
@@ -41,7 +46,8 @@ class ClusterSlotsCallback(
|
|
|
41
46
|
ResponseCallback[ResponseType, ResponseType, dict[tuple[int, int], tuple[ClusterNode, ...]]]
|
|
42
47
|
):
|
|
43
48
|
def transform(
|
|
44
|
-
self,
|
|
49
|
+
self,
|
|
50
|
+
response: ResponseType,
|
|
45
51
|
) -> dict[tuple[int, int], tuple[ClusterNode, ...]]:
|
|
46
52
|
res: dict[tuple[int, int], tuple[ClusterNode, ...]] = {}
|
|
47
53
|
|
|
@@ -64,7 +70,8 @@ class ClusterSlotsCallback(
|
|
|
64
70
|
|
|
65
71
|
class ClusterNodesCallback(ResponseCallback[ResponseType, ResponseType, list[ClusterNodeDetail]]):
|
|
66
72
|
def transform(
|
|
67
|
-
self,
|
|
73
|
+
self,
|
|
74
|
+
response: ResponseType,
|
|
68
75
|
) -> list[ClusterNodeDetail]:
|
|
69
76
|
resp: list[str] | str
|
|
70
77
|
|
|
@@ -72,11 +79,11 @@ class ClusterNodesCallback(ResponseCallback[ResponseType, ResponseType, list[Clu
|
|
|
72
79
|
resp = [nativestr(row) for row in response]
|
|
73
80
|
else:
|
|
74
81
|
resp = nativestr(response)
|
|
75
|
-
current_host = nativestr(options.get("current_host", ""))
|
|
82
|
+
current_host = nativestr(self.options.get("current_host", ""))
|
|
76
83
|
|
|
77
|
-
def parse_slots(s: str) -> tuple[list[int], list[dict[str,
|
|
84
|
+
def parse_slots(s: str) -> tuple[list[int], list[dict[str, RedisValueT]]]:
|
|
78
85
|
slots: list[int] = []
|
|
79
|
-
migrations: list[dict[str,
|
|
86
|
+
migrations: list[dict[str, RedisValueT]] = []
|
|
80
87
|
|
|
81
88
|
for r in s.split(" "):
|
|
82
89
|
if "->-" in r:
|
|
@@ -150,17 +157,18 @@ class ClusterShardsCallback(
|
|
|
150
157
|
ResponseCallback[
|
|
151
158
|
ResponseType,
|
|
152
159
|
ResponseType,
|
|
153
|
-
list[dict[AnyStr, list[
|
|
160
|
+
list[dict[AnyStr, list[RedisValueT] | Mapping[AnyStr, RedisValueT]]],
|
|
154
161
|
]
|
|
155
162
|
):
|
|
156
163
|
def transform(
|
|
157
|
-
self,
|
|
158
|
-
|
|
159
|
-
|
|
164
|
+
self,
|
|
165
|
+
response: ResponseType,
|
|
166
|
+
) -> list[dict[AnyStr, list[RedisValueT] | Mapping[AnyStr, RedisValueT]]]:
|
|
167
|
+
shard_mapping: list[dict[AnyStr, list[RedisValueT] | Mapping[AnyStr, RedisValueT]]] = []
|
|
160
168
|
|
|
161
169
|
for shard in response:
|
|
162
170
|
transformed = EncodingInsensitiveDict(flat_pairs_to_dict(shard))
|
|
163
|
-
node_mapping: list[dict[AnyStr,
|
|
171
|
+
node_mapping: list[dict[AnyStr, RedisValueT]] = []
|
|
164
172
|
for node in transformed["nodes"]:
|
|
165
173
|
node_mapping.append(flat_pairs_to_dict(node))
|
|
166
174
|
|
|
@@ -169,6 +177,7 @@ class ClusterShardsCallback(
|
|
|
169
177
|
return shard_mapping
|
|
170
178
|
|
|
171
179
|
def transform_3(
|
|
172
|
-
self,
|
|
173
|
-
|
|
180
|
+
self,
|
|
181
|
+
response: ResponseType,
|
|
182
|
+
) -> list[dict[AnyStr, list[RedisValueT] | Mapping[AnyStr, RedisValueT]]]:
|
|
174
183
|
return response
|