coredis 5.2.0__cp314-cp314t-macosx_10_13_x86_64.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.

Files changed (100) hide show
  1. 22fe76227e35f92ab5c3__mypyc.cpython-314t-darwin.so +0 -0
  2. coredis/__init__.py +42 -0
  3. coredis/_enum.py +42 -0
  4. coredis/_json.py +11 -0
  5. coredis/_packer.cpython-314t-darwin.so +0 -0
  6. coredis/_packer.py +71 -0
  7. coredis/_protocols.py +50 -0
  8. coredis/_py_311_typing.py +20 -0
  9. coredis/_py_312_typing.py +17 -0
  10. coredis/_sidecar.py +114 -0
  11. coredis/_utils.cpython-314t-darwin.so +0 -0
  12. coredis/_utils.py +440 -0
  13. coredis/_version.py +34 -0
  14. coredis/_version.pyi +1 -0
  15. coredis/cache.py +801 -0
  16. coredis/client/__init__.py +6 -0
  17. coredis/client/basic.py +1238 -0
  18. coredis/client/cluster.py +1264 -0
  19. coredis/commands/__init__.py +64 -0
  20. coredis/commands/_key_spec.py +517 -0
  21. coredis/commands/_utils.py +108 -0
  22. coredis/commands/_validators.py +159 -0
  23. coredis/commands/_wrappers.py +175 -0
  24. coredis/commands/bitfield.py +110 -0
  25. coredis/commands/constants.py +662 -0
  26. coredis/commands/core.py +8484 -0
  27. coredis/commands/function.py +408 -0
  28. coredis/commands/monitor.py +168 -0
  29. coredis/commands/pubsub.py +905 -0
  30. coredis/commands/request.py +108 -0
  31. coredis/commands/script.py +296 -0
  32. coredis/commands/sentinel.py +246 -0
  33. coredis/config.py +50 -0
  34. coredis/connection.py +906 -0
  35. coredis/constants.cpython-314t-darwin.so +0 -0
  36. coredis/constants.py +37 -0
  37. coredis/credentials.py +45 -0
  38. coredis/exceptions.py +360 -0
  39. coredis/experimental/__init__.py +1 -0
  40. coredis/globals.py +23 -0
  41. coredis/modules/__init__.py +117 -0
  42. coredis/modules/autocomplete.py +138 -0
  43. coredis/modules/base.py +262 -0
  44. coredis/modules/filters.py +1319 -0
  45. coredis/modules/graph.py +362 -0
  46. coredis/modules/json.py +691 -0
  47. coredis/modules/response/__init__.py +0 -0
  48. coredis/modules/response/_callbacks/__init__.py +0 -0
  49. coredis/modules/response/_callbacks/autocomplete.py +42 -0
  50. coredis/modules/response/_callbacks/graph.py +237 -0
  51. coredis/modules/response/_callbacks/json.py +21 -0
  52. coredis/modules/response/_callbacks/search.py +221 -0
  53. coredis/modules/response/_callbacks/timeseries.py +158 -0
  54. coredis/modules/response/types.py +179 -0
  55. coredis/modules/search.py +1089 -0
  56. coredis/modules/timeseries.py +1139 -0
  57. coredis/parser.cpython-314t-darwin.so +0 -0
  58. coredis/parser.py +344 -0
  59. coredis/pipeline.py +1225 -0
  60. coredis/pool/__init__.py +11 -0
  61. coredis/pool/basic.py +453 -0
  62. coredis/pool/cluster.py +517 -0
  63. coredis/pool/nodemanager.py +340 -0
  64. coredis/py.typed +0 -0
  65. coredis/recipes/__init__.py +0 -0
  66. coredis/recipes/credentials/__init__.py +5 -0
  67. coredis/recipes/credentials/iam_provider.py +63 -0
  68. coredis/recipes/locks/__init__.py +5 -0
  69. coredis/recipes/locks/extend.lua +17 -0
  70. coredis/recipes/locks/lua_lock.py +281 -0
  71. coredis/recipes/locks/release.lua +10 -0
  72. coredis/response/__init__.py +5 -0
  73. coredis/response/_callbacks/__init__.py +538 -0
  74. coredis/response/_callbacks/acl.py +32 -0
  75. coredis/response/_callbacks/cluster.py +183 -0
  76. coredis/response/_callbacks/command.py +86 -0
  77. coredis/response/_callbacks/connection.py +31 -0
  78. coredis/response/_callbacks/geo.py +58 -0
  79. coredis/response/_callbacks/hash.py +85 -0
  80. coredis/response/_callbacks/keys.py +59 -0
  81. coredis/response/_callbacks/module.py +33 -0
  82. coredis/response/_callbacks/script.py +85 -0
  83. coredis/response/_callbacks/sentinel.py +179 -0
  84. coredis/response/_callbacks/server.py +241 -0
  85. coredis/response/_callbacks/sets.py +44 -0
  86. coredis/response/_callbacks/sorted_set.py +204 -0
  87. coredis/response/_callbacks/streams.py +185 -0
  88. coredis/response/_callbacks/strings.py +70 -0
  89. coredis/response/_callbacks/vector_sets.py +159 -0
  90. coredis/response/_utils.py +33 -0
  91. coredis/response/types.py +416 -0
  92. coredis/retry.py +233 -0
  93. coredis/sentinel.py +477 -0
  94. coredis/stream.py +369 -0
  95. coredis/tokens.py +2286 -0
  96. coredis/typing.py +580 -0
  97. coredis-5.2.0.dist-info/METADATA +211 -0
  98. coredis-5.2.0.dist-info/RECORD +100 -0
  99. coredis-5.2.0.dist-info/WHEEL +6 -0
  100. coredis-5.2.0.dist-info/licenses/LICENSE +23 -0
@@ -0,0 +1,179 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import cast
4
+
5
+ from coredis._utils import EncodingInsensitiveDict, nativestr
6
+ from coredis.response._callbacks import ResponseCallback
7
+ from coredis.response._callbacks.server import InfoCallback
8
+ from coredis.typing import (
9
+ AnyStr,
10
+ ResponsePrimitive,
11
+ ResponseType,
12
+ )
13
+
14
+ SENTINEL_STATE_INT_FIELDS = {
15
+ "can-failover-its-master",
16
+ "config-epoch",
17
+ "down-after-milliseconds",
18
+ "failover-timeout",
19
+ "info-refresh",
20
+ "last-hello-message",
21
+ "last-ok-ping-reply",
22
+ "last-ping-reply",
23
+ "last-ping-sent",
24
+ "master-link-down-time",
25
+ "master-port",
26
+ "num-other-sentinels",
27
+ "num-slaves",
28
+ "o-down-time",
29
+ "pending-commands",
30
+ "parallel-syncs",
31
+ "port",
32
+ "quorum",
33
+ "role-reported-time",
34
+ "s-down-time",
35
+ "slave-priority",
36
+ "slave-repl-offset",
37
+ "voted-leader-epoch",
38
+ }
39
+
40
+
41
+ def sentinel_state_typed(
42
+ response: list[str],
43
+ ) -> EncodingInsensitiveDict[str, str | int | bool]:
44
+ it = iter(response)
45
+ result: EncodingInsensitiveDict[str, str | int | bool] = EncodingInsensitiveDict()
46
+
47
+ for key, value in zip(it, it):
48
+ if key in SENTINEL_STATE_INT_FIELDS:
49
+ value = int(value)
50
+ result[key] = value
51
+
52
+ return result
53
+
54
+
55
+ def add_flags(
56
+ result: EncodingInsensitiveDict[str, int | str | bool],
57
+ ) -> EncodingInsensitiveDict[str, int | str | bool]:
58
+ flags = set(nativestr(result["flags"]).split(","))
59
+ for name, flag in (
60
+ ("is_master", "master"),
61
+ ("is_slave", "slave"),
62
+ ("is_sdown", "s_down"),
63
+ ("is_odown", "o_down"),
64
+ ("is_sentinel", "sentinel"),
65
+ ("is_disconnected", "disconnected"),
66
+ ("is_master_down", "master_down"),
67
+ ):
68
+ result[name] = flag in flags
69
+ return result
70
+
71
+
72
+ def parse_sentinel_state(
73
+ item: list[ResponsePrimitive],
74
+ ) -> EncodingInsensitiveDict[str, int | str | bool]:
75
+ result = sentinel_state_typed([nativestr(k) for k in item])
76
+ result = add_flags(result)
77
+ return result
78
+
79
+
80
+ class PrimaryCallback(
81
+ ResponseCallback[
82
+ ResponseType,
83
+ dict[ResponsePrimitive, ResponsePrimitive],
84
+ dict[str, ResponsePrimitive],
85
+ ]
86
+ ):
87
+ def transform(
88
+ self,
89
+ response: ResponseType,
90
+ ) -> dict[str, ResponsePrimitive]:
91
+ return parse_sentinel_state(cast(list[ResponsePrimitive], response)).stringify_keys()
92
+
93
+ def transform_3(
94
+ self,
95
+ response: dict[ResponsePrimitive, ResponsePrimitive],
96
+ ) -> dict[str, ResponsePrimitive]:
97
+ return add_flags(EncodingInsensitiveDict(response)).stringify_keys()
98
+
99
+
100
+ class PrimariesCallback(
101
+ ResponseCallback[
102
+ list[ResponseType],
103
+ list[ResponseType],
104
+ dict[str, dict[str, ResponsePrimitive]],
105
+ ]
106
+ ):
107
+ def transform(
108
+ self,
109
+ response: list[ResponseType] | dict[ResponsePrimitive, ResponsePrimitive],
110
+ ) -> dict[str, dict[str, ResponsePrimitive]]:
111
+ result: dict[str, dict[str, ResponseType]] = {}
112
+
113
+ for item in response:
114
+ state = PrimaryCallback()(item)
115
+ result[str(state["name"])] = state
116
+
117
+ return result
118
+
119
+ def transform_3(
120
+ self,
121
+ response: list[ResponseType],
122
+ ) -> dict[str, dict[str, ResponsePrimitive]]:
123
+ states: dict[str, dict[str, ResponsePrimitive]] = {}
124
+ for state in response:
125
+ state = add_flags(EncodingInsensitiveDict(state)).stringify_keys()
126
+ states[nativestr(state["name"])] = state
127
+ return states
128
+
129
+
130
+ class SentinelsStateCallback(
131
+ ResponseCallback[
132
+ list[ResponseType],
133
+ list[ResponseType],
134
+ tuple[dict[str, ResponsePrimitive], ...],
135
+ ]
136
+ ):
137
+ def transform(
138
+ self,
139
+ response: list[ResponseType],
140
+ ) -> tuple[dict[str, ResponsePrimitive], ...]:
141
+ return tuple(
142
+ parse_sentinel_state([nativestr(i) for i in item]).stringify_keys() for item in response
143
+ )
144
+
145
+ def transform_3(
146
+ self,
147
+ response: list[ResponseType],
148
+ ) -> tuple[dict[str, ResponsePrimitive], ...]:
149
+ return tuple(
150
+ add_flags(EncodingInsensitiveDict(state)).stringify_keys() for state in response
151
+ )
152
+
153
+
154
+ class GetPrimaryCallback(
155
+ ResponseCallback[
156
+ list[ResponsePrimitive],
157
+ list[ResponsePrimitive],
158
+ tuple[str, int] | None,
159
+ ]
160
+ ):
161
+ def transform(
162
+ self,
163
+ response: list[ResponsePrimitive],
164
+ ) -> tuple[str, int] | None:
165
+ return nativestr(response[0]), int(response[1]) if response else None
166
+
167
+
168
+ class SentinelInfoCallback(
169
+ ResponseCallback[
170
+ list[ResponseType],
171
+ list[ResponseType],
172
+ dict[AnyStr, dict[int, dict[str, ResponsePrimitive]]],
173
+ ]
174
+ ):
175
+ def transform(
176
+ self,
177
+ response: list[ResponseType],
178
+ ) -> dict[AnyStr, dict[int, dict[str, ResponsePrimitive]]]:
179
+ return {response[0]: {r[0]: InfoCallback()(r[1]) for r in response[1]}}
@@ -0,0 +1,241 @@
1
+ from __future__ import annotations
2
+
3
+ import datetime
4
+ from typing import Any
5
+
6
+ from coredis._utils import EncodingInsensitiveDict, nativestr
7
+ from coredis.response._callbacks import ResponseCallback
8
+ from coredis.response._utils import flat_pairs_to_dict
9
+ from coredis.response.types import ClientInfo, RoleInfo, SlowLogInfo
10
+ from coredis.typing import (
11
+ AnyStr,
12
+ ClassVar,
13
+ RedisValueT,
14
+ ResponsePrimitive,
15
+ ResponseType,
16
+ StringT,
17
+ )
18
+
19
+
20
+ class TimeCallback(ResponseCallback[list[AnyStr], list[AnyStr], datetime.datetime]):
21
+ def transform(
22
+ self,
23
+ response: list[AnyStr],
24
+ ) -> datetime.datetime:
25
+ return datetime.datetime.fromtimestamp(int(response[0])) + datetime.timedelta(
26
+ microseconds=int(response[1]) / 1000.0
27
+ )
28
+
29
+
30
+ class SlowlogCallback(ResponseCallback[ResponseType, ResponseType, tuple[SlowLogInfo, ...]]):
31
+ def transform(
32
+ self,
33
+ response: ResponseType,
34
+ ) -> tuple[SlowLogInfo, ...]:
35
+ return tuple(
36
+ SlowLogInfo(
37
+ id=item[0],
38
+ start_time=int(item[1]),
39
+ duration=int(item[2]),
40
+ command=item[3],
41
+ client_addr=item[4],
42
+ client_name=item[5],
43
+ )
44
+ for item in response
45
+ )
46
+
47
+
48
+ class ClientInfoCallback(ResponseCallback[ResponseType, ResponseType, ClientInfo]):
49
+ INT_FIELDS: ClassVar = {
50
+ "id",
51
+ "fd",
52
+ "age",
53
+ "idle",
54
+ "db",
55
+ "sub",
56
+ "psub",
57
+ "multi",
58
+ "qbuf-free",
59
+ "argv-mem",
60
+ "multi-mem",
61
+ "obl",
62
+ "oll",
63
+ "omem",
64
+ "tot-mem",
65
+ "redir",
66
+ }
67
+
68
+ def transform(
69
+ self,
70
+ response: ResponseType,
71
+ ) -> ClientInfo:
72
+ decoded_response = nativestr(response)
73
+ pairs = [pair.split("=", 1) for pair in decoded_response.strip().split(" ")]
74
+
75
+ info: ClientInfo = {} # type: ignore
76
+ for k, v in pairs:
77
+ if k in ClientInfoCallback.INT_FIELDS:
78
+ info[k] = int(v) # type: ignore
79
+ else:
80
+ info[k] = v # type: ignore
81
+ return info
82
+
83
+
84
+ class ClientListCallback(ResponseCallback[ResponseType, ResponseType, tuple[ClientInfo, ...]]):
85
+ def transform(
86
+ self,
87
+ response: ResponseType,
88
+ ) -> tuple[ClientInfo, ...]:
89
+ return tuple(ClientInfoCallback()(c) for c in response.splitlines())
90
+
91
+
92
+ class DebugCallback(ResponseCallback[ResponseType, ResponseType, dict[str, str | int]]):
93
+ INT_FIELDS: ClassVar = {"refcount", "serializedlength", "lru", "lru_seconds_idle"}
94
+
95
+ def transform(
96
+ self,
97
+ response: ResponseType,
98
+ ) -> dict[str, str | int]:
99
+ # The 'type' of the object is the first item in the response, but isn't
100
+ # prefixed with a name
101
+
102
+ response = nativestr(response)
103
+ response = "type:" + response
104
+ parsed: dict[str, str | int] = {}
105
+ parsed.update(dict([kv.split(":") for kv in response.split()]))
106
+
107
+ # parse some expected int values from the string response
108
+ # note: this cmd isn't spec'd so these may not appear in all redis versions
109
+
110
+ for field in DebugCallback.INT_FIELDS:
111
+ if field in parsed:
112
+ parsed[field] = int(parsed[field])
113
+
114
+ return parsed
115
+
116
+
117
+ class InfoCallback(
118
+ ResponseCallback[
119
+ StringT,
120
+ StringT,
121
+ dict[str, ResponseType],
122
+ ]
123
+ ):
124
+ def transform(
125
+ self,
126
+ response: StringT,
127
+ ) -> dict[str, ResponseType]:
128
+ """Parses the result of Redis's INFO command into a Python dict"""
129
+
130
+ info: dict[str, Any] = {}
131
+ response = nativestr(response)
132
+
133
+ def get_value(value: str) -> ResponseType:
134
+ if "," not in value or "=" not in value:
135
+ try:
136
+ if "." in value:
137
+ return float(value)
138
+ else:
139
+ return int(value)
140
+ except ValueError:
141
+ return value
142
+ else:
143
+ sub_dict: dict[ResponsePrimitive, ResponseType] = {}
144
+
145
+ for item in value.split(","):
146
+ k, v = item.rsplit("=", 1)
147
+ sub_dict[k] = get_value(v)
148
+
149
+ return sub_dict
150
+
151
+ cur_info = {}
152
+ header = None
153
+ for line in response.splitlines():
154
+ if line and not line.startswith("#"):
155
+ if line.find(":") != -1:
156
+ key, value = line.split(":", 1)
157
+ if key in cur_info:
158
+ if not isinstance(cur_info[key], list):
159
+ cur_info[key] = [cur_info[key]]
160
+ cur_info[key].append(get_value(value))
161
+ else:
162
+ cur_info[key] = get_value(value)
163
+ else:
164
+ # if the line isn't splittable, append it to the "__raw__" key
165
+ cur_info.setdefault("__raw__", []).append(line)
166
+ elif line:
167
+ if cur_info and header:
168
+ if self.options.get("nested"):
169
+ info[header] = cur_info
170
+ else:
171
+ info.update(cur_info)
172
+ cur_info = {}
173
+ header = line.lstrip("#").strip().lower()
174
+ if header and header not in info:
175
+ if self.options.get("nested"):
176
+ info[header] = cur_info
177
+ else:
178
+ info.update(cur_info)
179
+ return info
180
+
181
+
182
+ class RoleCallback(ResponseCallback[ResponseType, ResponseType, RoleInfo]):
183
+ def transform(
184
+ self,
185
+ response: ResponseType,
186
+ ) -> RoleInfo:
187
+ role = nativestr(response[0])
188
+
189
+ def _parse_master(response: Any) -> Any:
190
+ offset, replicas = response[1:]
191
+ res: dict[str, Any] = {"role": role, "offset": offset, "slaves": []}
192
+
193
+ for replica in replicas:
194
+ host, port, offset = replica
195
+ res["slaves"].append({"host": host, "port": int(port), "offset": int(offset)})
196
+
197
+ return res
198
+
199
+ def _parse_replica(response: Any) -> Any:
200
+ host, port, status, offset = response[1:]
201
+
202
+ return dict(
203
+ role=role,
204
+ status=status,
205
+ offset=offset,
206
+ )
207
+
208
+ def _parse_sentinel(response: Any) -> Any:
209
+ return {"role": role, "masters": response[1]}
210
+
211
+ parser = {
212
+ "master": _parse_master,
213
+ "slave": _parse_replica,
214
+ "sentinel": _parse_sentinel,
215
+ }[role]
216
+ return RoleInfo(**parser(response)) # type: ignore
217
+
218
+
219
+ class LatencyHistogramCallback(
220
+ ResponseCallback[ResponseType, ResponseType, dict[AnyStr, dict[AnyStr, RedisValueT]]]
221
+ ):
222
+ def transform(
223
+ self,
224
+ response: ResponseType,
225
+ ) -> dict[AnyStr, dict[AnyStr, RedisValueT]]:
226
+ histogram = flat_pairs_to_dict(response)
227
+ for key, value in histogram.items():
228
+ histogram[key] = EncodingInsensitiveDict(flat_pairs_to_dict(value))
229
+ histogram[key]["histogram_usec"] = flat_pairs_to_dict(histogram[key]["histogram_usec"])
230
+ histogram[key] = dict(histogram[key])
231
+ return histogram
232
+
233
+
234
+ class LatencyCallback(
235
+ ResponseCallback[ResponseType, ResponseType, dict[AnyStr, tuple[int, int, int]]]
236
+ ):
237
+ def transform(
238
+ self,
239
+ response: ResponseType,
240
+ ) -> dict[AnyStr, tuple[int, int, int]]:
241
+ return {k[0]: (k[1], k[2], k[3]) for k in response}
@@ -0,0 +1,44 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import cast
4
+
5
+ from coredis.response._callbacks import ResponseCallback
6
+ from coredis.typing import (
7
+ AnyStr,
8
+ Iterable,
9
+ ResponsePrimitive,
10
+ ResponseType,
11
+ )
12
+
13
+
14
+ class SScanCallback(
15
+ ResponseCallback[list[ResponseType], list[ResponseType], tuple[int, set[AnyStr]]]
16
+ ):
17
+ def transform(
18
+ self,
19
+ response: list[ResponseType],
20
+ ) -> tuple[int, set[AnyStr]]:
21
+ cursor, r = response
22
+ assert isinstance(cursor, (bytes, str)) and isinstance(r, Iterable)
23
+ return int(cursor), set(cast(Iterable[AnyStr], r))
24
+
25
+
26
+ class ItemOrSetCallback(
27
+ ResponseCallback[
28
+ AnyStr | list[ResponsePrimitive] | set[ResponsePrimitive],
29
+ AnyStr | set[ResponsePrimitive],
30
+ AnyStr | set[AnyStr],
31
+ ]
32
+ ):
33
+ def transform(
34
+ self,
35
+ response: AnyStr | list[ResponsePrimitive] | set[ResponsePrimitive],
36
+ ) -> AnyStr | set[AnyStr]:
37
+ if self.options.get("count"):
38
+ if isinstance(response, set):
39
+ return cast(set[AnyStr], response)
40
+ if isinstance(response, list):
41
+ return cast(set[AnyStr], set(response) if response else set())
42
+ raise ValueError(f"Unable to map {response!r} to set")
43
+ else:
44
+ return cast(AnyStr, response)
@@ -0,0 +1,204 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import SupportsFloat, cast
4
+
5
+ from coredis.response._callbacks import ResponseCallback
6
+ from coredis.response.types import ScoredMember, ScoredMembers
7
+ from coredis.typing import (
8
+ AnyStr,
9
+ Generic,
10
+ ResponsePrimitive,
11
+ ResponseType,
12
+ )
13
+
14
+
15
+ class ZRankCallback(
16
+ ResponseCallback[
17
+ int | list[ResponsePrimitive] | None,
18
+ int | list[ResponsePrimitive] | None,
19
+ int | tuple[int, float] | None,
20
+ ],
21
+ ):
22
+ def transform(
23
+ self,
24
+ response: int | list[ResponsePrimitive] | None,
25
+ ) -> int | tuple[int, float] | None:
26
+ if self.options.get("withscore"):
27
+ return (response[0], float(response[1])) if response else None
28
+ else:
29
+ return cast(int | None, response)
30
+
31
+ def transform_3(
32
+ self,
33
+ response: int | list[ResponsePrimitive] | None,
34
+ ) -> int | tuple[int, float] | None:
35
+ if self.options.get("withscore"):
36
+ return (response[0], response[1]) if response else None
37
+ else:
38
+ return cast(int | None, response)
39
+
40
+
41
+ class ZMembersOrScoredMembers(
42
+ ResponseCallback[
43
+ list[AnyStr | list[ResponsePrimitive]],
44
+ list[AnyStr | list[ResponsePrimitive]],
45
+ tuple[AnyStr | ScoredMember, ...],
46
+ ],
47
+ ):
48
+ def transform(
49
+ self,
50
+ response: list[AnyStr | list[ResponsePrimitive]],
51
+ ) -> tuple[AnyStr | ScoredMember, ...]:
52
+ if not response:
53
+ return ()
54
+ elif self.options.get("withscores"):
55
+ it = iter(cast(list[AnyStr], response))
56
+ return tuple(ScoredMember(*v) for v in zip(it, map(float, it)))
57
+ else:
58
+ return cast(tuple[AnyStr, ...], tuple(response))
59
+
60
+ def transform_3(
61
+ self,
62
+ response: list[AnyStr | list[ResponsePrimitive]],
63
+ ) -> tuple[AnyStr | ScoredMember, ...]:
64
+ if self.options.get("withscores"):
65
+ return tuple(ScoredMember(*v) for v in cast(list[tuple[AnyStr, float]], response))
66
+ else:
67
+ return cast(tuple[AnyStr, ...], tuple(response))
68
+
69
+
70
+ class ZSetScorePairCallback(
71
+ ResponseCallback[
72
+ list[ResponsePrimitive] | None,
73
+ list[ResponsePrimitive | list[ResponsePrimitive]] | None,
74
+ ScoredMember | ScoredMembers | None,
75
+ ],
76
+ Generic[AnyStr],
77
+ ):
78
+ def transform(
79
+ self,
80
+ response: list[ResponsePrimitive] | None,
81
+ ) -> ScoredMember | ScoredMembers | None:
82
+ if not response:
83
+ return None
84
+
85
+ if not (self.options.get("withscores") or self.options.get("count")):
86
+ return ScoredMember(cast(AnyStr, response[0]), float(cast(SupportsFloat, response[1])))
87
+
88
+ it = iter(response)
89
+ return tuple(ScoredMember(*v) for v in zip(it, map(float, it)))
90
+
91
+ def transform_3(
92
+ self,
93
+ response: list[ResponsePrimitive | list[ResponsePrimitive]] | None,
94
+ ) -> ScoredMember | ScoredMembers | None:
95
+ if not response:
96
+ return None
97
+
98
+ if not (self.options.get("withscores") or self.options.get("count")):
99
+ return ScoredMember(*cast(tuple[AnyStr, float], response))
100
+
101
+ return tuple(ScoredMember(*v) for v in cast(list[tuple[AnyStr, float]], response))
102
+
103
+
104
+ class ZMPopCallback(
105
+ ResponseCallback[
106
+ list[ResponseType] | None,
107
+ list[ResponseType] | None,
108
+ tuple[AnyStr, ScoredMembers] | None,
109
+ ],
110
+ Generic[AnyStr],
111
+ ):
112
+ def transform(
113
+ self,
114
+ response: list[ResponseType] | None,
115
+ ) -> tuple[AnyStr, ScoredMembers] | None:
116
+ r = cast(tuple[AnyStr, list[tuple[AnyStr, int]]], response)
117
+ if r:
118
+ return r[0], tuple(ScoredMember(v[0], float(v[1])) for v in r[1])
119
+
120
+ return None
121
+
122
+
123
+ class ZMScoreCallback(
124
+ ResponseCallback[list[ResponsePrimitive], list[ResponsePrimitive], tuple[float | None, ...]]
125
+ ):
126
+ def transform(
127
+ self,
128
+ response: list[ResponsePrimitive],
129
+ ) -> tuple[float | None, ...]:
130
+ return tuple(score if score is None else float(score) for score in response)
131
+
132
+
133
+ class ZScanCallback(
134
+ ResponseCallback[list[ResponseType], list[ResponseType], tuple[int, ScoredMembers]],
135
+ Generic[AnyStr],
136
+ ):
137
+ def transform(
138
+ self,
139
+ response: list[ResponseType],
140
+ ) -> tuple[int, ScoredMembers]:
141
+ cursor, r = cast(tuple[int, list[AnyStr]], response)
142
+ it = iter(r)
143
+ return int(cursor), tuple(
144
+ ScoredMember(*cast(tuple[AnyStr, float], v)) for v in zip(it, map(float, it))
145
+ )
146
+
147
+
148
+ class ZRandMemberCallback(
149
+ ResponseCallback[
150
+ AnyStr | list[ResponsePrimitive] | None,
151
+ AnyStr | list[list[ResponsePrimitive]] | list[ResponsePrimitive] | None,
152
+ AnyStr | tuple[AnyStr, ...] | ScoredMembers | None,
153
+ ]
154
+ ):
155
+ def transform(
156
+ self,
157
+ response: AnyStr | list[ResponsePrimitive] | None,
158
+ ) -> AnyStr | tuple[AnyStr, ...] | ScoredMembers | None:
159
+ if not (response and self.options.get("withscores")):
160
+ return tuple(response) if isinstance(response, list) else response
161
+
162
+ it = iter(response)
163
+ return tuple(ScoredMember(*v) for v in zip(it, map(float, it)))
164
+
165
+ def transform_3(
166
+ self,
167
+ response: AnyStr | list[list[ResponsePrimitive]] | list[ResponsePrimitive] | None,
168
+ ) -> AnyStr | tuple[AnyStr, ...] | ScoredMembers | None:
169
+ if not (response and self.options.get("withscores")):
170
+ return tuple(response) if isinstance(response, list) else response
171
+
172
+ return tuple(ScoredMember(*v) for v in response)
173
+
174
+
175
+ class BZPopCallback(
176
+ ResponseCallback[
177
+ list[ResponsePrimitive] | None,
178
+ list[ResponsePrimitive] | None,
179
+ tuple[AnyStr, AnyStr, float] | None,
180
+ ]
181
+ ):
182
+ def transform(
183
+ self,
184
+ response: list[ResponsePrimitive] | None,
185
+ ) -> tuple[AnyStr, AnyStr, float] | None:
186
+ if response:
187
+ return response[0], response[1], float(response[2])
188
+ return None
189
+
190
+
191
+ class ZAddCallback(ResponseCallback[ResponsePrimitive, int | float, int | float]):
192
+ def transform(
193
+ self,
194
+ response: ResponsePrimitive,
195
+ ) -> int | float:
196
+ if self.options.get("condition"):
197
+ return float(response)
198
+ return int(response)
199
+
200
+ def transform_3(
201
+ self,
202
+ response: int | float,
203
+ ) -> int | float:
204
+ return response