redis 5.3.0b5__py3-none-any.whl → 6.0.0b2__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.
Files changed (44) hide show
  1. redis/__init__.py +2 -11
  2. redis/_parsers/base.py +14 -2
  3. redis/asyncio/client.py +27 -14
  4. redis/asyncio/cluster.py +85 -59
  5. redis/asyncio/connection.py +76 -23
  6. redis/asyncio/lock.py +26 -5
  7. redis/asyncio/sentinel.py +11 -1
  8. redis/asyncio/utils.py +1 -1
  9. redis/auth/token.py +6 -2
  10. redis/backoff.py +15 -0
  11. redis/client.py +23 -14
  12. redis/cluster.py +112 -48
  13. redis/commands/cluster.py +1 -11
  14. redis/commands/core.py +219 -207
  15. redis/commands/helpers.py +0 -70
  16. redis/commands/redismodules.py +5 -17
  17. redis/commands/search/aggregation.py +3 -1
  18. redis/commands/search/commands.py +41 -14
  19. redis/commands/search/dialect.py +3 -0
  20. redis/commands/search/profile_information.py +14 -0
  21. redis/commands/search/query.py +5 -1
  22. redis/commands/vectorset/__init__.py +46 -0
  23. redis/commands/vectorset/commands.py +367 -0
  24. redis/commands/vectorset/utils.py +94 -0
  25. redis/connection.py +76 -27
  26. redis/exceptions.py +4 -1
  27. redis/lock.py +24 -4
  28. redis/ocsp.py +2 -1
  29. redis/sentinel.py +3 -1
  30. redis/utils.py +114 -1
  31. {redis-5.3.0b5.dist-info → redis-6.0.0b2.dist-info}/METADATA +57 -23
  32. {redis-5.3.0b5.dist-info → redis-6.0.0b2.dist-info}/RECORD +35 -39
  33. {redis-5.3.0b5.dist-info → redis-6.0.0b2.dist-info}/WHEEL +1 -2
  34. redis/commands/graph/__init__.py +0 -263
  35. redis/commands/graph/commands.py +0 -313
  36. redis/commands/graph/edge.py +0 -91
  37. redis/commands/graph/exceptions.py +0 -3
  38. redis/commands/graph/execution_plan.py +0 -211
  39. redis/commands/graph/node.py +0 -88
  40. redis/commands/graph/path.py +0 -78
  41. redis/commands/graph/query_result.py +0 -588
  42. redis-5.3.0b5.dist-info/top_level.txt +0 -1
  43. /redis/commands/search/{indexDefinition.py → index_definition.py} +0 -0
  44. {redis-5.3.0b5.dist-info → redis-6.0.0b2.dist-info/licenses}/LICENSE +0 -0
@@ -0,0 +1,367 @@
1
+ import json
2
+ from enum import Enum
3
+ from typing import Awaitable, Dict, List, Optional, Union
4
+
5
+ from redis.client import NEVER_DECODE
6
+ from redis.commands.helpers import get_protocol_version
7
+ from redis.exceptions import DataError
8
+ from redis.typing import CommandsProtocol, EncodableT, KeyT, Number
9
+
10
+ VADD_CMD = "VADD"
11
+ VSIM_CMD = "VSIM"
12
+ VREM_CMD = "VREM"
13
+ VDIM_CMD = "VDIM"
14
+ VCARD_CMD = "VCARD"
15
+ VEMB_CMD = "VEMB"
16
+ VLINKS_CMD = "VLINKS"
17
+ VINFO_CMD = "VINFO"
18
+ VSETATTR_CMD = "VSETATTR"
19
+ VGETATTR_CMD = "VGETATTR"
20
+ VRANDMEMBER_CMD = "VRANDMEMBER"
21
+
22
+
23
+ class QuantizationOptions(Enum):
24
+ """Quantization options for the VADD command."""
25
+
26
+ NOQUANT = "NOQUANT"
27
+ BIN = "BIN"
28
+ Q8 = "Q8"
29
+
30
+
31
+ class CallbacksOptions(Enum):
32
+ """Options that can be set for the commands callbacks"""
33
+
34
+ RAW = "RAW"
35
+ WITHSCORES = "WITHSCORES"
36
+ ALLOW_DECODING = "ALLOW_DECODING"
37
+ RESP3 = "RESP3"
38
+
39
+
40
+ class VectorSetCommands(CommandsProtocol):
41
+ """Redis VectorSet commands"""
42
+
43
+ def vadd(
44
+ self,
45
+ key: KeyT,
46
+ vector: Union[List[float], bytes],
47
+ element: str,
48
+ reduce_dim: Optional[int] = None,
49
+ cas: Optional[bool] = False,
50
+ quantization: Optional[QuantizationOptions] = None,
51
+ ef: Optional[Number] = None,
52
+ attributes: Optional[Union[dict, str]] = None,
53
+ numlinks: Optional[int] = None,
54
+ ) -> Union[Awaitable[int], int]:
55
+ """
56
+ Add vector ``vector`` for element ``element`` to a vector set ``key``.
57
+
58
+ ``reduce_dim`` sets the dimensions to reduce the vector to.
59
+ If not provided, the vector is not reduced.
60
+
61
+ ``cas`` is a boolean flag that indicates whether to use CAS (check-and-set style)
62
+ when adding the vector. If not provided, CAS is not used.
63
+
64
+ ``quantization`` sets the quantization type to use.
65
+ If not provided, int8 quantization is used.
66
+ The options are:
67
+ - NOQUANT: No quantization
68
+ - BIN: Binary quantization
69
+ - Q8: Signed 8-bit quantization
70
+
71
+ ``ef`` sets the exploration factor to use.
72
+ If not provided, the default exploration factor is used.
73
+
74
+ ``attributes`` is a dictionary or json string that contains the attributes to set for the vector.
75
+ If not provided, no attributes are set.
76
+
77
+ ``numlinks`` sets the number of links to create for the vector.
78
+ If not provided, the default number of links is used.
79
+
80
+ For more information see https://redis.io/commands/vadd
81
+ """
82
+ if not vector or not element:
83
+ raise DataError("Both vector and element must be provided")
84
+
85
+ pieces = []
86
+ if reduce_dim:
87
+ pieces.extend(["REDUCE", reduce_dim])
88
+
89
+ values_pieces = []
90
+ if isinstance(vector, bytes):
91
+ values_pieces.extend(["FP32", vector])
92
+ else:
93
+ values_pieces.extend(["VALUES", len(vector)])
94
+ values_pieces.extend(vector)
95
+ pieces.extend(values_pieces)
96
+
97
+ pieces.append(element)
98
+
99
+ if cas:
100
+ pieces.append("CAS")
101
+
102
+ if quantization:
103
+ pieces.append(quantization.value)
104
+
105
+ if ef:
106
+ pieces.extend(["EF", ef])
107
+
108
+ if attributes:
109
+ if isinstance(attributes, dict):
110
+ # transform attributes to json string
111
+ attributes_json = json.dumps(attributes)
112
+ else:
113
+ attributes_json = attributes
114
+ pieces.extend(["SETATTR", attributes_json])
115
+
116
+ if numlinks:
117
+ pieces.extend(["M", numlinks])
118
+
119
+ return self.execute_command(VADD_CMD, key, *pieces)
120
+
121
+ def vsim(
122
+ self,
123
+ key: KeyT,
124
+ input: Union[List[float], bytes, str],
125
+ with_scores: Optional[bool] = False,
126
+ count: Optional[int] = None,
127
+ ef: Optional[Number] = None,
128
+ filter: Optional[str] = None,
129
+ filter_ef: Optional[str] = None,
130
+ truth: Optional[bool] = False,
131
+ no_thread: Optional[bool] = False,
132
+ ) -> Union[
133
+ Awaitable[Optional[List[Union[List[EncodableT], Dict[EncodableT, Number]]]]],
134
+ Optional[List[Union[List[EncodableT], Dict[EncodableT, Number]]]],
135
+ ]:
136
+ """
137
+ Compare a vector or element ``input`` with the other vectors in a vector set ``key``.
138
+
139
+ ``with_scores`` sets if the results should be returned with the
140
+ similarity scores of the elements in the result.
141
+
142
+ ``count`` sets the number of results to return.
143
+
144
+ ``ef`` sets the exploration factor.
145
+
146
+ ``filter`` sets filter that should be applied for the search.
147
+
148
+ ``filter_ef`` sets the max filtering effort.
149
+
150
+ ``truth`` when enabled forces the command to perform linear scan.
151
+
152
+ ``no_thread`` when enabled forces the command to execute the search
153
+ on the data structure in the main thread.
154
+
155
+ For more information see https://redis.io/commands/vsim
156
+ """
157
+
158
+ if not input:
159
+ raise DataError("'input' should be provided")
160
+
161
+ pieces = []
162
+ options = {}
163
+
164
+ if isinstance(input, bytes):
165
+ pieces.extend(["FP32", input])
166
+ elif isinstance(input, list):
167
+ pieces.extend(["VALUES", len(input)])
168
+ pieces.extend(input)
169
+ else:
170
+ pieces.extend(["ELE", input])
171
+
172
+ if with_scores:
173
+ pieces.append("WITHSCORES")
174
+ options[CallbacksOptions.WITHSCORES.value] = True
175
+
176
+ if count:
177
+ pieces.extend(["COUNT", count])
178
+
179
+ if ef:
180
+ pieces.extend(["EF", ef])
181
+
182
+ if filter:
183
+ pieces.extend(["FILTER", filter])
184
+
185
+ if filter_ef:
186
+ pieces.extend(["FILTER-EF", filter_ef])
187
+
188
+ if truth:
189
+ pieces.append("TRUTH")
190
+
191
+ if no_thread:
192
+ pieces.append("NOTHREAD")
193
+
194
+ return self.execute_command(VSIM_CMD, key, *pieces, **options)
195
+
196
+ def vdim(self, key: KeyT) -> Union[Awaitable[int], int]:
197
+ """
198
+ Get the dimension of a vector set.
199
+
200
+ In the case of vectors that were populated using the `REDUCE`
201
+ option, for random projection, the vector set will report the size of
202
+ the projected (reduced) dimension.
203
+
204
+ Raises `redis.exceptions.ResponseError` if the vector set doesn't exist.
205
+
206
+ For more information see https://redis.io/commands/vdim
207
+ """
208
+ return self.execute_command(VDIM_CMD, key)
209
+
210
+ def vcard(self, key: KeyT) -> Union[Awaitable[int], int]:
211
+ """
212
+ Get the cardinality(the number of elements) of a vector set with key ``key``.
213
+
214
+ Raises `redis.exceptions.ResponseError` if the vector set doesn't exist.
215
+
216
+ For more information see https://redis.io/commands/vcard
217
+ """
218
+ return self.execute_command(VCARD_CMD, key)
219
+
220
+ def vrem(self, key: KeyT, element: str) -> Union[Awaitable[int], int]:
221
+ """
222
+ Remove an element from a vector set.
223
+
224
+ For more information see https://redis.io/commands/vrem
225
+ """
226
+ return self.execute_command(VREM_CMD, key, element)
227
+
228
+ def vemb(
229
+ self, key: KeyT, element: str, raw: Optional[bool] = False
230
+ ) -> Union[
231
+ Awaitable[Optional[Union[List[EncodableT], Dict[str, EncodableT]]]],
232
+ Optional[Union[List[EncodableT], Dict[str, EncodableT]]],
233
+ ]:
234
+ """
235
+ Get the approximated vector of an element ``element`` from vector set ``key``.
236
+
237
+ ``raw`` is a boolean flag that indicates whether to return the
238
+ interal representation used by the vector.
239
+
240
+
241
+ For more information see https://redis.io/commands/vembed
242
+ """
243
+ options = {}
244
+ pieces = []
245
+ pieces.extend([key, element])
246
+
247
+ if get_protocol_version(self.client) in ["3", 3]:
248
+ options[CallbacksOptions.RESP3.value] = True
249
+
250
+ if raw:
251
+ pieces.append("RAW")
252
+
253
+ options[NEVER_DECODE] = True
254
+ if (
255
+ hasattr(self.client, "connection_pool")
256
+ and self.client.connection_pool.connection_kwargs["decode_responses"]
257
+ ) or (
258
+ hasattr(self.client, "nodes_manager")
259
+ and self.client.nodes_manager.connection_kwargs["decode_responses"]
260
+ ):
261
+ # allow decoding in the postprocessing callback
262
+ # if the user set decode_responses=True
263
+ # in the connection pool
264
+ options[CallbacksOptions.ALLOW_DECODING.value] = True
265
+
266
+ options[CallbacksOptions.RAW.value] = True
267
+
268
+ return self.execute_command(VEMB_CMD, *pieces, **options)
269
+
270
+ def vlinks(
271
+ self, key: KeyT, element: str, with_scores: Optional[bool] = False
272
+ ) -> Union[
273
+ Awaitable[
274
+ Optional[
275
+ List[Union[List[Union[str, bytes]], Dict[Union[str, bytes], Number]]]
276
+ ]
277
+ ],
278
+ Optional[List[Union[List[Union[str, bytes]], Dict[Union[str, bytes], Number]]]],
279
+ ]:
280
+ """
281
+ Returns the neighbors for each level the element ``element`` exists in the vector set ``key``.
282
+
283
+ The result is a list of lists, where each list contains the neighbors for one level.
284
+ If the element does not exist, or if the vector set does not exist, None is returned.
285
+
286
+ If the ``WITHSCORES`` option is provided, the result is a list of dicts,
287
+ where each dict contains the neighbors for one level, with the scores as values.
288
+
289
+ For more information see https://redis.io/commands/vlinks
290
+ """
291
+ options = {}
292
+ pieces = []
293
+ pieces.extend([key, element])
294
+
295
+ if with_scores:
296
+ pieces.append("WITHSCORES")
297
+ options[CallbacksOptions.WITHSCORES.value] = True
298
+
299
+ return self.execute_command(VLINKS_CMD, *pieces, **options)
300
+
301
+ def vinfo(self, key: KeyT) -> Union[Awaitable[dict], dict]:
302
+ """
303
+ Get information about a vector set.
304
+
305
+ For more information see https://redis.io/commands/vinfo
306
+ """
307
+ return self.execute_command(VINFO_CMD, key)
308
+
309
+ def vsetattr(
310
+ self, key: KeyT, element: str, attributes: Optional[Union[dict, str]] = None
311
+ ) -> Union[Awaitable[int], int]:
312
+ """
313
+ Associate or remove JSON attributes ``attributes`` of element ``element``
314
+ for vector set ``key``.
315
+
316
+ For more information see https://redis.io/commands/vsetattr
317
+ """
318
+ if attributes is None:
319
+ attributes_json = "{}"
320
+ elif isinstance(attributes, dict):
321
+ # transform attributes to json string
322
+ attributes_json = json.dumps(attributes)
323
+ else:
324
+ attributes_json = attributes
325
+
326
+ return self.execute_command(VSETATTR_CMD, key, element, attributes_json)
327
+
328
+ def vgetattr(
329
+ self, key: KeyT, element: str
330
+ ) -> Union[Optional[Awaitable[dict]], Optional[dict]]:
331
+ """
332
+ Retrieve the JSON attributes of an element ``elemet`` for vector set ``key``.
333
+
334
+ If the element does not exist, or if the vector set does not exist, None is
335
+ returned.
336
+
337
+ For more information see https://redis.io/commands/vgetattr
338
+ """
339
+ return self.execute_command(VGETATTR_CMD, key, element)
340
+
341
+ def vrandmember(
342
+ self, key: KeyT, count: Optional[int] = None
343
+ ) -> Union[
344
+ Awaitable[Optional[Union[List[str], str]]], Optional[Union[List[str], str]]
345
+ ]:
346
+ """
347
+ Returns random elements from a vector set ``key``.
348
+
349
+ ``count`` is the number of elements to return.
350
+ If ``count`` is not provided, a single element is returned as a single string.
351
+ If ``count`` is positive(smaller than the number of elements
352
+ in the vector set), the command returns a list with up to ``count``
353
+ distinct elements from the vector set
354
+ If ``count`` is negative, the command returns a list with ``count`` random elements,
355
+ potentially with duplicates.
356
+ If ``count`` is greater than the number of elements in the vector set,
357
+ only the entire set is returned as a list.
358
+
359
+ If the vector set does not exist, ``None`` is returned.
360
+
361
+ For more information see https://redis.io/commands/vrandmember
362
+ """
363
+ pieces = []
364
+ pieces.append(key)
365
+ if count is not None:
366
+ pieces.append(count)
367
+ return self.execute_command(VRANDMEMBER_CMD, *pieces)
@@ -0,0 +1,94 @@
1
+ from redis._parsers.helpers import pairs_to_dict
2
+ from redis.commands.vectorset.commands import CallbacksOptions
3
+
4
+
5
+ def parse_vemb_result(response, **options):
6
+ """
7
+ Handle VEMB result since the command can returning different result
8
+ structures depending on input options and on quantization type of the vector set.
9
+
10
+ Parsing VEMB result into:
11
+ - List[Union[bytes, Union[int, float]]]
12
+ - Dict[str, Union[bytes, str, float]]
13
+ """
14
+ if response is None:
15
+ return response
16
+
17
+ if options.get(CallbacksOptions.RAW.value):
18
+ result = {}
19
+ result["quantization"] = (
20
+ response[0].decode("utf-8")
21
+ if options.get(CallbacksOptions.ALLOW_DECODING.value)
22
+ else response[0]
23
+ )
24
+ result["raw"] = response[1]
25
+ result["l2"] = float(response[2])
26
+ if len(response) > 3:
27
+ result["range"] = float(response[3])
28
+ return result
29
+ else:
30
+ if options.get(CallbacksOptions.RESP3.value):
31
+ return response
32
+
33
+ result = []
34
+ for i in range(len(response)):
35
+ try:
36
+ result.append(int(response[i]))
37
+ except ValueError:
38
+ # if the value is not an integer, it should be a float
39
+ result.append(float(response[i]))
40
+
41
+ return result
42
+
43
+
44
+ def parse_vlinks_result(response, **options):
45
+ """
46
+ Handle VLINKS result since the command can be returning different result
47
+ structures depending on input options.
48
+ Parsing VLINKS result into:
49
+ - List[List[str]]
50
+ - List[Dict[str, Number]]
51
+ """
52
+ if response is None:
53
+ return response
54
+
55
+ if options.get(CallbacksOptions.WITHSCORES.value):
56
+ result = []
57
+ # Redis will return a list of list of strings.
58
+ # This list have to be transformed to list of dicts
59
+ for level_item in response:
60
+ level_data_dict = {}
61
+ for key, value in pairs_to_dict(level_item).items():
62
+ value = float(value)
63
+ level_data_dict[key] = value
64
+ result.append(level_data_dict)
65
+ return result
66
+ else:
67
+ # return the list of elements for each level
68
+ # list of lists
69
+ return response
70
+
71
+
72
+ def parse_vsim_result(response, **options):
73
+ """
74
+ Handle VSIM result since the command can be returning different result
75
+ structures depending on input options.
76
+ Parsing VSIM result into:
77
+ - List[List[str]]
78
+ - List[Dict[str, Number]]
79
+ """
80
+ if response is None:
81
+ return response
82
+
83
+ if options.get(CallbacksOptions.WITHSCORES.value):
84
+ # Redis will return a list of list of pairs.
85
+ # This list have to be transformed to dict
86
+ result_dict = {}
87
+ for key, value in pairs_to_dict(response).items():
88
+ value = float(value)
89
+ result_dict[key] = value
90
+ return result_dict
91
+ else:
92
+ # return the list of elements for each level
93
+ # list of lists
94
+ return response