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.
- redis/__init__.py +2 -11
- redis/_parsers/base.py +14 -2
- redis/asyncio/client.py +27 -14
- redis/asyncio/cluster.py +85 -59
- redis/asyncio/connection.py +76 -23
- redis/asyncio/lock.py +26 -5
- redis/asyncio/sentinel.py +11 -1
- redis/asyncio/utils.py +1 -1
- redis/auth/token.py +6 -2
- redis/backoff.py +15 -0
- redis/client.py +23 -14
- redis/cluster.py +112 -48
- redis/commands/cluster.py +1 -11
- redis/commands/core.py +219 -207
- redis/commands/helpers.py +0 -70
- redis/commands/redismodules.py +5 -17
- redis/commands/search/aggregation.py +3 -1
- redis/commands/search/commands.py +41 -14
- redis/commands/search/dialect.py +3 -0
- redis/commands/search/profile_information.py +14 -0
- redis/commands/search/query.py +5 -1
- redis/commands/vectorset/__init__.py +46 -0
- redis/commands/vectorset/commands.py +367 -0
- redis/commands/vectorset/utils.py +94 -0
- redis/connection.py +76 -27
- redis/exceptions.py +4 -1
- redis/lock.py +24 -4
- redis/ocsp.py +2 -1
- redis/sentinel.py +3 -1
- redis/utils.py +114 -1
- {redis-5.3.0b5.dist-info → redis-6.0.0b2.dist-info}/METADATA +57 -23
- {redis-5.3.0b5.dist-info → redis-6.0.0b2.dist-info}/RECORD +35 -39
- {redis-5.3.0b5.dist-info → redis-6.0.0b2.dist-info}/WHEEL +1 -2
- redis/commands/graph/__init__.py +0 -263
- redis/commands/graph/commands.py +0 -313
- redis/commands/graph/edge.py +0 -91
- redis/commands/graph/exceptions.py +0 -3
- redis/commands/graph/execution_plan.py +0 -211
- redis/commands/graph/node.py +0 -88
- redis/commands/graph/path.py +0 -78
- redis/commands/graph/query_result.py +0 -588
- redis-5.3.0b5.dist-info/top_level.txt +0 -1
- /redis/commands/search/{indexDefinition.py → index_definition.py} +0 -0
- {redis-5.3.0b5.dist-info → redis-6.0.0b2.dist-info/licenses}/LICENSE +0 -0
redis/commands/helpers.py
CHANGED
|
@@ -79,29 +79,6 @@ def parse_list_to_dict(response):
|
|
|
79
79
|
return res
|
|
80
80
|
|
|
81
81
|
|
|
82
|
-
def parse_to_dict(response):
|
|
83
|
-
if response is None:
|
|
84
|
-
return {}
|
|
85
|
-
|
|
86
|
-
res = {}
|
|
87
|
-
for det in response:
|
|
88
|
-
if not isinstance(det, list) or not det:
|
|
89
|
-
continue
|
|
90
|
-
if len(det) == 1:
|
|
91
|
-
res[det[0]] = True
|
|
92
|
-
elif isinstance(det[1], list):
|
|
93
|
-
res[det[0]] = parse_list_to_dict(det[1])
|
|
94
|
-
else:
|
|
95
|
-
try: # try to set the attribute. may be provided without value
|
|
96
|
-
try: # try to convert the value to float
|
|
97
|
-
res[det[0]] = float(det[1])
|
|
98
|
-
except (TypeError, ValueError):
|
|
99
|
-
res[det[0]] = det[1]
|
|
100
|
-
except IndexError:
|
|
101
|
-
pass
|
|
102
|
-
return res
|
|
103
|
-
|
|
104
|
-
|
|
105
82
|
def random_string(length=10):
|
|
106
83
|
"""
|
|
107
84
|
Returns a random N character long string.
|
|
@@ -111,26 +88,6 @@ def random_string(length=10):
|
|
|
111
88
|
)
|
|
112
89
|
|
|
113
90
|
|
|
114
|
-
def quote_string(v):
|
|
115
|
-
"""
|
|
116
|
-
RedisGraph strings must be quoted,
|
|
117
|
-
quote_string wraps given v with quotes incase
|
|
118
|
-
v is a string.
|
|
119
|
-
"""
|
|
120
|
-
|
|
121
|
-
if isinstance(v, bytes):
|
|
122
|
-
v = v.decode()
|
|
123
|
-
elif not isinstance(v, str):
|
|
124
|
-
return v
|
|
125
|
-
if len(v) == 0:
|
|
126
|
-
return '""'
|
|
127
|
-
|
|
128
|
-
v = v.replace("\\", "\\\\")
|
|
129
|
-
v = v.replace('"', '\\"')
|
|
130
|
-
|
|
131
|
-
return f'"{v}"'
|
|
132
|
-
|
|
133
|
-
|
|
134
91
|
def decode_dict_keys(obj):
|
|
135
92
|
"""Decode the keys of the given dictionary with utf-8."""
|
|
136
93
|
newobj = copy.copy(obj)
|
|
@@ -141,33 +98,6 @@ def decode_dict_keys(obj):
|
|
|
141
98
|
return newobj
|
|
142
99
|
|
|
143
100
|
|
|
144
|
-
def stringify_param_value(value):
|
|
145
|
-
"""
|
|
146
|
-
Turn a parameter value into a string suitable for the params header of
|
|
147
|
-
a Cypher command.
|
|
148
|
-
You may pass any value that would be accepted by `json.dumps()`.
|
|
149
|
-
|
|
150
|
-
Ways in which output differs from that of `str()`:
|
|
151
|
-
* Strings are quoted.
|
|
152
|
-
* None --> "null".
|
|
153
|
-
* In dictionaries, keys are _not_ quoted.
|
|
154
|
-
|
|
155
|
-
:param value: The parameter value to be turned into a string.
|
|
156
|
-
:return: string
|
|
157
|
-
"""
|
|
158
|
-
|
|
159
|
-
if isinstance(value, str):
|
|
160
|
-
return quote_string(value)
|
|
161
|
-
elif value is None:
|
|
162
|
-
return "null"
|
|
163
|
-
elif isinstance(value, (list, tuple)):
|
|
164
|
-
return f'[{",".join(map(stringify_param_value, value))}]'
|
|
165
|
-
elif isinstance(value, dict):
|
|
166
|
-
return f'{{{",".join(f"{k}:{stringify_param_value(v)}" for k, v in value.items())}}}' # noqa
|
|
167
|
-
else:
|
|
168
|
-
return str(value)
|
|
169
|
-
|
|
170
|
-
|
|
171
101
|
def get_protocol_version(client):
|
|
172
102
|
if isinstance(client, redis.Redis) or isinstance(client, redis.asyncio.Redis):
|
|
173
103
|
return client.connection_pool.connection_kwargs.get("protocol")
|
redis/commands/redismodules.py
CHANGED
|
@@ -72,15 +72,13 @@ class RedisModuleCommands:
|
|
|
72
72
|
tdigest = TDigestBloom(client=self)
|
|
73
73
|
return tdigest
|
|
74
74
|
|
|
75
|
-
def
|
|
76
|
-
"""Access the
|
|
77
|
-
redis graph data.
|
|
78
|
-
"""
|
|
75
|
+
def vset(self):
|
|
76
|
+
"""Access the VectorSet commands namespace."""
|
|
79
77
|
|
|
80
|
-
from .
|
|
78
|
+
from .vectorset import VectorSet
|
|
81
79
|
|
|
82
|
-
|
|
83
|
-
return
|
|
80
|
+
vset = VectorSet(client=self)
|
|
81
|
+
return vset
|
|
84
82
|
|
|
85
83
|
|
|
86
84
|
class AsyncRedisModuleCommands(RedisModuleCommands):
|
|
@@ -91,13 +89,3 @@ class AsyncRedisModuleCommands(RedisModuleCommands):
|
|
|
91
89
|
|
|
92
90
|
s = AsyncSearch(client=self, index_name=index_name)
|
|
93
91
|
return s
|
|
94
|
-
|
|
95
|
-
def graph(self, index_name="idx"):
|
|
96
|
-
"""Access the graph namespace, providing support for
|
|
97
|
-
redis graph data.
|
|
98
|
-
"""
|
|
99
|
-
|
|
100
|
-
from .graph import AsyncGraph
|
|
101
|
-
|
|
102
|
-
g = AsyncGraph(client=self, name=index_name)
|
|
103
|
-
return g
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
from typing import List, Union
|
|
2
2
|
|
|
3
|
+
from redis.commands.search.dialect import DEFAULT_DIALECT
|
|
4
|
+
|
|
3
5
|
FIELDNAME = object()
|
|
4
6
|
|
|
5
7
|
|
|
@@ -110,7 +112,7 @@ class AggregateRequest:
|
|
|
110
112
|
self._with_schema = False
|
|
111
113
|
self._verbatim = False
|
|
112
114
|
self._cursor = []
|
|
113
|
-
self._dialect =
|
|
115
|
+
self._dialect = DEFAULT_DIALECT
|
|
114
116
|
self._add_scores = False
|
|
115
117
|
self._scorer = "TFIDF"
|
|
116
118
|
|
|
@@ -5,12 +5,13 @@ from typing import Dict, List, Optional, Union
|
|
|
5
5
|
from redis.client import NEVER_DECODE, Pipeline
|
|
6
6
|
from redis.utils import deprecated_function
|
|
7
7
|
|
|
8
|
-
from ..helpers import get_protocol_version
|
|
8
|
+
from ..helpers import get_protocol_version
|
|
9
9
|
from ._util import to_string
|
|
10
10
|
from .aggregation import AggregateRequest, AggregateResult, Cursor
|
|
11
11
|
from .document import Document
|
|
12
12
|
from .field import Field
|
|
13
|
-
from .
|
|
13
|
+
from .index_definition import IndexDefinition
|
|
14
|
+
from .profile_information import ProfileInformation
|
|
14
15
|
from .query import Query
|
|
15
16
|
from .result import Result
|
|
16
17
|
from .suggestion import SuggestionParser
|
|
@@ -67,7 +68,7 @@ class SearchCommands:
|
|
|
67
68
|
|
|
68
69
|
def _parse_results(self, cmd, res, **kwargs):
|
|
69
70
|
if get_protocol_version(self.client) in ["3", 3]:
|
|
70
|
-
return res
|
|
71
|
+
return ProfileInformation(res) if cmd == "FT.PROFILE" else res
|
|
71
72
|
else:
|
|
72
73
|
return self._RESP2_MODULE_CALLBACKS[cmd](res, **kwargs)
|
|
73
74
|
|
|
@@ -101,7 +102,7 @@ class SearchCommands:
|
|
|
101
102
|
with_scores=query._with_scores,
|
|
102
103
|
)
|
|
103
104
|
|
|
104
|
-
return result,
|
|
105
|
+
return result, ProfileInformation(res[1])
|
|
105
106
|
|
|
106
107
|
def _parse_spellcheck(self, res, **kwargs):
|
|
107
108
|
corrections = {}
|
|
@@ -254,8 +255,18 @@ class SearchCommands:
|
|
|
254
255
|
|
|
255
256
|
For more information see `FT.DROPINDEX <https://redis.io/commands/ft.dropindex>`_.
|
|
256
257
|
""" # noqa
|
|
257
|
-
|
|
258
|
-
|
|
258
|
+
args = [DROPINDEX_CMD, self.index_name]
|
|
259
|
+
|
|
260
|
+
delete_str = (
|
|
261
|
+
"DD"
|
|
262
|
+
if isinstance(delete_documents, bool) and delete_documents is True
|
|
263
|
+
else ""
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
if delete_str:
|
|
267
|
+
args.append(delete_str)
|
|
268
|
+
|
|
269
|
+
return self.execute_command(*args)
|
|
259
270
|
|
|
260
271
|
def _add_document(
|
|
261
272
|
self,
|
|
@@ -499,7 +510,7 @@ class SearchCommands:
|
|
|
499
510
|
For more information see `FT.SEARCH <https://redis.io/commands/ft.search>`_.
|
|
500
511
|
""" # noqa
|
|
501
512
|
args, query = self._mk_query_args(query, query_params=query_params)
|
|
502
|
-
st = time.
|
|
513
|
+
st = time.monotonic()
|
|
503
514
|
|
|
504
515
|
options = {}
|
|
505
516
|
if get_protocol_version(self.client) not in ["3", 3]:
|
|
@@ -511,7 +522,7 @@ class SearchCommands:
|
|
|
511
522
|
return res
|
|
512
523
|
|
|
513
524
|
return self._parse_results(
|
|
514
|
-
SEARCH_CMD, res, query=query, duration=(time.
|
|
525
|
+
SEARCH_CMD, res, query=query, duration=(time.monotonic() - st) * 1000.0
|
|
515
526
|
)
|
|
516
527
|
|
|
517
528
|
def explain(
|
|
@@ -585,7 +596,7 @@ class SearchCommands:
|
|
|
585
596
|
|
|
586
597
|
def profile(
|
|
587
598
|
self,
|
|
588
|
-
query: Union[
|
|
599
|
+
query: Union[Query, AggregateRequest],
|
|
589
600
|
limited: bool = False,
|
|
590
601
|
query_params: Optional[Dict[str, Union[str, int, float]]] = None,
|
|
591
602
|
):
|
|
@@ -595,13 +606,13 @@ class SearchCommands:
|
|
|
595
606
|
|
|
596
607
|
### Parameters
|
|
597
608
|
|
|
598
|
-
**query**: This can be either an `AggregateRequest
|
|
609
|
+
**query**: This can be either an `AggregateRequest` or `Query`.
|
|
599
610
|
**limited**: If set to True, removes details of reader iterator.
|
|
600
611
|
**query_params**: Define one or more value parameters.
|
|
601
612
|
Each parameter has a name and a value.
|
|
602
613
|
|
|
603
614
|
"""
|
|
604
|
-
st = time.
|
|
615
|
+
st = time.monotonic()
|
|
605
616
|
cmd = [PROFILE_CMD, self.index_name, ""]
|
|
606
617
|
if limited:
|
|
607
618
|
cmd.append("LIMITED")
|
|
@@ -620,7 +631,7 @@ class SearchCommands:
|
|
|
620
631
|
res = self.execute_command(*cmd)
|
|
621
632
|
|
|
622
633
|
return self._parse_results(
|
|
623
|
-
PROFILE_CMD, res, query=query, duration=(time.
|
|
634
|
+
PROFILE_CMD, res, query=query, duration=(time.monotonic() - st) * 1000.0
|
|
624
635
|
)
|
|
625
636
|
|
|
626
637
|
def spellcheck(self, query, distance=None, include=None, exclude=None):
|
|
@@ -691,6 +702,10 @@ class SearchCommands:
|
|
|
691
702
|
cmd = [DICT_DUMP_CMD, name]
|
|
692
703
|
return self.execute_command(*cmd)
|
|
693
704
|
|
|
705
|
+
@deprecated_function(
|
|
706
|
+
version="8.0.0",
|
|
707
|
+
reason="deprecated since Redis 8.0, call config_set from core module instead",
|
|
708
|
+
)
|
|
694
709
|
def config_set(self, option: str, value: str) -> bool:
|
|
695
710
|
"""Set runtime configuration option.
|
|
696
711
|
|
|
@@ -705,6 +720,10 @@ class SearchCommands:
|
|
|
705
720
|
raw = self.execute_command(*cmd)
|
|
706
721
|
return raw == "OK"
|
|
707
722
|
|
|
723
|
+
@deprecated_function(
|
|
724
|
+
version="8.0.0",
|
|
725
|
+
reason="deprecated since Redis 8.0, call config_get from core module instead",
|
|
726
|
+
)
|
|
708
727
|
def config_get(self, option: str) -> str:
|
|
709
728
|
"""Get runtime configuration option value.
|
|
710
729
|
|
|
@@ -931,7 +950,7 @@ class AsyncSearchCommands(SearchCommands):
|
|
|
931
950
|
For more information see `FT.SEARCH <https://redis.io/commands/ft.search>`_.
|
|
932
951
|
""" # noqa
|
|
933
952
|
args, query = self._mk_query_args(query, query_params=query_params)
|
|
934
|
-
st = time.
|
|
953
|
+
st = time.monotonic()
|
|
935
954
|
|
|
936
955
|
options = {}
|
|
937
956
|
if get_protocol_version(self.client) not in ["3", 3]:
|
|
@@ -943,7 +962,7 @@ class AsyncSearchCommands(SearchCommands):
|
|
|
943
962
|
return res
|
|
944
963
|
|
|
945
964
|
return self._parse_results(
|
|
946
|
-
SEARCH_CMD, res, query=query, duration=(time.
|
|
965
|
+
SEARCH_CMD, res, query=query, duration=(time.monotonic() - st) * 1000.0
|
|
947
966
|
)
|
|
948
967
|
|
|
949
968
|
async def aggregate(
|
|
@@ -1006,6 +1025,10 @@ class AsyncSearchCommands(SearchCommands):
|
|
|
1006
1025
|
|
|
1007
1026
|
return self._parse_results(SPELLCHECK_CMD, res)
|
|
1008
1027
|
|
|
1028
|
+
@deprecated_function(
|
|
1029
|
+
version="8.0.0",
|
|
1030
|
+
reason="deprecated since Redis 8.0, call config_set from core module instead",
|
|
1031
|
+
)
|
|
1009
1032
|
async def config_set(self, option: str, value: str) -> bool:
|
|
1010
1033
|
"""Set runtime configuration option.
|
|
1011
1034
|
|
|
@@ -1020,6 +1043,10 @@ class AsyncSearchCommands(SearchCommands):
|
|
|
1020
1043
|
raw = await self.execute_command(*cmd)
|
|
1021
1044
|
return raw == "OK"
|
|
1022
1045
|
|
|
1046
|
+
@deprecated_function(
|
|
1047
|
+
version="8.0.0",
|
|
1048
|
+
reason="deprecated since Redis 8.0, call config_get from core module instead",
|
|
1049
|
+
)
|
|
1023
1050
|
async def config_get(self, option: str) -> str:
|
|
1024
1051
|
"""Get runtime configuration option value.
|
|
1025
1052
|
|
redis/commands/search/query.py
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
from typing import List, Optional, Union
|
|
2
2
|
|
|
3
|
+
from redis.commands.search.dialect import DEFAULT_DIALECT
|
|
4
|
+
|
|
3
5
|
|
|
4
6
|
class Query:
|
|
5
7
|
"""
|
|
@@ -40,7 +42,7 @@ class Query:
|
|
|
40
42
|
self._highlight_fields: List = []
|
|
41
43
|
self._language: Optional[str] = None
|
|
42
44
|
self._expander: Optional[str] = None
|
|
43
|
-
self._dialect:
|
|
45
|
+
self._dialect: int = DEFAULT_DIALECT
|
|
44
46
|
|
|
45
47
|
def query_string(self) -> str:
|
|
46
48
|
"""Return the query string of this query only."""
|
|
@@ -177,6 +179,8 @@ class Query:
|
|
|
177
179
|
Use a different scoring function to evaluate document relevance.
|
|
178
180
|
Default is `TFIDF`.
|
|
179
181
|
|
|
182
|
+
Since Redis 8.0 default was changed to BM25STD.
|
|
183
|
+
|
|
180
184
|
:param scorer: The scoring function to use
|
|
181
185
|
(e.g. `TFIDF.DOCNORM` or `BM25`)
|
|
182
186
|
"""
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
from redis._parsers.helpers import pairs_to_dict
|
|
4
|
+
from redis.commands.vectorset.utils import (
|
|
5
|
+
parse_vemb_result,
|
|
6
|
+
parse_vlinks_result,
|
|
7
|
+
parse_vsim_result,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
from ..helpers import get_protocol_version
|
|
11
|
+
from .commands import (
|
|
12
|
+
VEMB_CMD,
|
|
13
|
+
VGETATTR_CMD,
|
|
14
|
+
VINFO_CMD,
|
|
15
|
+
VLINKS_CMD,
|
|
16
|
+
VSIM_CMD,
|
|
17
|
+
VectorSetCommands,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class VectorSet(VectorSetCommands):
|
|
22
|
+
def __init__(self, client, **kwargs):
|
|
23
|
+
"""Create a new VectorSet client."""
|
|
24
|
+
# Set the module commands' callbacks
|
|
25
|
+
self._MODULE_CALLBACKS = {
|
|
26
|
+
VEMB_CMD: parse_vemb_result,
|
|
27
|
+
VGETATTR_CMD: lambda r: r and json.loads(r) or None,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
self._RESP2_MODULE_CALLBACKS = {
|
|
31
|
+
VINFO_CMD: lambda r: r and pairs_to_dict(r) or None,
|
|
32
|
+
VSIM_CMD: parse_vsim_result,
|
|
33
|
+
VLINKS_CMD: parse_vlinks_result,
|
|
34
|
+
}
|
|
35
|
+
self._RESP3_MODULE_CALLBACKS = {}
|
|
36
|
+
|
|
37
|
+
self.client = client
|
|
38
|
+
self.execute_command = client.execute_command
|
|
39
|
+
|
|
40
|
+
if get_protocol_version(self.client) in ["3", 3]:
|
|
41
|
+
self._MODULE_CALLBACKS.update(self._RESP3_MODULE_CALLBACKS)
|
|
42
|
+
else:
|
|
43
|
+
self._MODULE_CALLBACKS.update(self._RESP2_MODULE_CALLBACKS)
|
|
44
|
+
|
|
45
|
+
for k, v in self._MODULE_CALLBACKS.items():
|
|
46
|
+
self.client.set_response_callback(k, v)
|