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.

Files changed (78) hide show
  1. coredis/__init__.py +1 -3
  2. coredis/_packer.py +10 -10
  3. coredis/_protocols.py +19 -51
  4. coredis/_py_311_typing.py +20 -0
  5. coredis/_py_312_typing.py +17 -0
  6. coredis/_utils.py +49 -55
  7. coredis/_version.py +3 -3
  8. coredis/cache.py +57 -82
  9. coredis/client/__init__.py +1 -2
  10. coredis/client/basic.py +129 -56
  11. coredis/client/cluster.py +147 -70
  12. coredis/commands/__init__.py +27 -7
  13. coredis/commands/_key_spec.py +11 -10
  14. coredis/commands/_utils.py +1 -1
  15. coredis/commands/_validators.py +30 -20
  16. coredis/commands/_wrappers.py +19 -99
  17. coredis/commands/bitfield.py +10 -2
  18. coredis/commands/constants.py +20 -3
  19. coredis/commands/core.py +1674 -1251
  20. coredis/commands/function.py +21 -19
  21. coredis/commands/monitor.py +0 -71
  22. coredis/commands/pubsub.py +7 -142
  23. coredis/commands/request.py +108 -0
  24. coredis/commands/script.py +21 -22
  25. coredis/commands/sentinel.py +60 -49
  26. coredis/connection.py +14 -15
  27. coredis/exceptions.py +2 -2
  28. coredis/experimental/__init__.py +0 -4
  29. coredis/globals.py +3 -0
  30. coredis/modules/autocomplete.py +28 -30
  31. coredis/modules/base.py +15 -31
  32. coredis/modules/filters.py +269 -245
  33. coredis/modules/graph.py +61 -62
  34. coredis/modules/json.py +172 -140
  35. coredis/modules/response/_callbacks/autocomplete.py +5 -4
  36. coredis/modules/response/_callbacks/graph.py +34 -29
  37. coredis/modules/response/_callbacks/json.py +5 -3
  38. coredis/modules/response/_callbacks/search.py +49 -53
  39. coredis/modules/response/_callbacks/timeseries.py +18 -30
  40. coredis/modules/response/types.py +1 -5
  41. coredis/modules/search.py +186 -169
  42. coredis/modules/timeseries.py +184 -164
  43. coredis/parser.py +6 -19
  44. coredis/pipeline.py +477 -521
  45. coredis/pool/basic.py +7 -7
  46. coredis/pool/cluster.py +3 -3
  47. coredis/pool/nodemanager.py +10 -3
  48. coredis/response/_callbacks/__init__.py +76 -57
  49. coredis/response/_callbacks/acl.py +0 -3
  50. coredis/response/_callbacks/cluster.py +25 -16
  51. coredis/response/_callbacks/command.py +8 -6
  52. coredis/response/_callbacks/connection.py +4 -3
  53. coredis/response/_callbacks/geo.py +17 -13
  54. coredis/response/_callbacks/hash.py +13 -11
  55. coredis/response/_callbacks/keys.py +9 -5
  56. coredis/response/_callbacks/module.py +2 -3
  57. coredis/response/_callbacks/script.py +6 -8
  58. coredis/response/_callbacks/sentinel.py +21 -17
  59. coredis/response/_callbacks/server.py +36 -14
  60. coredis/response/_callbacks/sets.py +3 -4
  61. coredis/response/_callbacks/sorted_set.py +27 -24
  62. coredis/response/_callbacks/streams.py +22 -13
  63. coredis/response/_callbacks/strings.py +7 -6
  64. coredis/response/_callbacks/vector_sets.py +159 -0
  65. coredis/response/types.py +13 -4
  66. coredis/retry.py +12 -13
  67. coredis/sentinel.py +11 -1
  68. coredis/stream.py +4 -3
  69. coredis/tokens.py +348 -16
  70. coredis/typing.py +432 -81
  71. {coredis-4.24.0.dist-info → coredis-5.0.0.dist-info}/METADATA +4 -9
  72. coredis-5.0.0.dist-info/RECORD +95 -0
  73. coredis/client/keydb.py +0 -336
  74. coredis/pipeline.pyi +0 -2103
  75. coredis-4.24.0.dist-info/RECORD +0 -93
  76. {coredis-4.24.0.dist-info → coredis-5.0.0.dist-info}/WHEEL +0 -0
  77. {coredis-4.24.0.dist-info → coredis-5.0.0.dist-info}/licenses/LICENSE +0 -0
  78. {coredis-4.24.0.dist-info → coredis-5.0.0.dist-info}/top_level.txt +0 -0
@@ -9,7 +9,6 @@ from coredis.typing import (
9
9
  Generic,
10
10
  ResponsePrimitive,
11
11
  ResponseType,
12
- ValueT,
13
12
  )
14
13
 
15
14
 
@@ -23,9 +22,8 @@ class ZRankCallback(
23
22
  def transform(
24
23
  self,
25
24
  response: int | list[ResponsePrimitive] | None,
26
- **options: ValueT | None,
27
25
  ) -> int | tuple[int, float] | None:
28
- if options.get("withscore"):
26
+ if self.options.get("withscore"):
29
27
  return (response[0], float(response[1])) if response else None
30
28
  else:
31
29
  return cast(int | None, response)
@@ -33,9 +31,8 @@ class ZRankCallback(
33
31
  def transform_3(
34
32
  self,
35
33
  response: int | list[ResponsePrimitive] | None,
36
- **options: ValueT | None,
37
34
  ) -> int | tuple[int, float] | None:
38
- if options.get("withscore"):
35
+ if self.options.get("withscore"):
39
36
  return (response[0], response[1]) if response else None
40
37
  else:
41
38
  return cast(int | None, response)
@@ -51,11 +48,10 @@ class ZMembersOrScoredMembers(
51
48
  def transform(
52
49
  self,
53
50
  response: list[AnyStr | list[ResponsePrimitive]],
54
- **options: ValueT | None,
55
51
  ) -> tuple[AnyStr | ScoredMember, ...]:
56
52
  if not response:
57
53
  return ()
58
- elif options.get("withscores"):
54
+ elif self.options.get("withscores"):
59
55
  it = iter(cast(list[AnyStr], response))
60
56
  return tuple(ScoredMember(*v) for v in zip(it, map(float, it)))
61
57
  else:
@@ -64,9 +60,8 @@ class ZMembersOrScoredMembers(
64
60
  def transform_3(
65
61
  self,
66
62
  response: list[AnyStr | list[ResponsePrimitive]],
67
- **options: ValueT | None,
68
63
  ) -> tuple[AnyStr | ScoredMember, ...]:
69
- if options.get("withscores"):
64
+ if self.options.get("withscores"):
70
65
  return tuple(ScoredMember(*v) for v in cast(list[tuple[AnyStr, float]], response))
71
66
  else:
72
67
  return cast(tuple[AnyStr, ...], tuple(response))
@@ -81,12 +76,13 @@ class ZSetScorePairCallback(
81
76
  Generic[AnyStr],
82
77
  ):
83
78
  def transform(
84
- self, response: list[ResponsePrimitive] | None, **options: ValueT | None
79
+ self,
80
+ response: list[ResponsePrimitive] | None,
85
81
  ) -> ScoredMember | ScoredMembers | None:
86
82
  if not response:
87
83
  return None
88
84
 
89
- if not (options.get("withscores") or options.get("count")):
85
+ if not (self.options.get("withscores") or self.options.get("count")):
90
86
  return ScoredMember(cast(AnyStr, response[0]), float(cast(SupportsFloat, response[1])))
91
87
 
92
88
  it = iter(response)
@@ -95,12 +91,11 @@ class ZSetScorePairCallback(
95
91
  def transform_3(
96
92
  self,
97
93
  response: list[ResponsePrimitive | list[ResponsePrimitive]] | None,
98
- **options: ValueT | None,
99
94
  ) -> ScoredMember | ScoredMembers | None:
100
95
  if not response:
101
96
  return None
102
97
 
103
- if not (options.get("withscores") or options.get("count")):
98
+ if not (self.options.get("withscores") or self.options.get("count")):
104
99
  return ScoredMember(*cast(tuple[AnyStr, float], response))
105
100
 
106
101
  return tuple(ScoredMember(*v) for v in cast(list[tuple[AnyStr, float]], response))
@@ -115,7 +110,8 @@ class ZMPopCallback(
115
110
  Generic[AnyStr],
116
111
  ):
117
112
  def transform(
118
- self, response: list[ResponseType] | None, **options: ValueT | None
113
+ self,
114
+ response: list[ResponseType] | None,
119
115
  ) -> tuple[AnyStr, ScoredMembers] | None:
120
116
  r = cast(tuple[AnyStr, list[tuple[AnyStr, int]]], response)
121
117
  if r:
@@ -128,7 +124,8 @@ class ZMScoreCallback(
128
124
  ResponseCallback[list[ResponsePrimitive], list[ResponsePrimitive], tuple[float | None, ...]]
129
125
  ):
130
126
  def transform(
131
- self, response: list[ResponsePrimitive], **options: ValueT | None
127
+ self,
128
+ response: list[ResponsePrimitive],
132
129
  ) -> tuple[float | None, ...]:
133
130
  return tuple(score if score is None else float(score) for score in response)
134
131
 
@@ -138,7 +135,8 @@ class ZScanCallback(
138
135
  Generic[AnyStr],
139
136
  ):
140
137
  def transform(
141
- self, response: list[ResponseType], **options: ValueT | None
138
+ self,
139
+ response: list[ResponseType],
142
140
  ) -> tuple[int, ScoredMembers]:
143
141
  cursor, r = cast(tuple[int, list[AnyStr]], response)
144
142
  it = iter(r)
@@ -157,9 +155,8 @@ class ZRandMemberCallback(
157
155
  def transform(
158
156
  self,
159
157
  response: AnyStr | list[ResponsePrimitive] | None,
160
- **options: ValueT | None,
161
158
  ) -> AnyStr | tuple[AnyStr, ...] | ScoredMembers | None:
162
- if not (response and options.get("withscores")):
159
+ if not (response and self.options.get("withscores")):
163
160
  return tuple(response) if isinstance(response, list) else response
164
161
 
165
162
  it = iter(response)
@@ -168,9 +165,8 @@ class ZRandMemberCallback(
168
165
  def transform_3(
169
166
  self,
170
167
  response: AnyStr | list[list[ResponsePrimitive]] | list[ResponsePrimitive] | None,
171
- **options: ValueT | None,
172
168
  ) -> AnyStr | tuple[AnyStr, ...] | ScoredMembers | None:
173
- if not (response and options.get("withscores")):
169
+ if not (response and self.options.get("withscores")):
174
170
  return tuple(response) if isinstance(response, list) else response
175
171
 
176
172
  return tuple(ScoredMember(*v) for v in response)
@@ -184,7 +180,8 @@ class BZPopCallback(
184
180
  ]
185
181
  ):
186
182
  def transform(
187
- self, response: list[ResponsePrimitive] | None, **options: ValueT | None
183
+ self,
184
+ response: list[ResponsePrimitive] | None,
188
185
  ) -> tuple[AnyStr, AnyStr, float] | None:
189
186
  if response:
190
187
  return response[0], response[1], float(response[2])
@@ -192,10 +189,16 @@ class BZPopCallback(
192
189
 
193
190
 
194
191
  class ZAddCallback(ResponseCallback[ResponsePrimitive, int | float, int | float]):
195
- def transform(self, response: ResponsePrimitive, **options: ValueT | None) -> int | float:
196
- if options.get("condition"):
192
+ def transform(
193
+ self,
194
+ response: ResponsePrimitive,
195
+ ) -> int | float:
196
+ if self.options.get("condition"):
197
197
  return float(response)
198
198
  return int(response)
199
199
 
200
- def transform_3(self, response: int | float, **options: ValueT | None) -> int | float:
200
+ def transform_3(
201
+ self,
202
+ response: int | float,
203
+ ) -> int | float:
201
204
  return response
@@ -16,13 +16,13 @@ from coredis.typing import (
16
16
  OrderedDict,
17
17
  ResponseType,
18
18
  StringT,
19
- ValueT,
20
19
  )
21
20
 
22
21
 
23
22
  class StreamRangeCallback(ResponseCallback[ResponseType, ResponseType, tuple[StreamEntry, ...]]):
24
23
  def transform(
25
- self, response: ResponseType, **options: ValueT | None
24
+ self,
25
+ response: ResponseType,
26
26
  ) -> tuple[StreamEntry, ...]:
27
27
  return tuple(StreamEntry(r[0], flat_pairs_to_ordered_dict(r[1])) for r in response)
28
28
 
@@ -31,9 +31,10 @@ class ClaimCallback(
31
31
  ResponseCallback[ResponseType, ResponseType, tuple[AnyStr, ...] | tuple[StreamEntry, ...]]
32
32
  ):
33
33
  def transform(
34
- self, response: ResponseType, **options: ValueT | None
34
+ self,
35
+ response: ResponseType,
35
36
  ) -> tuple[AnyStr, ...] | tuple[StreamEntry, ...]:
36
- if options.get("justid") is not None:
37
+ if self.options.get("justid") is not None:
37
38
  return tuple(response)
38
39
  else:
39
40
  return StreamRangeCallback()(response)
@@ -48,12 +49,13 @@ class AutoClaimCallback(
48
49
  ]
49
50
  ):
50
51
  def transform(
51
- self, response: ResponseType, **options: ValueT | None
52
+ self,
53
+ response: ResponseType,
52
54
  ) -> (
53
55
  tuple[AnyStr, tuple[AnyStr, ...]]
54
56
  | tuple[AnyStr, tuple[StreamEntry, ...], tuple[AnyStr, ...]]
55
57
  ):
56
- if options.get("justid") is not None:
58
+ if self.options.get("justid") is not None:
57
59
  return response[0], tuple(response[1])
58
60
  else:
59
61
  return (
@@ -67,7 +69,8 @@ class MultiStreamRangeCallback(
67
69
  ResponseCallback[ResponseType, ResponseType, dict[AnyStr, tuple[StreamEntry, ...]] | None]
68
70
  ):
69
71
  def transform_3(
70
- self, response: ResponseType, **options: ValueT | None
72
+ self,
73
+ response: ResponseType,
71
74
  ) -> dict[AnyStr, tuple[StreamEntry, ...]] | None:
72
75
  if response:
73
76
  mapping: dict[AnyStr, tuple[StreamEntry, ...]] = {}
@@ -81,7 +84,8 @@ class MultiStreamRangeCallback(
81
84
  return None
82
85
 
83
86
  def transform(
84
- self, response: ResponseType, **options: ValueT | None
87
+ self,
88
+ response: ResponseType,
85
89
  ) -> dict[AnyStr, tuple[StreamEntry, ...]] | None:
86
90
  if response:
87
91
  mapping: dict[AnyStr, tuple[StreamEntry, ...]] = {}
@@ -99,9 +103,10 @@ class PendingCallback(
99
103
  ResponseCallback[ResponseType, ResponseType, StreamPending | tuple[StreamPendingExt, ...]]
100
104
  ):
101
105
  def transform(
102
- self, response: ResponseType, **options: ValueT | None
106
+ self,
107
+ response: ResponseType,
103
108
  ) -> StreamPending | tuple[StreamPendingExt, ...]:
104
- if not options.get("count"):
109
+ if not self.options.get("count"):
105
110
  return StreamPending(
106
111
  response[0],
107
112
  response[1],
@@ -114,15 +119,19 @@ class PendingCallback(
114
119
 
115
120
  class XInfoCallback(ResponseCallback[ResponseType, ResponseType, tuple[dict[AnyStr, AnyStr], ...]]):
116
121
  def transform(
117
- self, response: ResponseType, **options: ValueT | None
122
+ self,
123
+ response: ResponseType,
118
124
  ) -> tuple[dict[AnyStr, AnyStr], ...]:
119
125
  return tuple(flat_pairs_to_dict(row) for row in response)
120
126
 
121
127
 
122
128
  class StreamInfoCallback(ResponseCallback[ResponseType, ResponseType, StreamInfo]):
123
- def transform(self, response: ResponseType, **options: ValueT | None) -> StreamInfo:
129
+ def transform(
130
+ self,
131
+ response: ResponseType,
132
+ ) -> StreamInfo:
124
133
  res: dict[StringT, Any] = EncodingInsensitiveDict(flat_pairs_to_dict(response))
125
- if not options.get("full"):
134
+ if not self.options.get("full"):
126
135
  k1 = "first-entry"
127
136
  kn = "last-entry"
128
137
  e1: StreamEntry | None = None
@@ -1,5 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from typing import Any
4
+
3
5
  from coredis._utils import EncodingInsensitiveDict
4
6
  from coredis.response._callbacks import ResponseCallback, SimpleStringCallback
5
7
  from coredis.response.types import LCSMatch, LCSResult
@@ -7,13 +9,12 @@ from coredis.typing import (
7
9
  AnyStr,
8
10
  ResponsePrimitive,
9
11
  ResponseType,
10
- ValueT,
11
12
  )
12
13
 
13
14
 
14
15
  class StringSetCallback(ResponseCallback[AnyStr | None, AnyStr | None, AnyStr | bool | None]):
15
- def transform(self, response: AnyStr | None, **options: ValueT | None) -> AnyStr | bool | None:
16
- if options.get("get"):
16
+ def transform(self, response: AnyStr | None, **options: Any) -> AnyStr | bool | None:
17
+ if self.options.get("get"):
17
18
  return response
18
19
  else:
19
20
  return SimpleStringCallback()(response)
@@ -23,13 +24,13 @@ class LCSCallback(
23
24
  ResponseCallback[
24
25
  list[ResponseType],
25
26
  dict[ResponsePrimitive, ResponseType],
26
- AnyStr | int | LCSResult,
27
+ LCSResult,
27
28
  ]
28
29
  ):
29
30
  def transform(
30
31
  self,
31
32
  response: (list[ResponseType] | dict[ResponsePrimitive, ResponseType]),
32
- **options: ValueT | None,
33
+ **options: Any,
33
34
  ) -> LCSResult:
34
35
  assert (
35
36
  isinstance(response, list)
@@ -52,7 +53,7 @@ class LCSCallback(
52
53
  def transform_3(
53
54
  self,
54
55
  response: dict[ResponsePrimitive, ResponseType],
55
- **options: ValueT | None,
56
+ **options: Any,
56
57
  ) -> LCSResult:
57
58
  proxy = EncodingInsensitiveDict(response)
58
59
 
@@ -0,0 +1,159 @@
1
+ from __future__ import annotations
2
+
3
+ from coredis._json import json
4
+ from coredis._utils import nativestr
5
+ from coredis.response._callbacks import ResponseCallback
6
+ from coredis.response._utils import flat_pairs_to_dict
7
+ from coredis.response.types import VectorData
8
+ from coredis.typing import AnyStr, JsonType, ResponsePrimitive, StringT
9
+
10
+
11
+ class VSimCallback(
12
+ ResponseCallback[
13
+ list[AnyStr],
14
+ list[AnyStr] | dict[AnyStr, float | list[float | JsonType]],
15
+ tuple[AnyStr, ...]
16
+ | dict[AnyStr, float]
17
+ | dict[AnyStr, JsonType]
18
+ | dict[AnyStr, tuple[float, JsonType]],
19
+ ],
20
+ ):
21
+ def transform(
22
+ self,
23
+ response: list[AnyStr],
24
+ ) -> (
25
+ tuple[AnyStr, ...]
26
+ | dict[AnyStr, float]
27
+ | dict[AnyStr, JsonType]
28
+ | dict[AnyStr, tuple[float, JsonType]]
29
+ ):
30
+ withscores, withattribs = self.options.get("withscores"), self.options.get("withattribs")
31
+ if withscores or withattribs:
32
+ it = iter(response)
33
+ match withscores, withattribs:
34
+ case True, None | False:
35
+ return dict(list(zip(it, map(float, it))))
36
+ case None | False, True:
37
+ return dict(list(zip(it, map(json.loads, it))))
38
+ case True, True:
39
+ return dict(
40
+ list(zip(it, map(lambda x: (float(x[0]), json.loads(x[1])), zip(it, it))))
41
+ )
42
+ else:
43
+ return self.transform_3(response)
44
+
45
+ def transform_3(
46
+ self,
47
+ response: list[AnyStr]
48
+ | dict[AnyStr, float]
49
+ | dict[AnyStr, AnyStr]
50
+ | dict[AnyStr, list[float | AnyStr]],
51
+ ) -> (
52
+ tuple[AnyStr, ...]
53
+ | dict[AnyStr, float]
54
+ | dict[AnyStr, JsonType]
55
+ | dict[AnyStr, tuple[float, JsonType]]
56
+ ):
57
+ withscores, withattribs = self.options.get("withscores"), self.options.get("withattribs")
58
+ if withscores or withattribs:
59
+ assert isinstance(response, dict)
60
+ match withscores, withattribs:
61
+ case None | False, True:
62
+ return {k: json.loads(v) for k, v in response.items()}
63
+ case True, True:
64
+ return {k: (v[0], json.loads(v[1])) for k, v in response.items()}
65
+ case _:
66
+ return response
67
+ else:
68
+ return tuple(response)
69
+
70
+
71
+ class VLinksCallback(
72
+ ResponseCallback[
73
+ list[list[AnyStr]] | None,
74
+ list[list[AnyStr] | dict[AnyStr, float]] | None,
75
+ tuple[tuple[AnyStr, ...] | dict[AnyStr, float], ...] | None,
76
+ ],
77
+ ):
78
+ def transform(
79
+ self,
80
+ response: list[list[AnyStr]] | None,
81
+ ) -> tuple[tuple[AnyStr, ...] | dict[AnyStr, float], ...] | None:
82
+ if response:
83
+ if self.options.get("withscores"):
84
+ return tuple(dict(zip(it := iter(layer), map(float, it))) for layer in response)
85
+ else:
86
+ return tuple(tuple(layer) for layer in response)
87
+ return None
88
+
89
+ def transform_3(
90
+ self,
91
+ response: list[list[AnyStr] | dict[AnyStr, float]] | None,
92
+ ) -> tuple[tuple[AnyStr, ...] | dict[AnyStr, float], ...] | None:
93
+ if response:
94
+ if self.options.get("withscores"):
95
+ assert isinstance(response[0], dict)
96
+ return tuple(response)
97
+ else:
98
+ return tuple(tuple(layer) for layer in response)
99
+ return None
100
+
101
+
102
+ class VEmbCallback(
103
+ ResponseCallback[
104
+ list[StringT] | list[ResponsePrimitive],
105
+ list[float] | list[ResponsePrimitive],
106
+ tuple[float, ...] | VectorData | None,
107
+ ]
108
+ ):
109
+ def transform(
110
+ self,
111
+ response: list[StringT] | list[ResponsePrimitive] | None,
112
+ ) -> tuple[float, ...] | VectorData | None:
113
+ if response:
114
+ if self.options.get("raw"):
115
+ return VectorData(
116
+ quantization=nativestr(response[0]),
117
+ blob=response[1],
118
+ l2_norm=float(response[2]),
119
+ quantization_range=float(response[3]) if len(response) == 4 else None,
120
+ )
121
+ else:
122
+ return tuple(map(float, response))
123
+ return None
124
+
125
+ def transform_3(
126
+ self,
127
+ response: list[float] | list[ResponsePrimitive] | None,
128
+ ) -> tuple[float, ...] | VectorData | None:
129
+ if response:
130
+ if self.options.get("raw"):
131
+ return VectorData(
132
+ quantization=nativestr(response[0]),
133
+ blob=response[1],
134
+ l2_norm=response[2],
135
+ quantization_range=response[3] if len(response) == 4 else None,
136
+ )
137
+ else:
138
+ return tuple(response)
139
+ return None
140
+
141
+
142
+ class VInfoCallback(
143
+ ResponseCallback[
144
+ list[AnyStr | int] | None,
145
+ dict[AnyStr, AnyStr | int] | None,
146
+ dict[AnyStr, AnyStr | int] | None,
147
+ ]
148
+ ):
149
+ def transform(
150
+ self,
151
+ response: list[AnyStr | int] | None,
152
+ ) -> dict[AnyStr, AnyStr | int] | None:
153
+ return flat_pairs_to_dict(response) if response else None
154
+
155
+ def transform_3(
156
+ self,
157
+ response: dict[AnyStr, AnyStr | int] | None,
158
+ ) -> dict[AnyStr, AnyStr | int] | None:
159
+ return response
coredis/response/types.py CHANGED
@@ -13,9 +13,9 @@ from coredis.typing import (
13
13
  Mapping,
14
14
  NamedTuple,
15
15
  OrderedDict,
16
+ RedisValueT,
16
17
  StringT,
17
18
  TypedDict,
18
- ValueT,
19
19
  )
20
20
 
21
21
  #: Response from `CLIENT INFO <https://redis.io/commands/client-info>`__
@@ -112,8 +112,6 @@ class LibraryDefinition(TypedDict):
112
112
  name: StringT
113
113
  #: the engine used by the library
114
114
  engine: Literal["LUA"]
115
- #: the library's description
116
- description: StringT
117
115
  #: Mapping of function names to functions in the library
118
116
  functions: dict[StringT, FunctionDefinition]
119
117
  #: The library's source code
@@ -371,7 +369,7 @@ class ClusterNodeDetail(TypedDict):
371
369
  pong_recv: int
372
370
  link_state: str
373
371
  slots: list[int]
374
- migrations: list[dict[str, ValueT]]
372
+ migrations: list[dict[str, RedisValueT]]
375
373
 
376
374
 
377
375
  class PubSubMessage(TypedDict):
@@ -405,3 +403,14 @@ class PubSubMessage(TypedDict):
405
403
  #: this will be an :class:`int` corresponding to the number of channels and patterns that the
406
404
  #: connection is currently subscribed to.
407
405
  data: int | StringT
406
+
407
+
408
+ class VectorData(TypedDict):
409
+ #: The quantization type as a string (``fp32``, ``bin`` or ``q8``)
410
+ quantization: str
411
+ #: Raw bytes representation of the vector
412
+ blob: bytes
413
+ #: The L2 norm of the vector before normalization
414
+ l2_norm: float
415
+ #: If the vector is quantized as q8, the quantization range
416
+ quantization_range: float
coredis/retry.py CHANGED
@@ -6,7 +6,7 @@ from abc import ABC, abstractmethod
6
6
  from functools import wraps
7
7
  from typing import Any
8
8
 
9
- from coredis.typing import Callable, Coroutine, P, R
9
+ from coredis.typing import Awaitable, Callable, P, R
10
10
 
11
11
  logger = logging.getLogger(__name__)
12
12
 
@@ -31,10 +31,10 @@ class RetryPolicy(ABC):
31
31
 
32
32
  async def call_with_retries(
33
33
  self,
34
- func: Callable[..., Coroutine[Any, Any, R]],
35
- before_hook: Callable[..., Coroutine[Any, Any, Any]] | None = None,
36
- failure_hook: Callable[..., Coroutine[Any, Any, None]]
37
- | dict[type[BaseException], Callable[..., Coroutine[Any, Any, None]]]
34
+ func: Callable[..., Awaitable[R]],
35
+ before_hook: Callable[..., Awaitable[Any]] | None = None,
36
+ failure_hook: Callable[..., Awaitable[Any]]
37
+ | dict[type[BaseException], Callable[..., Awaitable[None]]]
38
38
  | None = None,
39
39
  ) -> R:
40
40
  """
@@ -159,12 +159,11 @@ class CompositeRetryPolicy(RetryPolicy):
159
159
 
160
160
  async def call_with_retries(
161
161
  self,
162
- func: Callable[..., Coroutine[Any, Any, R]],
163
- before_hook: Callable[..., Coroutine[Any, Any, Any]] | None = None,
162
+ func: Callable[..., Awaitable[R]],
163
+ before_hook: Callable[..., Awaitable[Any]] | None = None,
164
164
  failure_hook: None
165
165
  | (
166
- Callable[..., Coroutine[Any, Any, None]]
167
- | dict[type[BaseException], Callable[..., Coroutine[Any, Any, None]]]
166
+ Callable[..., Awaitable[Any]] | dict[type[BaseException], Callable[..., Awaitable[Any]]]
168
167
  ) = None,
169
168
  ) -> R:
170
169
  """
@@ -214,15 +213,15 @@ class CompositeRetryPolicy(RetryPolicy):
214
213
 
215
214
  def retryable(
216
215
  policy: RetryPolicy,
217
- failure_hook: Callable[..., Coroutine[Any, Any, None]] | None = None,
218
- ) -> Callable[[Callable[P, Coroutine[Any, Any, R]]], Callable[P, Coroutine[Any, Any, R]]]:
216
+ failure_hook: Callable[..., Awaitable[Any]] | None = None,
217
+ ) -> Callable[[Callable[P, Awaitable[R]]], Callable[P, Awaitable[R]]]:
219
218
  """
220
219
  Decorator to be used to apply a retry policy to a coroutine
221
220
  """
222
221
 
223
222
  def inner(
224
- func: Callable[P, Coroutine[Any, Any, R]],
225
- ) -> Callable[P, Coroutine[Any, Any, R]]:
223
+ func: Callable[P, Awaitable[R]],
224
+ ) -> Callable[P, Awaitable[R]]:
226
225
  @wraps(func)
227
226
  async def _inner(*args: P.args, **kwargs: P.kwargs) -> R:
228
227
  return await policy.call_with_retries(
coredis/sentinel.py CHANGED
@@ -24,6 +24,7 @@ from coredis.typing import (
24
24
  Iterable,
25
25
  Literal,
26
26
  StringT,
27
+ TypeAdapter,
27
28
  )
28
29
 
29
30
 
@@ -46,7 +47,7 @@ class SentinelManagedConnection(Connection, Generic[AnyStr]):
46
47
  socket_keepalive_options: dict[int, int | bytes] | None = None,
47
48
  *,
48
49
  client_name: str | None = None,
49
- protocol_version: Literal[2, 3] = 2,
50
+ protocol_version: Literal[2, 3] = 3,
50
51
  ):
51
52
  self.connection_pool: SentinelConnectionPool = weakref.proxy(connection_pool)
52
53
  super().__init__(
@@ -195,6 +196,7 @@ class Sentinel(Generic[AnyStr]):
195
196
  sentinel_kwargs: dict[str, Any] | None = ...,
196
197
  decode_responses: Literal[False] = ...,
197
198
  cache: AbstractCache | None = None,
199
+ type_adapter: TypeAdapter | None = ...,
198
200
  **connection_kwargs: Any,
199
201
  ) -> None: ...
200
202
 
@@ -206,6 +208,7 @@ class Sentinel(Generic[AnyStr]):
206
208
  sentinel_kwargs: dict[str, Any] | None = ...,
207
209
  decode_responses: Literal[True] = ...,
208
210
  cache: AbstractCache | None = None,
211
+ type_adapter: TypeAdapter | None = None,
209
212
  **connection_kwargs: Any,
210
213
  ) -> None: ...
211
214
 
@@ -216,6 +219,7 @@ class Sentinel(Generic[AnyStr]):
216
219
  sentinel_kwargs: dict[str, Any] | None = None,
217
220
  decode_responses: bool = False,
218
221
  cache: AbstractCache | None = None,
222
+ type_adapter: TypeAdapter | None = None,
219
223
  **connection_kwargs: Any,
220
224
  ) -> None:
221
225
  """
@@ -236,6 +240,9 @@ class Sentinel(Generic[AnyStr]):
236
240
  and ``protocol_version`` options specified in :paramref:`connection_kwargs` will be used.
237
241
  :param cache: If provided the cache will be shared between both primaries and replicas
238
242
  returned by this sentinel.
243
+ :param type_adapter: The adapter to use for serializing / deserializing customs types
244
+ when interacting with redis commands. If provided this adapter will be used for both
245
+ primaries and replicas returned by this sentinel.
239
246
  :param connection_kwargs: are keyword arguments that will be used when
240
247
  establishing a connection to a Redis server (i.e. are passed on to the
241
248
  constructor of :class:`Redis` for all primary and replicas).
@@ -260,6 +267,7 @@ class Sentinel(Generic[AnyStr]):
260
267
  self.min_other_sentinels = min_other_sentinels
261
268
  self.connection_kwargs = connection_kwargs
262
269
  self.__cache = cache
270
+ self.__type_adapter = type_adapter
263
271
  self.connection_kwargs["decode_responses"] = self.sentinel_kwargs["decode_responses"] = (
264
272
  decode_responses
265
273
  )
@@ -406,6 +414,7 @@ class Sentinel(Generic[AnyStr]):
406
414
  **connection_kwargs,
407
415
  ),
408
416
  cache=self.__cache,
417
+ type_adapter=self.__type_adapter,
409
418
  )
410
419
 
411
420
  @overload
@@ -461,4 +470,5 @@ class Sentinel(Generic[AnyStr]):
461
470
  **connection_kwargs,
462
471
  ),
463
472
  cache=self.__cache,
473
+ type_adapter=self.__type_adapter,
464
474
  )
coredis/stream.py CHANGED
@@ -19,6 +19,7 @@ from coredis.typing import (
19
19
  Generator,
20
20
  Generic,
21
21
  KeyT,
22
+ MutableMapping,
22
23
  Parameters,
23
24
  StringT,
24
25
  TypedDict,
@@ -38,7 +39,7 @@ class State(TypedDict, total=False):
38
39
 
39
40
 
40
41
  class Consumer(Generic[AnyStr]):
41
- state: dict[KeyT, State]
42
+ state: MutableMapping[KeyT, State]
42
43
  DEFAULT_START_ID: ClassVar[bytes] = b"0-0"
43
44
 
44
45
  def __init__(
@@ -71,10 +72,10 @@ class Consumer(Generic[AnyStr]):
71
72
  """
72
73
  self.client: Client[AnyStr] = client
73
74
  self.streams: set[KeyT] = set(streams)
74
- self.state: dict[StringT, State] = EncodingInsensitiveDict(
75
+ self.state: MutableMapping[StringT, State] = EncodingInsensitiveDict(
75
76
  {stream: stream_parameters.get(nativestr(stream), {}) for stream in streams}
76
77
  )
77
- self.buffer: dict[AnyStr, list[StreamEntry]] = EncodingInsensitiveDict({})
78
+ self.buffer: MutableMapping[AnyStr, list[StreamEntry]] = EncodingInsensitiveDict({})
78
79
  self.buffer_size = buffer_size
79
80
  self.timeout = timeout
80
81
  self._initialized = False