coredis 5.0.0rc2__tar.gz → 5.1.0__tar.gz
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-5.0.0rc2 → coredis-5.1.0}/HISTORY.rst +44 -6
- {coredis-5.0.0rc2/coredis.egg-info → coredis-5.1.0}/PKG-INFO +1 -2
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/_protocols.py +0 -23
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/_utils.py +8 -4
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/_version.py +3 -3
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/commands/core.py +50 -8
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/commands/script.py +12 -16
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/commands/sentinel.py +9 -7
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/pipeline.py +5 -6
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/pool/basic.py +14 -11
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/response/_callbacks/sentinel.py +28 -25
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/response/_callbacks/vector_sets.py +44 -11
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/sentinel.py +18 -5
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/tokens.py +5 -0
- {coredis-5.0.0rc2 → coredis-5.1.0/coredis.egg-info}/PKG-INFO +1 -2
- {coredis-5.0.0rc2 → coredis-5.1.0}/pyproject.toml +1 -1
- {coredis-5.0.0rc2 → coredis-5.1.0}/requirements/dev.txt +1 -1
- {coredis-5.0.0rc2 → coredis-5.1.0}/requirements/docs.txt +3 -3
- {coredis-5.0.0rc2 → coredis-5.1.0}/setup.py +0 -1
- {coredis-5.0.0rc2 → coredis-5.1.0}/LICENSE +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/MANIFEST.in +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/README.md +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/__init__.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/_json.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/_packer.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/_py_311_typing.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/_py_312_typing.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/_sidecar.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/cache.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/client/__init__.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/client/basic.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/client/cluster.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/commands/__init__.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/commands/_key_spec.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/commands/_utils.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/commands/_validators.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/commands/_wrappers.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/commands/bitfield.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/commands/constants.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/commands/function.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/commands/monitor.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/commands/pubsub.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/commands/request.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/config.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/connection.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/constants.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/credentials.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/exceptions.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/experimental/__init__.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/globals.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/modules/__init__.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/modules/autocomplete.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/modules/base.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/modules/filters.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/modules/graph.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/modules/json.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/modules/response/__init__.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/modules/response/_callbacks/__init__.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/modules/response/_callbacks/autocomplete.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/modules/response/_callbacks/graph.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/modules/response/_callbacks/json.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/modules/response/_callbacks/search.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/modules/response/_callbacks/timeseries.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/modules/response/types.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/modules/search.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/modules/timeseries.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/parser.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/pool/__init__.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/pool/cluster.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/pool/nodemanager.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/py.typed +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/recipes/__init__.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/recipes/credentials/__init__.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/recipes/credentials/iam_provider.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/recipes/locks/__init__.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/recipes/locks/extend.lua +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/recipes/locks/lua_lock.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/recipes/locks/release.lua +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/response/__init__.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/response/_callbacks/__init__.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/response/_callbacks/acl.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/response/_callbacks/cluster.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/response/_callbacks/command.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/response/_callbacks/connection.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/response/_callbacks/geo.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/response/_callbacks/hash.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/response/_callbacks/keys.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/response/_callbacks/module.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/response/_callbacks/script.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/response/_callbacks/server.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/response/_callbacks/sets.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/response/_callbacks/sorted_set.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/response/_callbacks/streams.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/response/_callbacks/strings.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/response/_utils.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/response/types.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/retry.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/speedups.c +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/speedups.pyi +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/stream.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis/typing.py +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis.egg-info/SOURCES.txt +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis.egg-info/dependency_links.txt +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis.egg-info/requires.txt +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/coredis.egg-info/top_level.txt +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/requirements/ci.txt +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/requirements/dev_extra.txt +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/requirements/main.txt +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/requirements/publishing.txt +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/requirements/recipes.txt +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/requirements/test.txt +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/setup.cfg +0 -0
- {coredis-5.0.0rc2 → coredis-5.1.0}/versioneer.py +0 -0
|
@@ -3,6 +3,50 @@
|
|
|
3
3
|
Changelog
|
|
4
4
|
=========
|
|
5
5
|
|
|
6
|
+
v5.1.0
|
|
7
|
+
------
|
|
8
|
+
Release Date: 2025-09-10
|
|
9
|
+
|
|
10
|
+
* Bug Fix
|
|
11
|
+
|
|
12
|
+
* Ensure ``ssl_context`` passed in kwargs of ``from_url`` factory
|
|
13
|
+
method is respected.
|
|
14
|
+
|
|
15
|
+
v5.0.1
|
|
16
|
+
------
|
|
17
|
+
Release Date: 2025-07-18
|
|
18
|
+
|
|
19
|
+
* Bug Fix
|
|
20
|
+
|
|
21
|
+
* Fix regression caused by ``5.0.0`` which completely broke the use of Sentinel
|
|
22
|
+
with ``decode_responses=False``.
|
|
23
|
+
|
|
24
|
+
v5.0.0
|
|
25
|
+
------
|
|
26
|
+
Release Date: 2025-07-16
|
|
27
|
+
|
|
28
|
+
* Features
|
|
29
|
+
|
|
30
|
+
* Add support for using custom types with redis commands
|
|
31
|
+
by registering serializers and deserializers
|
|
32
|
+
* Allow stacking pipeline commands synchronously
|
|
33
|
+
* Expose statically typed responses for pipeline commands
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
* Compatibility
|
|
37
|
+
|
|
38
|
+
* Redis command methods are no longer coroutines and instead
|
|
39
|
+
synchronous methods that return subclasses of ``Awaitable``
|
|
40
|
+
(``CommandRequest``) which can be awaited as before.
|
|
41
|
+
* Add support for redis 8.0 vector set commands
|
|
42
|
+
* Add support for redis 8.0 hash expiry commands
|
|
43
|
+
* Remove deprecated pubsub ``listen`` and threaded worker APIs
|
|
44
|
+
* Remove support for KeyDB
|
|
45
|
+
|
|
46
|
+
* Performance
|
|
47
|
+
|
|
48
|
+
* Streamline client side cache shrinking
|
|
49
|
+
|
|
6
50
|
v5.0.0rc2
|
|
7
51
|
---------
|
|
8
52
|
Release Date: 2025-07-10
|
|
@@ -1966,9 +2010,3 @@ v1.0.1
|
|
|
1966
2010
|
* add more examples
|
|
1967
2011
|
* change `Script.register` to `Script.execute`
|
|
1968
2012
|
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: coredis
|
|
3
|
-
Version: 5.0
|
|
3
|
+
Version: 5.1.0
|
|
4
4
|
Summary: Python async client for Redis key-value store
|
|
5
5
|
Home-page: https://github.com/alisaifee/coredis
|
|
6
6
|
Author: Ali-Akber Saifee
|
|
@@ -14,7 +14,6 @@ Project-URL: Documentation, https://coredis.readthedocs.org
|
|
|
14
14
|
Keywords: Redis,key-value store,asyncio
|
|
15
15
|
Classifier: Development Status :: 5 - Production/Stable
|
|
16
16
|
Classifier: Intended Audience :: Developers
|
|
17
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
18
17
|
Classifier: Operating System :: OS Independent
|
|
19
18
|
Classifier: Programming Language :: Python
|
|
20
19
|
Classifier: Programming Language :: Python :: 3.10
|
|
@@ -10,14 +10,10 @@ from coredis.typing import (
|
|
|
10
10
|
Awaitable,
|
|
11
11
|
Callable,
|
|
12
12
|
ExecutionParameters,
|
|
13
|
-
KeyT,
|
|
14
|
-
Parameters,
|
|
15
13
|
Protocol,
|
|
16
14
|
R,
|
|
17
15
|
RedisCommandP,
|
|
18
|
-
RedisValueT,
|
|
19
16
|
ResponseType,
|
|
20
|
-
StringT,
|
|
21
17
|
TypeVar,
|
|
22
18
|
Unpack,
|
|
23
19
|
ValueT,
|
|
@@ -47,25 +43,6 @@ class AbstractExecutor(Protocol):
|
|
|
47
43
|
) -> CommandRequest[R]: ...
|
|
48
44
|
|
|
49
45
|
|
|
50
|
-
@runtime_checkable
|
|
51
|
-
class SupportsScript(Protocol[T_co]): # noqa
|
|
52
|
-
def evalsha(
|
|
53
|
-
self,
|
|
54
|
-
sha1: StringT,
|
|
55
|
-
keys: Parameters[KeyT] | None = ...,
|
|
56
|
-
args: Parameters[RedisValueT] | None = ...,
|
|
57
|
-
) -> CommandRequest[ResponseType]: ...
|
|
58
|
-
|
|
59
|
-
def evalsha_ro(
|
|
60
|
-
self,
|
|
61
|
-
sha1: StringT,
|
|
62
|
-
keys: Parameters[KeyT] | None = ...,
|
|
63
|
-
args: Parameters[RedisValueT] | None = ...,
|
|
64
|
-
) -> CommandRequest[ResponseType]: ...
|
|
65
|
-
|
|
66
|
-
def script_load(self, script: StringT) -> CommandRequest[T_co]: ...
|
|
67
|
-
|
|
68
|
-
|
|
69
46
|
@runtime_checkable
|
|
70
47
|
class ConnectionP(Protocol):
|
|
71
48
|
decode_responses: bool
|
|
@@ -72,6 +72,14 @@ class EncodingInsensitiveDict(UserDict[Any, Any]):
|
|
|
72
72
|
alt = self._alt_key(key)
|
|
73
73
|
return self.data.pop(alt, default)
|
|
74
74
|
|
|
75
|
+
def stringify_keys(self) -> dict[str, Any]:
|
|
76
|
+
d = {}
|
|
77
|
+
for key, value in self.items():
|
|
78
|
+
d[key.decode(self._encoding) if isinstance(key, bytes) else key] = (
|
|
79
|
+
value.stringify_keys() if isinstance(value, EncodingInsensitiveDict) else value
|
|
80
|
+
)
|
|
81
|
+
return d
|
|
82
|
+
|
|
75
83
|
|
|
76
84
|
@enum.unique
|
|
77
85
|
class CaseAndEncodingInsensitiveEnum(bytes, enum.Enum):
|
|
@@ -120,10 +128,6 @@ def b(x: ResponseType, encoding: str | None = None) -> bytes:
|
|
|
120
128
|
return _v.encode(encoding) if encoding else _v.encode()
|
|
121
129
|
|
|
122
130
|
|
|
123
|
-
def defaultvalue(value: U | None, default: T) -> U | T:
|
|
124
|
-
return default if value is None else value
|
|
125
|
-
|
|
126
|
-
|
|
127
131
|
def nativestr(x: ResponseType, encoding: str = "utf-8") -> str:
|
|
128
132
|
if isinstance(x, (str, bytes)):
|
|
129
133
|
return x if isinstance(x, str) else x.decode(encoding, "replace")
|
|
@@ -8,11 +8,11 @@ import json
|
|
|
8
8
|
|
|
9
9
|
version_json = '''
|
|
10
10
|
{
|
|
11
|
-
"date": "2025-
|
|
11
|
+
"date": "2025-09-10T09:08:52-0700",
|
|
12
12
|
"dirty": false,
|
|
13
13
|
"error": null,
|
|
14
|
-
"full-revisionid": "
|
|
15
|
-
"version": "5.0
|
|
14
|
+
"full-revisionid": "e958acd66930fab10e9517ba712e0b914f284a0b",
|
|
15
|
+
"version": "5.1.0"
|
|
16
16
|
}
|
|
17
17
|
''' # END VERSION_JSON
|
|
18
18
|
|
|
@@ -7,7 +7,7 @@ from typing import overload
|
|
|
7
7
|
from deprecated.sphinx import versionadded
|
|
8
8
|
|
|
9
9
|
from coredis._json import json
|
|
10
|
-
from coredis._utils import
|
|
10
|
+
from coredis._utils import dict_to_flat_list, tuples_to_flat_list
|
|
11
11
|
from coredis.commands import CommandMixin
|
|
12
12
|
from coredis.commands._utils import (
|
|
13
13
|
normalized_milliseconds,
|
|
@@ -5269,8 +5269,8 @@ class CoreCommands(CommandMixin[AnyStr]):
|
|
|
5269
5269
|
"""
|
|
5270
5270
|
|
|
5271
5271
|
command_arguments: CommandArgList = [
|
|
5272
|
-
|
|
5273
|
-
|
|
5272
|
+
start if start is not None else "-",
|
|
5273
|
+
end if end is not None else "+",
|
|
5274
5274
|
]
|
|
5275
5275
|
|
|
5276
5276
|
if count is not None:
|
|
@@ -5298,8 +5298,8 @@ class CoreCommands(CommandMixin[AnyStr]):
|
|
|
5298
5298
|
IDs interval, in reverse order (from greater to smaller IDs) compared to XRANGE
|
|
5299
5299
|
"""
|
|
5300
5300
|
command_arguments: CommandArgList = [
|
|
5301
|
-
|
|
5302
|
-
|
|
5301
|
+
end if end is not None else "+",
|
|
5302
|
+
start if start is not None else "-",
|
|
5303
5303
|
]
|
|
5304
5304
|
|
|
5305
5305
|
if count is not None:
|
|
@@ -8110,6 +8110,37 @@ class CoreCommands(CommandMixin[AnyStr]):
|
|
|
8110
8110
|
filter_ef: int | None = ...,
|
|
8111
8111
|
truth: bool | None = ...,
|
|
8112
8112
|
) -> CommandRequest[dict[AnyStr, float]]: ...
|
|
8113
|
+
@overload
|
|
8114
|
+
def vsim(
|
|
8115
|
+
self,
|
|
8116
|
+
key: KeyT,
|
|
8117
|
+
*,
|
|
8118
|
+
element: StringT | None = ...,
|
|
8119
|
+
values: Parameters[float] | bytes | None = ...,
|
|
8120
|
+
withattribs: Literal[True],
|
|
8121
|
+
count: int | None = ...,
|
|
8122
|
+
epsilon: float | None = ...,
|
|
8123
|
+
ef: int | None = ...,
|
|
8124
|
+
filter: StringT | None = ...,
|
|
8125
|
+
filter_ef: int | None = ...,
|
|
8126
|
+
truth: bool | None = ...,
|
|
8127
|
+
) -> CommandRequest[dict[AnyStr, JsonType]]: ...
|
|
8128
|
+
@overload
|
|
8129
|
+
def vsim(
|
|
8130
|
+
self,
|
|
8131
|
+
key: KeyT,
|
|
8132
|
+
*,
|
|
8133
|
+
element: StringT | None = ...,
|
|
8134
|
+
values: Parameters[float] | bytes | None = ...,
|
|
8135
|
+
withscores: Literal[True],
|
|
8136
|
+
withattribs: Literal[True],
|
|
8137
|
+
count: int | None = ...,
|
|
8138
|
+
epsilon: float | None = ...,
|
|
8139
|
+
ef: int | None = ...,
|
|
8140
|
+
filter: StringT | None = ...,
|
|
8141
|
+
filter_ef: int | None = ...,
|
|
8142
|
+
truth: bool | None = ...,
|
|
8143
|
+
) -> CommandRequest[dict[AnyStr, tuple[float, JsonType]]]: ...
|
|
8113
8144
|
|
|
8114
8145
|
@versionadded(version="5.0.0")
|
|
8115
8146
|
@mutually_exclusive_parameters("values", "element", required=True)
|
|
@@ -8117,6 +8148,7 @@ class CoreCommands(CommandMixin[AnyStr]):
|
|
|
8117
8148
|
CommandName.VSIM,
|
|
8118
8149
|
version_introduced="8.0.0",
|
|
8119
8150
|
group=CommandGroup.VECTOR_SET,
|
|
8151
|
+
arguments={"withattribs": {"version_introduced": "8.1.240"}},
|
|
8120
8152
|
)
|
|
8121
8153
|
def vsim(
|
|
8122
8154
|
self,
|
|
@@ -8125,13 +8157,19 @@ class CoreCommands(CommandMixin[AnyStr]):
|
|
|
8125
8157
|
element: StringT | None = None,
|
|
8126
8158
|
values: Parameters[float] | bytes | None = None,
|
|
8127
8159
|
withscores: bool | None = None,
|
|
8160
|
+
withattribs: bool | None = None,
|
|
8128
8161
|
count: int | None = None,
|
|
8129
8162
|
epsilon: float | None = None,
|
|
8130
8163
|
ef: int | None = None,
|
|
8131
8164
|
filter: StringT | None = None,
|
|
8132
8165
|
filter_ef: int | None = None,
|
|
8133
8166
|
truth: bool | None = None,
|
|
8134
|
-
) -> CommandRequest[
|
|
8167
|
+
) -> CommandRequest[
|
|
8168
|
+
tuple[AnyStr, ...]
|
|
8169
|
+
| dict[AnyStr, float]
|
|
8170
|
+
| dict[AnyStr, JsonType]
|
|
8171
|
+
| dict[AnyStr, tuple[float, JsonType]]
|
|
8172
|
+
]:
|
|
8135
8173
|
"""
|
|
8136
8174
|
Return elements similar to a given vector or element
|
|
8137
8175
|
|
|
@@ -8140,6 +8178,7 @@ class CoreCommands(CommandMixin[AnyStr]):
|
|
|
8140
8178
|
:param values: either a byte representation of a 32-bit floating point (FP32) blob of values
|
|
8141
8179
|
or a sequence of doubles representing the vector to use as the similarity reference.
|
|
8142
8180
|
:param withscores: whether to return similarity scores for each result
|
|
8181
|
+
:param withattribs: whether to include attributes for for each result
|
|
8143
8182
|
:param count: number of results to limit to
|
|
8144
8183
|
:param epsilon: distance threshold; results with distance greater than this are
|
|
8145
8184
|
excluded.
|
|
@@ -8148,7 +8187,8 @@ class CoreCommands(CommandMixin[AnyStr]):
|
|
|
8148
8187
|
:param filter_ef: limits the number of filtering attempts
|
|
8149
8188
|
:param truth: forces an exact linear scan of all elements bypassing the HSNW graph
|
|
8150
8189
|
:return: the matching elements or a mapping of the matching elements to their scores
|
|
8151
|
-
if :paramref:`withscores` is ``True``
|
|
8190
|
+
if :paramref:`withscores` is ``True`` and/or their attributes if :paramref:`withattribs`
|
|
8191
|
+
is ``True``
|
|
8152
8192
|
"""
|
|
8153
8193
|
command_arguments: CommandArgList = [key]
|
|
8154
8194
|
if values is not None:
|
|
@@ -8162,6 +8202,8 @@ class CoreCommands(CommandMixin[AnyStr]):
|
|
|
8162
8202
|
|
|
8163
8203
|
if withscores:
|
|
8164
8204
|
command_arguments.append(PureToken.WITHSCORES)
|
|
8205
|
+
if withattribs:
|
|
8206
|
+
command_arguments.append(PureToken.WITHATTRIBS)
|
|
8165
8207
|
if count is not None:
|
|
8166
8208
|
command_arguments.extend([PrefixToken.COUNT, count])
|
|
8167
8209
|
if ef is not None:
|
|
@@ -8177,7 +8219,7 @@ class CoreCommands(CommandMixin[AnyStr]):
|
|
|
8177
8219
|
return self.create_request(
|
|
8178
8220
|
CommandName.VSIM,
|
|
8179
8221
|
*command_arguments,
|
|
8180
|
-
callback=VSimCallback[AnyStr](withscores=withscores),
|
|
8222
|
+
callback=VSimCallback[AnyStr](withscores=withscores, withattribs=withattribs),
|
|
8181
8223
|
)
|
|
8182
8224
|
|
|
8183
8225
|
@versionadded(version="5.0.0")
|
|
@@ -8,9 +8,7 @@ from typing import TYPE_CHECKING, Any, cast
|
|
|
8
8
|
|
|
9
9
|
from deprecated.sphinx import versionadded
|
|
10
10
|
|
|
11
|
-
from coredis._protocols import SupportsScript
|
|
12
11
|
from coredis._utils import b
|
|
13
|
-
from coredis.commands import CommandRequest
|
|
14
12
|
from coredis.exceptions import NoScriptError
|
|
15
13
|
from coredis.retry import ConstantRetryPolicy, retryable
|
|
16
14
|
from coredis.typing import (
|
|
@@ -25,6 +23,7 @@ from coredis.typing import (
|
|
|
25
23
|
RedisValueT,
|
|
26
24
|
ResponseType,
|
|
27
25
|
StringT,
|
|
26
|
+
ValueT,
|
|
28
27
|
add_runtime_checks,
|
|
29
28
|
safe_beartype,
|
|
30
29
|
)
|
|
@@ -53,7 +52,7 @@ class Script(Generic[AnyStr]):
|
|
|
53
52
|
|
|
54
53
|
def __init__(
|
|
55
54
|
self,
|
|
56
|
-
registered_client:
|
|
55
|
+
registered_client: coredis.client.Client[AnyStr] | None = None,
|
|
57
56
|
script: StringT | None = None,
|
|
58
57
|
readonly: bool = False,
|
|
59
58
|
):
|
|
@@ -66,7 +65,7 @@ class Script(Generic[AnyStr]):
|
|
|
66
65
|
:param readonly: If ``True`` the script will be called with
|
|
67
66
|
:meth:`coredis.Redis.evalsha_ro` instead of :meth:`coredis.Redis.evalsha`
|
|
68
67
|
"""
|
|
69
|
-
self.registered_client:
|
|
68
|
+
self.registered_client: coredis.client.Client[AnyStr] | None = registered_client
|
|
70
69
|
self.script: StringT
|
|
71
70
|
if not script:
|
|
72
71
|
raise RuntimeError("No script provided")
|
|
@@ -77,10 +76,10 @@ class Script(Generic[AnyStr]):
|
|
|
77
76
|
def __call__(
|
|
78
77
|
self,
|
|
79
78
|
keys: Parameters[KeyT] | None = None,
|
|
80
|
-
args: Parameters[
|
|
81
|
-
client:
|
|
79
|
+
args: Parameters[ValueT] | None = None,
|
|
80
|
+
client: coredis.client.Client[AnyStr] | None = None,
|
|
82
81
|
readonly: bool | None = None,
|
|
83
|
-
) ->
|
|
82
|
+
) -> Awaitable[ResponseType]:
|
|
84
83
|
"""
|
|
85
84
|
Executes the script registered in :paramref:`Script.script` using
|
|
86
85
|
:meth:`coredis.Redis.evalsha`. Additionally, if the script was not yet
|
|
@@ -113,19 +112,16 @@ class Script(Generic[AnyStr]):
|
|
|
113
112
|
cast(Pipeline[AnyStr], client).scripts.add(self)
|
|
114
113
|
return method(self.sha, keys=keys, args=args)
|
|
115
114
|
else:
|
|
116
|
-
return
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
failure_hook=lambda _: client.script_load(self.script),
|
|
121
|
-
)(method)(self.sha, keys=keys, args=args),
|
|
122
|
-
)
|
|
115
|
+
return retryable(
|
|
116
|
+
ConstantRetryPolicy((NoScriptError,), 1, 0),
|
|
117
|
+
failure_hook=lambda _: client.script_load(self.script),
|
|
118
|
+
)(method)(self.sha, keys=keys, args=args)
|
|
123
119
|
|
|
124
120
|
async def execute(
|
|
125
121
|
self,
|
|
126
122
|
keys: Parameters[KeyT] | None = None,
|
|
127
|
-
args: Parameters[
|
|
128
|
-
client:
|
|
123
|
+
args: Parameters[ValueT] | None = None,
|
|
124
|
+
client: coredis.client.Client[AnyStr] | None = None,
|
|
129
125
|
readonly: bool | None = None,
|
|
130
126
|
) -> ResponseType:
|
|
131
127
|
"""
|
|
@@ -16,7 +16,7 @@ from coredis.response._callbacks.sentinel import (
|
|
|
16
16
|
from coredis.typing import (
|
|
17
17
|
AnyStr,
|
|
18
18
|
RedisValueT,
|
|
19
|
-
|
|
19
|
+
ResponsePrimitive,
|
|
20
20
|
StringT,
|
|
21
21
|
)
|
|
22
22
|
|
|
@@ -105,7 +105,7 @@ class SentinelCommands(CommandMixin[AnyStr]):
|
|
|
105
105
|
@redis_command(CommandName.SENTINEL_INFO_CACHE)
|
|
106
106
|
def sentinel_infocache(
|
|
107
107
|
self, *nodenames: StringT
|
|
108
|
-
) -> CommandRequest[dict[AnyStr, dict[int, dict[str,
|
|
108
|
+
) -> CommandRequest[dict[AnyStr, dict[int, dict[str, ResponsePrimitive]]]]:
|
|
109
109
|
"""
|
|
110
110
|
Return cached INFO output from masters and replicas.
|
|
111
111
|
"""
|
|
@@ -119,7 +119,9 @@ class SentinelCommands(CommandMixin[AnyStr]):
|
|
|
119
119
|
@redis_command(
|
|
120
120
|
CommandName.SENTINEL_MASTER,
|
|
121
121
|
)
|
|
122
|
-
def sentinel_master(
|
|
122
|
+
def sentinel_master(
|
|
123
|
+
self, service_name: StringT
|
|
124
|
+
) -> CommandRequest[dict[str, ResponsePrimitive]]:
|
|
123
125
|
"""Returns a dictionary containing the specified masters state."""
|
|
124
126
|
|
|
125
127
|
return CommandRequest(
|
|
@@ -129,7 +131,7 @@ class SentinelCommands(CommandMixin[AnyStr]):
|
|
|
129
131
|
@redis_command(
|
|
130
132
|
CommandName.SENTINEL_MASTERS,
|
|
131
133
|
)
|
|
132
|
-
def sentinel_masters(self) -> CommandRequest[dict[str, dict[str,
|
|
134
|
+
def sentinel_masters(self) -> CommandRequest[dict[str, dict[str, ResponsePrimitive]]]:
|
|
133
135
|
"""Returns a list of dictionaries containing each master's state."""
|
|
134
136
|
|
|
135
137
|
return CommandRequest(self, CommandName.SENTINEL_MASTERS, callback=PrimariesCallback())
|
|
@@ -173,7 +175,7 @@ class SentinelCommands(CommandMixin[AnyStr]):
|
|
|
173
175
|
)
|
|
174
176
|
def sentinel_sentinels(
|
|
175
177
|
self, service_name: StringT
|
|
176
|
-
) -> CommandRequest[tuple[dict[str,
|
|
178
|
+
) -> CommandRequest[tuple[dict[str, ResponsePrimitive], ...]]:
|
|
177
179
|
"""Returns a list of sentinels for :paramref:`service_name`"""
|
|
178
180
|
|
|
179
181
|
return CommandRequest(
|
|
@@ -205,7 +207,7 @@ class SentinelCommands(CommandMixin[AnyStr]):
|
|
|
205
207
|
)
|
|
206
208
|
def sentinel_slaves(
|
|
207
209
|
self, service_name: StringT
|
|
208
|
-
) -> CommandRequest[tuple[dict[str,
|
|
210
|
+
) -> CommandRequest[tuple[dict[str, ResponsePrimitive], ...]]:
|
|
209
211
|
"""Returns a list of slaves for paramref:`service_name`"""
|
|
210
212
|
|
|
211
213
|
return CommandRequest(
|
|
@@ -217,7 +219,7 @@ class SentinelCommands(CommandMixin[AnyStr]):
|
|
|
217
219
|
)
|
|
218
220
|
def sentinel_replicas(
|
|
219
221
|
self, service_name: StringT
|
|
220
|
-
) -> CommandRequest[tuple[dict[str,
|
|
222
|
+
) -> CommandRequest[tuple[dict[str, ResponsePrimitive], ...]]:
|
|
221
223
|
"""Returns a list of replicas for :paramref:`service_name`"""
|
|
222
224
|
|
|
223
225
|
return CommandRequest(
|
|
@@ -89,8 +89,6 @@ def wrap_pipeline_method(
|
|
|
89
89
|
def wrapper(*args: P.args, **kwargs: P.kwargs) -> Awaitable[R]:
|
|
90
90
|
return func(*args, **kwargs)
|
|
91
91
|
|
|
92
|
-
wrapper.__annotations__ = wrapper.__annotations__.copy()
|
|
93
|
-
wrapper.__annotations__["return"] = kls
|
|
94
92
|
wrapper.__doc__ = textwrap.dedent(wrapper.__doc__ or "")
|
|
95
93
|
wrapper.__doc__ = f"""
|
|
96
94
|
.. note:: Pipeline variant of :meth:`coredis.Redis.{func.__name__}` that does not execute
|
|
@@ -165,13 +163,12 @@ class PipelineCommandRequest(CommandRequest[CommandResponseT]):
|
|
|
165
163
|
if hasattr(self, "response"):
|
|
166
164
|
return self.response.__await__()
|
|
167
165
|
elif self.parent:
|
|
168
|
-
parent = self.parent
|
|
169
166
|
|
|
170
167
|
async def _transformed() -> CommandResponseT:
|
|
171
|
-
if
|
|
172
|
-
return
|
|
168
|
+
if (r := await self.parent) == self.client: # type: ignore
|
|
169
|
+
return r # type: ignore
|
|
173
170
|
else:
|
|
174
|
-
return
|
|
171
|
+
return self.callback(r)
|
|
175
172
|
|
|
176
173
|
return _transformed().__await__()
|
|
177
174
|
else:
|
|
@@ -541,6 +538,8 @@ class Pipeline(Client[AnyStr], metaclass=PipelineMeta):
|
|
|
541
538
|
) -> None:
|
|
542
539
|
"""
|
|
543
540
|
Queue a command for execution on the next `execute()` call.
|
|
541
|
+
|
|
542
|
+
:meta private:
|
|
544
543
|
"""
|
|
545
544
|
self.command_stack.append(command)
|
|
546
545
|
|
|
@@ -155,17 +155,20 @@ class ConnectionPool:
|
|
|
155
155
|
pass
|
|
156
156
|
|
|
157
157
|
if parsed_url.scheme == "rediss":
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
158
|
+
if "ssl_context" not in kwargs:
|
|
159
|
+
keyfile = cast(str | None, url_options.pop("ssl_keyfile", None))
|
|
160
|
+
certfile = cast(str | None, url_options.pop("ssl_certfile", None))
|
|
161
|
+
check_hostname = query_param_to_bool(
|
|
162
|
+
url_options.pop("ssl_check_hostname", None)
|
|
163
|
+
)
|
|
164
|
+
cert_reqs = cast(
|
|
165
|
+
str | VerifyMode | None,
|
|
166
|
+
url_options.pop("ssl_cert_reqs", None),
|
|
167
|
+
)
|
|
168
|
+
ca_certs = cast(str | None, url_options.pop("ssl_ca_certs", None))
|
|
169
|
+
url_options["ssl_context"] = RedisSSLContext(
|
|
170
|
+
keyfile, certfile, cert_reqs, ca_certs, check_hostname
|
|
171
|
+
).get()
|
|
169
172
|
|
|
170
173
|
# last shot at the db value
|
|
171
174
|
_db = url_options.get("db", db or 0)
|
|
@@ -7,7 +7,6 @@ from coredis.response._callbacks import ResponseCallback
|
|
|
7
7
|
from coredis.response._callbacks.server import InfoCallback
|
|
8
8
|
from coredis.typing import (
|
|
9
9
|
AnyStr,
|
|
10
|
-
MutableMapping,
|
|
11
10
|
ResponsePrimitive,
|
|
12
11
|
ResponseType,
|
|
13
12
|
)
|
|
@@ -41,9 +40,9 @@ SENTINEL_STATE_INT_FIELDS = {
|
|
|
41
40
|
|
|
42
41
|
def sentinel_state_typed(
|
|
43
42
|
response: list[str],
|
|
44
|
-
) ->
|
|
43
|
+
) -> EncodingInsensitiveDict[str, str | int | bool]:
|
|
45
44
|
it = iter(response)
|
|
46
|
-
result:
|
|
45
|
+
result: EncodingInsensitiveDict[str, str | int | bool] = EncodingInsensitiveDict()
|
|
47
46
|
|
|
48
47
|
for key, value in zip(it, it):
|
|
49
48
|
if key in SENTINEL_STATE_INT_FIELDS:
|
|
@@ -54,8 +53,8 @@ def sentinel_state_typed(
|
|
|
54
53
|
|
|
55
54
|
|
|
56
55
|
def add_flags(
|
|
57
|
-
result:
|
|
58
|
-
) ->
|
|
56
|
+
result: EncodingInsensitiveDict[str, int | str | bool],
|
|
57
|
+
) -> EncodingInsensitiveDict[str, int | str | bool]:
|
|
59
58
|
flags = set(nativestr(result["flags"]).split(","))
|
|
60
59
|
for name, flag in (
|
|
61
60
|
("is_master", "master"),
|
|
@@ -72,7 +71,7 @@ def add_flags(
|
|
|
72
71
|
|
|
73
72
|
def parse_sentinel_state(
|
|
74
73
|
item: list[ResponsePrimitive],
|
|
75
|
-
) ->
|
|
74
|
+
) -> EncodingInsensitiveDict[str, int | str | bool]:
|
|
76
75
|
result = sentinel_state_typed([nativestr(k) for k in item])
|
|
77
76
|
result = add_flags(result)
|
|
78
77
|
return result
|
|
@@ -82,34 +81,34 @@ class PrimaryCallback(
|
|
|
82
81
|
ResponseCallback[
|
|
83
82
|
ResponseType,
|
|
84
83
|
dict[ResponsePrimitive, ResponsePrimitive],
|
|
85
|
-
dict[str,
|
|
84
|
+
dict[str, ResponsePrimitive],
|
|
86
85
|
]
|
|
87
86
|
):
|
|
88
87
|
def transform(
|
|
89
88
|
self,
|
|
90
89
|
response: ResponseType,
|
|
91
|
-
) -> dict[str,
|
|
92
|
-
return
|
|
90
|
+
) -> dict[str, ResponsePrimitive]:
|
|
91
|
+
return parse_sentinel_state(cast(list[ResponsePrimitive], response)).stringify_keys()
|
|
93
92
|
|
|
94
93
|
def transform_3(
|
|
95
94
|
self,
|
|
96
95
|
response: dict[ResponsePrimitive, ResponsePrimitive],
|
|
97
|
-
) -> dict[str,
|
|
98
|
-
return
|
|
96
|
+
) -> dict[str, ResponsePrimitive]:
|
|
97
|
+
return add_flags(EncodingInsensitiveDict(response)).stringify_keys()
|
|
99
98
|
|
|
100
99
|
|
|
101
100
|
class PrimariesCallback(
|
|
102
101
|
ResponseCallback[
|
|
103
102
|
list[ResponseType],
|
|
104
103
|
list[ResponseType],
|
|
105
|
-
dict[str, dict[str,
|
|
104
|
+
dict[str, dict[str, ResponsePrimitive]],
|
|
106
105
|
]
|
|
107
106
|
):
|
|
108
107
|
def transform(
|
|
109
108
|
self,
|
|
110
109
|
response: list[ResponseType] | dict[ResponsePrimitive, ResponsePrimitive],
|
|
111
|
-
) -> dict[str, dict[str,
|
|
112
|
-
result: dict[str, dict[str,
|
|
110
|
+
) -> dict[str, dict[str, ResponsePrimitive]]:
|
|
111
|
+
result: dict[str, dict[str, ResponseType]] = {}
|
|
113
112
|
|
|
114
113
|
for item in response:
|
|
115
114
|
state = PrimaryCallback()(item)
|
|
@@ -120,11 +119,11 @@ class PrimariesCallback(
|
|
|
120
119
|
def transform_3(
|
|
121
120
|
self,
|
|
122
121
|
response: list[ResponseType],
|
|
123
|
-
) -> dict[str, dict[str,
|
|
124
|
-
states: dict[str, dict[str,
|
|
122
|
+
) -> dict[str, dict[str, ResponsePrimitive]]:
|
|
123
|
+
states: dict[str, dict[str, ResponsePrimitive]] = {}
|
|
125
124
|
for state in response:
|
|
126
|
-
|
|
127
|
-
states[nativestr(
|
|
125
|
+
state = add_flags(EncodingInsensitiveDict(state)).stringify_keys()
|
|
126
|
+
states[nativestr(state["name"])] = state
|
|
128
127
|
return states
|
|
129
128
|
|
|
130
129
|
|
|
@@ -132,20 +131,24 @@ class SentinelsStateCallback(
|
|
|
132
131
|
ResponseCallback[
|
|
133
132
|
list[ResponseType],
|
|
134
133
|
list[ResponseType],
|
|
135
|
-
tuple[dict[str,
|
|
134
|
+
tuple[dict[str, ResponsePrimitive], ...],
|
|
136
135
|
]
|
|
137
136
|
):
|
|
138
137
|
def transform(
|
|
139
138
|
self,
|
|
140
139
|
response: list[ResponseType],
|
|
141
|
-
) -> tuple[dict[str,
|
|
142
|
-
return tuple(
|
|
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
|
+
)
|
|
143
144
|
|
|
144
145
|
def transform_3(
|
|
145
146
|
self,
|
|
146
147
|
response: list[ResponseType],
|
|
147
|
-
) -> tuple[dict[str,
|
|
148
|
-
return tuple(
|
|
148
|
+
) -> tuple[dict[str, ResponsePrimitive], ...]:
|
|
149
|
+
return tuple(
|
|
150
|
+
add_flags(EncodingInsensitiveDict(state)).stringify_keys() for state in response
|
|
151
|
+
)
|
|
149
152
|
|
|
150
153
|
|
|
151
154
|
class GetPrimaryCallback(
|
|
@@ -166,11 +169,11 @@ class SentinelInfoCallback(
|
|
|
166
169
|
ResponseCallback[
|
|
167
170
|
list[ResponseType],
|
|
168
171
|
list[ResponseType],
|
|
169
|
-
dict[AnyStr, dict[int, dict[str,
|
|
172
|
+
dict[AnyStr, dict[int, dict[str, ResponsePrimitive]]],
|
|
170
173
|
]
|
|
171
174
|
):
|
|
172
175
|
def transform(
|
|
173
176
|
self,
|
|
174
177
|
response: list[ResponseType],
|
|
175
|
-
) -> dict[AnyStr, dict[int, dict[str,
|
|
178
|
+
) -> dict[AnyStr, dict[int, dict[str, ResponsePrimitive]]]:
|
|
176
179
|
return {response[0]: {r[0]: InfoCallback()(r[1]) for r in response[1]}}
|