coredis 5.0.0rc2__tar.gz → 5.0.1__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.

Files changed (113) hide show
  1. {coredis-5.0.0rc2 → coredis-5.0.1}/HISTORY.rst +35 -7
  2. {coredis-5.0.0rc2/coredis.egg-info → coredis-5.0.1}/PKG-INFO +1 -2
  3. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/_protocols.py +0 -23
  4. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/_utils.py +8 -4
  5. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/_version.py +3 -3
  6. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/commands/core.py +50 -8
  7. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/commands/script.py +12 -16
  8. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/commands/sentinel.py +9 -7
  9. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/pipeline.py +5 -6
  10. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/response/_callbacks/sentinel.py +28 -25
  11. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/response/_callbacks/vector_sets.py +44 -11
  12. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/sentinel.py +18 -5
  13. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/tokens.py +5 -0
  14. {coredis-5.0.0rc2 → coredis-5.0.1/coredis.egg-info}/PKG-INFO +1 -2
  15. {coredis-5.0.0rc2 → coredis-5.0.1}/pyproject.toml +1 -1
  16. {coredis-5.0.0rc2 → coredis-5.0.1}/requirements/dev.txt +1 -1
  17. {coredis-5.0.0rc2 → coredis-5.0.1}/setup.py +0 -1
  18. {coredis-5.0.0rc2 → coredis-5.0.1}/LICENSE +0 -0
  19. {coredis-5.0.0rc2 → coredis-5.0.1}/MANIFEST.in +0 -0
  20. {coredis-5.0.0rc2 → coredis-5.0.1}/README.md +0 -0
  21. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/__init__.py +0 -0
  22. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/_json.py +0 -0
  23. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/_packer.py +0 -0
  24. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/_py_311_typing.py +0 -0
  25. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/_py_312_typing.py +0 -0
  26. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/_sidecar.py +0 -0
  27. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/cache.py +0 -0
  28. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/client/__init__.py +0 -0
  29. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/client/basic.py +0 -0
  30. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/client/cluster.py +0 -0
  31. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/commands/__init__.py +0 -0
  32. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/commands/_key_spec.py +0 -0
  33. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/commands/_utils.py +0 -0
  34. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/commands/_validators.py +0 -0
  35. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/commands/_wrappers.py +0 -0
  36. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/commands/bitfield.py +0 -0
  37. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/commands/constants.py +0 -0
  38. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/commands/function.py +0 -0
  39. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/commands/monitor.py +0 -0
  40. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/commands/pubsub.py +0 -0
  41. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/commands/request.py +0 -0
  42. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/config.py +0 -0
  43. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/connection.py +0 -0
  44. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/constants.py +0 -0
  45. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/credentials.py +0 -0
  46. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/exceptions.py +0 -0
  47. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/experimental/__init__.py +0 -0
  48. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/globals.py +0 -0
  49. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/modules/__init__.py +0 -0
  50. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/modules/autocomplete.py +0 -0
  51. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/modules/base.py +0 -0
  52. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/modules/filters.py +0 -0
  53. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/modules/graph.py +0 -0
  54. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/modules/json.py +0 -0
  55. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/modules/response/__init__.py +0 -0
  56. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/modules/response/_callbacks/__init__.py +0 -0
  57. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/modules/response/_callbacks/autocomplete.py +0 -0
  58. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/modules/response/_callbacks/graph.py +0 -0
  59. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/modules/response/_callbacks/json.py +0 -0
  60. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/modules/response/_callbacks/search.py +0 -0
  61. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/modules/response/_callbacks/timeseries.py +0 -0
  62. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/modules/response/types.py +0 -0
  63. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/modules/search.py +0 -0
  64. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/modules/timeseries.py +0 -0
  65. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/parser.py +0 -0
  66. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/pool/__init__.py +0 -0
  67. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/pool/basic.py +0 -0
  68. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/pool/cluster.py +0 -0
  69. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/pool/nodemanager.py +0 -0
  70. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/py.typed +0 -0
  71. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/recipes/__init__.py +0 -0
  72. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/recipes/credentials/__init__.py +0 -0
  73. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/recipes/credentials/iam_provider.py +0 -0
  74. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/recipes/locks/__init__.py +0 -0
  75. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/recipes/locks/extend.lua +0 -0
  76. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/recipes/locks/lua_lock.py +0 -0
  77. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/recipes/locks/release.lua +0 -0
  78. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/response/__init__.py +0 -0
  79. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/response/_callbacks/__init__.py +0 -0
  80. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/response/_callbacks/acl.py +0 -0
  81. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/response/_callbacks/cluster.py +0 -0
  82. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/response/_callbacks/command.py +0 -0
  83. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/response/_callbacks/connection.py +0 -0
  84. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/response/_callbacks/geo.py +0 -0
  85. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/response/_callbacks/hash.py +0 -0
  86. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/response/_callbacks/keys.py +0 -0
  87. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/response/_callbacks/module.py +0 -0
  88. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/response/_callbacks/script.py +0 -0
  89. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/response/_callbacks/server.py +0 -0
  90. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/response/_callbacks/sets.py +0 -0
  91. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/response/_callbacks/sorted_set.py +0 -0
  92. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/response/_callbacks/streams.py +0 -0
  93. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/response/_callbacks/strings.py +0 -0
  94. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/response/_utils.py +0 -0
  95. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/response/types.py +0 -0
  96. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/retry.py +0 -0
  97. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/speedups.c +0 -0
  98. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/speedups.pyi +0 -0
  99. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/stream.py +0 -0
  100. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis/typing.py +0 -0
  101. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis.egg-info/SOURCES.txt +0 -0
  102. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis.egg-info/dependency_links.txt +0 -0
  103. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis.egg-info/requires.txt +0 -0
  104. {coredis-5.0.0rc2 → coredis-5.0.1}/coredis.egg-info/top_level.txt +0 -0
  105. {coredis-5.0.0rc2 → coredis-5.0.1}/requirements/ci.txt +0 -0
  106. {coredis-5.0.0rc2 → coredis-5.0.1}/requirements/dev_extra.txt +0 -0
  107. {coredis-5.0.0rc2 → coredis-5.0.1}/requirements/docs.txt +0 -0
  108. {coredis-5.0.0rc2 → coredis-5.0.1}/requirements/main.txt +0 -0
  109. {coredis-5.0.0rc2 → coredis-5.0.1}/requirements/publishing.txt +0 -0
  110. {coredis-5.0.0rc2 → coredis-5.0.1}/requirements/recipes.txt +0 -0
  111. {coredis-5.0.0rc2 → coredis-5.0.1}/requirements/test.txt +0 -0
  112. {coredis-5.0.0rc2 → coredis-5.0.1}/setup.cfg +0 -0
  113. {coredis-5.0.0rc2 → coredis-5.0.1}/versioneer.py +0 -0
@@ -3,6 +3,41 @@
3
3
  Changelog
4
4
  =========
5
5
 
6
+ v5.0.1
7
+ ------
8
+ Release Date: 2025-07-18
9
+
10
+ * Bug Fix
11
+
12
+ * Fix regression caused by ``5.0.0`` which completely broke the use of Sentinel
13
+ with ``decode_responses=False``.
14
+
15
+ v5.0.0
16
+ ------
17
+ Release Date: 2025-07-16
18
+
19
+ * Features
20
+
21
+ * Add support for using custom types with redis commands
22
+ by registering serializers and deserializers
23
+ * Allow stacking pipeline commands synchronously
24
+ * Expose statically typed responses for pipeline commands
25
+
26
+
27
+ * Compatibility
28
+
29
+ * Redis command methods are no longer coroutines and instead
30
+ synchronous methods that return subclasses of ``Awaitable``
31
+ (``CommandRequest``) which can be awaited as before.
32
+ * Add support for redis 8.0 vector set commands
33
+ * Add support for redis 8.0 hash expiry commands
34
+ * Remove deprecated pubsub ``listen`` and threaded worker APIs
35
+ * Remove support for KeyDB
36
+
37
+ * Performance
38
+
39
+ * Streamline client side cache shrinking
40
+
6
41
  v5.0.0rc2
7
42
  ---------
8
43
  Release Date: 2025-07-10
@@ -1965,10 +2000,3 @@ v1.0.1
1965
2000
  * fix bug of `PubSub.run_in_thread`
1966
2001
  * add more examples
1967
2002
  * change `Script.register` to `Script.execute`
1968
-
1969
-
1970
-
1971
-
1972
-
1973
-
1974
-
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: coredis
3
- Version: 5.0.0rc2
3
+ Version: 5.0.1
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-07-10T16:37:52-0700",
11
+ "date": "2025-07-18T09:26:51-0700",
12
12
  "dirty": false,
13
13
  "error": null,
14
- "full-revisionid": "500ec3f7c2c644928da3459bf3242872e672728c",
15
- "version": "5.0.0rc2"
14
+ "full-revisionid": "dbec024933c248c144549a88927631eb9294a9a2",
15
+ "version": "5.0.1"
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 defaultvalue, dict_to_flat_list, tuples_to_flat_list
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
- defaultvalue(start, "-"),
5273
- defaultvalue(end, "+"),
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
- defaultvalue(end, "+"),
5302
- defaultvalue(start, "-"),
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[tuple[AnyStr, ...] | dict[AnyStr, float]]:
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: SupportsScript[AnyStr] | None = None,
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: SupportsScript[AnyStr] | None = 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[RedisValueT] | None = None,
81
- client: SupportsScript[AnyStr] | None = None,
79
+ args: Parameters[ValueT] | None = None,
80
+ client: coredis.client.Client[AnyStr] | None = None,
82
81
  readonly: bool | None = None,
83
- ) -> CommandRequest[ResponseType]:
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 cast(
117
- CommandRequest[ResponseType],
118
- retryable(
119
- ConstantRetryPolicy((NoScriptError,), 1, 0),
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[RedisValueT] | None = None,
128
- client: SupportsScript[AnyStr] | None = None,
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
- ResponseType,
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, ResponseType]]]]:
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(self, service_name: StringT) -> CommandRequest[dict[str, int | bool | str]]:
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, int | bool | 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, int | bool | 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, int | bool | 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, int | bool | 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 hasattr(parent, "response"):
172
- return self.callback(await parent.response)
168
+ if (r := await self.parent) == self.client: # type: ignore
169
+ return r # type: ignore
173
170
  else:
174
- return await parent # type: ignore[no-any-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
 
@@ -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
- ) -> dict[str, str | int | bool]:
43
+ ) -> EncodingInsensitiveDict[str, str | int | bool]:
45
44
  it = iter(response)
46
- result: dict[str, str | int | bool] = {}
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: MutableMapping[str, int | str | bool],
58
- ) -> MutableMapping[str, int | str | bool]:
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
- ) -> MutableMapping[str, int | str | bool]:
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, str | int | bool],
84
+ dict[str, ResponsePrimitive],
86
85
  ]
87
86
  ):
88
87
  def transform(
89
88
  self,
90
89
  response: ResponseType,
91
- ) -> dict[str, str | int | bool]:
92
- return dict(parse_sentinel_state(cast(list[ResponsePrimitive], response)))
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, str | int | bool]:
98
- return dict(add_flags(EncodingInsensitiveDict(response)))
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, str | int | bool]],
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, str | int | bool]]:
112
- result: dict[str, dict[str, str | int | bool]] = {}
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, str | int | bool]]:
124
- states: dict[str, dict[str, str | int | bool]] = {}
122
+ ) -> dict[str, dict[str, ResponsePrimitive]]:
123
+ states: dict[str, dict[str, ResponsePrimitive]] = {}
125
124
  for state in response:
126
- proxy = add_flags(EncodingInsensitiveDict(state))
127
- states[nativestr(proxy["name"])] = dict(proxy)
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, str | bool | int], ...],
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, str | bool | int], ...]:
142
- return tuple(dict(parse_sentinel_state([nativestr(i) for i in item])) for item in response)
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, str | bool | int], ...]:
148
- return tuple(dict(add_flags(EncodingInsensitiveDict(state))) for state in response)
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, ResponseType]]],
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, ResponseType]]]:
178
+ ) -> dict[AnyStr, dict[int, dict[str, ResponsePrimitive]]]:
176
179
  return {response[0]: {r[0]: InfoCallback()(r[1]) for r in response[1]}}
@@ -1,36 +1,69 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from coredis._json import json
3
4
  from coredis._utils import nativestr
4
5
  from coredis.response._callbacks import ResponseCallback
5
6
  from coredis.response._utils import flat_pairs_to_dict
6
7
  from coredis.response.types import VectorData
7
- from coredis.typing import AnyStr, ResponsePrimitive, StringT
8
+ from coredis.typing import AnyStr, JsonType, ResponsePrimitive, StringT
8
9
 
9
10
 
10
11
  class VSimCallback(
11
12
  ResponseCallback[
12
13
  list[AnyStr],
13
- list[AnyStr] | dict[AnyStr, float],
14
- tuple[AnyStr, ...] | dict[AnyStr, float],
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]],
15
19
  ],
16
20
  ):
17
21
  def transform(
18
22
  self,
19
23
  response: list[AnyStr],
20
- ) -> tuple[AnyStr, ...] | dict[AnyStr, float]:
21
- if self.options.get("withscores"):
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:
22
32
  it = iter(response)
23
- return dict(list(zip(it, map(float, it))))
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
+ )
24
42
  else:
25
- return tuple(response)
43
+ return self.transform_3(response)
26
44
 
27
45
  def transform_3(
28
46
  self,
29
- response: list[AnyStr] | dict[AnyStr, float],
30
- ) -> tuple[AnyStr, ...] | dict[AnyStr, float]:
31
- if self.options.get("withscores"):
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:
32
59
  assert isinstance(response, dict)
33
- return response
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
34
67
  else:
35
68
  return tuple(response)
36
69
 
@@ -23,7 +23,9 @@ from coredis.typing import (
23
23
  Generic,
24
24
  Iterable,
25
25
  Literal,
26
+ ResponsePrimitive,
26
27
  StringT,
28
+ TypeAdapter,
27
29
  )
28
30
 
29
31
 
@@ -195,6 +197,7 @@ class Sentinel(Generic[AnyStr]):
195
197
  sentinel_kwargs: dict[str, Any] | None = ...,
196
198
  decode_responses: Literal[False] = ...,
197
199
  cache: AbstractCache | None = None,
200
+ type_adapter: TypeAdapter | None = ...,
198
201
  **connection_kwargs: Any,
199
202
  ) -> None: ...
200
203
 
@@ -206,6 +209,7 @@ class Sentinel(Generic[AnyStr]):
206
209
  sentinel_kwargs: dict[str, Any] | None = ...,
207
210
  decode_responses: Literal[True] = ...,
208
211
  cache: AbstractCache | None = None,
212
+ type_adapter: TypeAdapter | None = None,
209
213
  **connection_kwargs: Any,
210
214
  ) -> None: ...
211
215
 
@@ -216,6 +220,7 @@ class Sentinel(Generic[AnyStr]):
216
220
  sentinel_kwargs: dict[str, Any] | None = None,
217
221
  decode_responses: bool = False,
218
222
  cache: AbstractCache | None = None,
223
+ type_adapter: TypeAdapter | None = None,
219
224
  **connection_kwargs: Any,
220
225
  ) -> None:
221
226
  """
@@ -236,6 +241,9 @@ class Sentinel(Generic[AnyStr]):
236
241
  and ``protocol_version`` options specified in :paramref:`connection_kwargs` will be used.
237
242
  :param cache: If provided the cache will be shared between both primaries and replicas
238
243
  returned by this sentinel.
244
+ :param type_adapter: The adapter to use for serializing / deserializing customs types
245
+ when interacting with redis commands. If provided this adapter will be used for both
246
+ primaries and replicas returned by this sentinel.
239
247
  :param connection_kwargs: are keyword arguments that will be used when
240
248
  establishing a connection to a Redis server (i.e. are passed on to the
241
249
  constructor of :class:`Redis` for all primary and replicas).
@@ -260,6 +268,7 @@ class Sentinel(Generic[AnyStr]):
260
268
  self.min_other_sentinels = min_other_sentinels
261
269
  self.connection_kwargs = connection_kwargs
262
270
  self.__cache = cache
271
+ self.__type_adapter = type_adapter
263
272
  self.connection_kwargs["decode_responses"] = self.sentinel_kwargs["decode_responses"] = (
264
273
  decode_responses
265
274
  )
@@ -283,18 +292,18 @@ class Sentinel(Generic[AnyStr]):
283
292
 
284
293
  def __check_primary_state(
285
294
  self,
286
- state: dict[str, int | bool | str],
295
+ state: dict[str, ResponsePrimitive],
287
296
  ) -> bool:
288
297
  if not state["is_master"] or state["is_sdown"] or state["is_odown"]:
289
298
  return False
290
299
 
291
- if int(state["num-other-sentinels"]) < self.min_other_sentinels:
300
+ if int(state["num-other-sentinels"] or 0) < self.min_other_sentinels:
292
301
  return False
293
302
 
294
303
  return True
295
304
 
296
305
  def __filter_replicas(
297
- self, replicas: Iterable[dict[str, str | int | bool]]
306
+ self, replicas: Iterable[dict[str, ResponsePrimitive]]
298
307
  ) -> list[tuple[str, int]]:
299
308
  """Removes replicas that are in an ODOWN or SDOWN state"""
300
309
  replicas_alive: list[tuple[str, int]] = []
@@ -302,7 +311,9 @@ class Sentinel(Generic[AnyStr]):
302
311
  for replica in replicas:
303
312
  if replica["is_odown"] or replica["is_sdown"]:
304
313
  continue
305
- replicas_alive.append((nativestr(replica["ip"]), int(replica["port"])))
314
+ ip, port = replica["ip"], replica["port"]
315
+ assert ip and port
316
+ replicas_alive.append((nativestr(ip), int(port)))
306
317
 
307
318
  return replicas_alive
308
319
 
@@ -329,7 +340,7 @@ class Sentinel(Generic[AnyStr]):
329
340
  self.sentinels[0],
330
341
  )
331
342
 
332
- return nativestr(state["ip"]), int(state["port"])
343
+ return nativestr(state["ip"]), int(state["port"] or -1)
333
344
  raise PrimaryNotFoundError(f"No primary found for {service_name!r}")
334
345
 
335
346
  async def discover_replicas(self, service_name: str) -> list[tuple[str, int]]:
@@ -406,6 +417,7 @@ class Sentinel(Generic[AnyStr]):
406
417
  **connection_kwargs,
407
418
  ),
408
419
  cache=self.__cache,
420
+ type_adapter=self.__type_adapter,
409
421
  )
410
422
 
411
423
  @overload
@@ -461,4 +473,5 @@ class Sentinel(Generic[AnyStr]):
461
473
  **connection_kwargs,
462
474
  ),
463
475
  cache=self.__cache,
476
+ type_adapter=self.__type_adapter,
464
477
  )
@@ -771,6 +771,11 @@ class PureToken(CaseAndEncodingInsensitiveEnum):
771
771
  #: - ``VSIM``
772
772
  TRUTH = b"TRUTH"
773
773
 
774
+ #: Used by:
775
+ #:
776
+ #: - ``VSIM``
777
+ WITHATTRIBS = b"WITHATTRIBS"
778
+
774
779
  #: Used by:
775
780
  #:
776
781
  #: - ``VEMB``
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: coredis
3
- Version: 5.0.0rc2
3
+ Version: 5.0.1
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
@@ -1,7 +1,7 @@
1
1
  [build-system]
2
2
  build-backend = "setuptools.build_meta"
3
3
  requires = [
4
- "mypy==1.16.1",
4
+ "mypy==1.17.0",
5
5
  "packaging>=21,<26",
6
6
  "beartype>=0.20",
7
7
  "pympler>1,<2",
@@ -2,7 +2,7 @@
2
2
  -r publishing.txt
3
3
  -r recipes.txt
4
4
  ruff
5
- mypy==1.16.1; implementation_name!='pypy'
5
+ mypy==1.17.0; implementation_name!='pypy'
6
6
  redis>=4.2.0
7
7
  twine
8
8
  types-deprecated
@@ -147,7 +147,6 @@ setup(
147
147
  classifiers=[
148
148
  "Development Status :: 5 - Production/Stable",
149
149
  "Intended Audience :: Developers",
150
- "License :: OSI Approved :: MIT License",
151
150
  "Operating System :: OS Independent",
152
151
  "Programming Language :: Python",
153
152
  "Programming Language :: Python :: 3.10",
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes