valkey-glide 2.0.0rc7__cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl → 2.2.0__cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.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 (45) hide show
  1. glide/__init__.py +160 -106
  2. glide/async_commands/cluster_commands.py +101 -104
  3. glide/async_commands/core.py +617 -424
  4. glide/async_commands/{server_modules/ft.py → ft.py} +8 -7
  5. glide/async_commands/{server_modules/glide_json.py → glide_json.py} +15 -92
  6. glide/async_commands/standalone_commands.py +19 -57
  7. glide/glide.cpython-312-aarch64-linux-gnu.so +0 -0
  8. glide/glide.pyi +26 -1
  9. glide/glide_client.py +85 -47
  10. glide/logger.py +33 -21
  11. glide/opentelemetry.py +185 -0
  12. glide_shared/__init__.py +330 -0
  13. glide_shared/commands/__init__.py +0 -0
  14. {glide/async_commands → glide_shared/commands}/batch.py +441 -40
  15. glide_shared/commands/batch_options.py +261 -0
  16. glide_shared/commands/core_options.py +407 -0
  17. {glide/async_commands → glide_shared/commands}/server_modules/ft_options/ft_aggregate_options.py +3 -3
  18. {glide/async_commands → glide_shared/commands}/server_modules/ft_options/ft_create_options.py +4 -2
  19. {glide/async_commands → glide_shared/commands}/server_modules/ft_options/ft_profile_options.py +4 -4
  20. {glide/async_commands → glide_shared/commands}/server_modules/ft_options/ft_search_options.py +4 -2
  21. {glide/async_commands → glide_shared/commands}/server_modules/json_batch.py +4 -4
  22. glide_shared/commands/server_modules/json_options.py +93 -0
  23. {glide/async_commands → glide_shared/commands}/sorted_set.py +2 -2
  24. {glide/async_commands → glide_shared/commands}/stream.py +1 -1
  25. {glide → glide_shared}/config.py +386 -61
  26. {glide → glide_shared}/constants.py +3 -3
  27. {glide → glide_shared}/exceptions.py +27 -1
  28. glide_shared/protobuf/command_request_pb2.py +56 -0
  29. glide_shared/protobuf/connection_request_pb2.py +56 -0
  30. {glide → glide_shared}/protobuf/response_pb2.py +6 -6
  31. {glide → glide_shared}/routes.py +29 -15
  32. valkey_glide-2.2.0.dist-info/METADATA +210 -0
  33. valkey_glide-2.2.0.dist-info/RECORD +40 -0
  34. glide/protobuf/command_request_pb2.py +0 -54
  35. glide/protobuf/command_request_pb2.pyi +0 -1187
  36. glide/protobuf/connection_request_pb2.py +0 -54
  37. glide/protobuf/connection_request_pb2.pyi +0 -320
  38. glide/protobuf/response_pb2.pyi +0 -100
  39. valkey_glide-2.0.0rc7.dist-info/METADATA +0 -144
  40. valkey_glide-2.0.0rc7.dist-info/RECORD +0 -37
  41. {glide/async_commands → glide_shared/commands}/bitmap.py +0 -0
  42. {glide/async_commands → glide_shared/commands}/command_args.py +0 -0
  43. {glide/async_commands → glide_shared/commands}/server_modules/ft_options/ft_constants.py +0 -0
  44. {glide → glide_shared}/protobuf_codec.py +0 -0
  45. {valkey_glide-2.0.0rc7.dist-info → valkey_glide-2.2.0.dist-info}/WHEEL +0 -0
glide/__init__.py CHANGED
@@ -1,13 +1,28 @@
1
1
  # Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0
2
2
 
3
- from glide.async_commands.batch import (
4
- Batch,
5
- ClusterBatch,
6
- ClusterTransaction,
7
- TBatch,
8
- Transaction,
3
+ import sys
4
+ import types
5
+ import warnings
6
+
7
+ from glide.glide import (
8
+ ClusterScanCursor,
9
+ OpenTelemetryConfig,
10
+ OpenTelemetryMetricsConfig,
11
+ OpenTelemetryTracesConfig,
12
+ Script,
9
13
  )
10
- from glide.async_commands.bitmap import (
14
+ from glide_shared import (
15
+ OK,
16
+ TOK,
17
+ AdvancedGlideClientConfiguration,
18
+ AdvancedGlideClusterClientConfiguration,
19
+ AggregationType,
20
+ AllNodes,
21
+ AllPrimaries,
22
+ BackoffStrategy,
23
+ Batch,
24
+ BatchOptions,
25
+ BatchRetryStrategy,
11
26
  BitEncoding,
12
27
  BitFieldGet,
13
28
  BitFieldIncrBy,
@@ -20,28 +35,26 @@ from glide.async_commands.bitmap import (
20
35
  BitOffsetMultiplier,
21
36
  BitOverflowControl,
22
37
  BitwiseOperation,
23
- OffsetOptions,
24
- SignedEncoding,
25
- UnsignedEncoding,
26
- )
27
- from glide.async_commands.command_args import Limit, ListDirection, ObjectType, OrderBy
28
- from glide.async_commands.core import (
38
+ ByAddressRoute,
39
+ ClosingError,
40
+ ClusterBatch,
41
+ ClusterBatchOptions,
42
+ ClusterTransaction,
29
43
  ConditionalChange,
30
- CoreCommands,
44
+ ConfigurationError,
45
+ ConnectionError,
46
+ DataType,
47
+ DistanceMetricType,
48
+ ExclusiveIdBound,
49
+ ExecAbortError,
31
50
  ExpireOptions,
32
51
  ExpiryGetEx,
33
52
  ExpirySet,
34
53
  ExpiryType,
35
54
  ExpiryTypeGetEx,
55
+ Field,
56
+ FieldType,
36
57
  FlushMode,
37
- FunctionRestorePolicy,
38
- InfoSection,
39
- InsertPosition,
40
- OnlyIfEqual,
41
- UpdateOptions,
42
- )
43
- from glide.async_commands.server_modules import ft, glide_json, json_batch
44
- from glide.async_commands.server_modules.ft_options.ft_aggregate_options import (
45
58
  FtAggregateApply,
46
59
  FtAggregateClause,
47
60
  FtAggregateFilter,
@@ -49,59 +62,66 @@ from glide.async_commands.server_modules.ft_options.ft_aggregate_options import
49
62
  FtAggregateLimit,
50
63
  FtAggregateOptions,
51
64
  FtAggregateReducer,
65
+ FtAggregateResponse,
52
66
  FtAggregateSortBy,
53
67
  FtAggregateSortProperty,
54
- )
55
- from glide.async_commands.server_modules.ft_options.ft_create_options import (
56
- DataType,
57
- DistanceMetricType,
58
- Field,
59
- FieldType,
60
68
  FtCreateOptions,
61
- NumericField,
62
- TagField,
63
- TextField,
64
- VectorAlgorithm,
65
- VectorField,
66
- VectorFieldAttributes,
67
- VectorFieldAttributesFlat,
68
- VectorFieldAttributesHnsw,
69
- VectorType,
70
- )
71
- from glide.async_commands.server_modules.ft_options.ft_profile_options import (
69
+ FtInfoResponse,
72
70
  FtProfileOptions,
73
- QueryType,
74
- )
75
- from glide.async_commands.server_modules.ft_options.ft_search_options import (
71
+ FtProfileResponse,
76
72
  FtSearchLimit,
77
73
  FtSearchOptions,
78
- ReturnField,
79
- )
80
- from glide.async_commands.server_modules.glide_json import (
81
- JsonArrIndexOptions,
82
- JsonArrPopOptions,
83
- JsonGetOptions,
84
- )
85
- from glide.async_commands.sorted_set import (
86
- AggregationType,
74
+ FtSearchResponse,
75
+ FunctionRestorePolicy,
87
76
  GeoSearchByBox,
88
77
  GeoSearchByRadius,
89
78
  GeoSearchCount,
90
79
  GeospatialData,
91
80
  GeoUnit,
81
+ GlideClientConfiguration,
82
+ GlideClusterClientConfiguration,
83
+ GlideError,
84
+ HashFieldConditionalChange,
85
+ IamAuthConfig,
86
+ IdBound,
92
87
  InfBound,
88
+ InfoSection,
89
+ InsertPosition,
90
+ JsonArrIndexOptions,
91
+ JsonArrPopOptions,
92
+ JsonGetOptions,
93
93
  LexBoundary,
94
+ Limit,
95
+ ListDirection,
96
+ MaxId,
97
+ MinId,
98
+ NodeAddress,
99
+ NumericField,
100
+ ObjectType,
101
+ OffsetOptions,
102
+ OnlyIfEqual,
103
+ OrderBy,
104
+ PeriodicChecksManualInterval,
105
+ PeriodicChecksStatus,
106
+ ProtocolVersion,
107
+ PubSubMsg,
108
+ QueryType,
109
+ RandomNode,
94
110
  RangeByIndex,
95
111
  RangeByLex,
96
112
  RangeByScore,
113
+ ReadFrom,
114
+ RequestError,
115
+ ReturnField,
116
+ Route,
97
117
  ScoreBoundary,
98
118
  ScoreFilter,
99
- )
100
- from glide.async_commands.stream import (
101
- ExclusiveIdBound,
102
- IdBound,
103
- MaxId,
104
- MinId,
119
+ ServerCredentials,
120
+ ServiceType,
121
+ SignedEncoding,
122
+ SlotIdRoute,
123
+ SlotKeyRoute,
124
+ SlotType,
105
125
  StreamAddOptions,
106
126
  StreamClaimOptions,
107
127
  StreamGroupOptions,
@@ -110,78 +130,105 @@ from glide.async_commands.stream import (
110
130
  StreamReadGroupOptions,
111
131
  StreamReadOptions,
112
132
  StreamTrimOptions,
113
- TrimByMaxLen,
114
- TrimByMinId,
115
- )
116
- from glide.config import (
117
- AdvancedGlideClientConfiguration,
118
- AdvancedGlideClusterClientConfiguration,
119
- BackoffStrategy,
120
- GlideClientConfiguration,
121
- GlideClusterClientConfiguration,
122
- NodeAddress,
123
- PeriodicChecksManualInterval,
124
- PeriodicChecksStatus,
125
- ProtocolVersion,
126
- ReadFrom,
127
- ServerCredentials,
128
- )
129
- from glide.constants import (
130
- OK,
131
- TOK,
132
- FtAggregateResponse,
133
- FtInfoResponse,
134
- FtProfileResponse,
135
- FtSearchResponse,
133
+ TagField,
134
+ TBatch,
136
135
  TClusterResponse,
137
136
  TEncodable,
137
+ TextField,
138
138
  TFunctionListResponse,
139
139
  TFunctionStatsFullResponse,
140
140
  TFunctionStatsSingleNodeResponse,
141
+ TimeoutError,
141
142
  TJsonResponse,
142
143
  TJsonUniversalResponse,
144
+ TlsAdvancedConfiguration,
145
+ Transaction,
143
146
  TResult,
147
+ TrimByMaxLen,
148
+ TrimByMinId,
144
149
  TSingleNodeRoute,
145
150
  TXInfoStreamFullResponse,
146
151
  TXInfoStreamResponse,
152
+ UnsignedEncoding,
153
+ UpdateOptions,
154
+ VectorAlgorithm,
155
+ VectorField,
156
+ VectorFieldAttributes,
157
+ VectorFieldAttributesFlat,
158
+ VectorFieldAttributesHnsw,
159
+ VectorType,
160
+ json_batch,
147
161
  )
148
- from glide.exceptions import (
149
- ClosingError,
150
- ConfigurationError,
151
- ConnectionError,
152
- ExecAbortError,
153
- GlideError,
154
- RequestError,
155
- TimeoutError,
156
- )
157
- from glide.glide_client import GlideClient, GlideClusterClient, TGlideClient
158
- from glide.logger import Level as LogLevel
159
- from glide.logger import Logger
160
- from glide.routes import (
161
- AllNodes,
162
- AllPrimaries,
163
- ByAddressRoute,
164
- RandomNode,
165
- Route,
166
- SlotIdRoute,
167
- SlotKeyRoute,
168
- SlotType,
169
- )
170
162
 
171
- from .glide import ClusterScanCursor, Script
163
+ from .async_commands import ft, glide_json
164
+ from .glide_client import GlideClient, GlideClusterClient, TGlideClient
165
+ from .logger import Level as LogLevel
166
+ from .logger import Logger
167
+
168
+ _glide_module = sys.modules[__name__]
169
+
170
+ _legacy_modules = [
171
+ "glide.exceptions",
172
+ "glide.config",
173
+ "glide.constants",
174
+ "glide.routes",
175
+ "glide.async_commands",
176
+ "glide.async_commands.batch",
177
+ "glide.async_commands.batch_options",
178
+ "glide.async_commands.bitmap",
179
+ "glide.async_commands.command_args",
180
+ "glide.async_commands.server_modules",
181
+ "glide.async_commands.server_modules.ft_options",
182
+ "glide.async_commands.server_modules.ft_options.ft_aggregate_options",
183
+ "glide.async_commands.server_modules.ft_options.ft_create_options",
184
+ "glide.async_commands.server_modules.ft_options.ft_profile_options",
185
+ "glide.async_commands.server_modules.ft_options.ft_search_options",
186
+ "glide.async_commands.server_modules.glide_json",
187
+ "glide.async_commands.sorted_set",
188
+ "glide.async_commands.stream",
189
+ ]
190
+
191
+
192
+ class _LegacyModule(types.ModuleType):
193
+ """Proxy for a deprecated module that warns when first accessed."""
194
+
195
+ def __init__(self, name):
196
+ super().__init__(name)
197
+ self._warned = False
198
+
199
+ def __getattr__(self, name):
200
+ if not self._warned:
201
+ warnings.warn(
202
+ f"Importing from '{self.__name__}' is deprecated. "
203
+ f"Please import directly from 'glide' instead.",
204
+ DeprecationWarning,
205
+ stacklevel=2,
206
+ )
207
+ self._warned = True
208
+
209
+ # Access the attribute from the real top-level glide module
210
+ return getattr(_glide_module, name)
172
211
 
173
- PubSubMsg = CoreCommands.PubSubMsg
212
+
213
+ # Replace old modules with lazy proxy modules
214
+ for old_name in _legacy_modules:
215
+ if old_name not in sys.modules:
216
+ sys.modules[old_name] = _LegacyModule(old_name)
174
217
 
175
218
  __all__ = [
176
219
  # Client
220
+ "TGlideClient",
177
221
  "GlideClient",
178
222
  "GlideClusterClient",
179
223
  "Batch",
180
224
  "ClusterBatch",
181
225
  "ClusterTransaction",
182
226
  "Transaction",
183
- "TGlideClient",
184
227
  "TBatch",
228
+ # Batch Options
229
+ "BatchOptions",
230
+ "BatchRetryStrategy",
231
+ "ClusterBatchOptions",
185
232
  # Config
186
233
  "AdvancedGlideClientConfiguration",
187
234
  "AdvancedGlideClusterClientConfiguration",
@@ -190,10 +237,16 @@ __all__ = [
190
237
  "BackoffStrategy",
191
238
  "ReadFrom",
192
239
  "ServerCredentials",
240
+ "ServiceType",
241
+ "IamAuthConfig",
193
242
  "NodeAddress",
243
+ "OpenTelemetryConfig",
244
+ "OpenTelemetryMetricsConfig",
245
+ "OpenTelemetryTracesConfig",
194
246
  "ProtocolVersion",
195
247
  "PeriodicChecksManualInterval",
196
248
  "PeriodicChecksStatus",
249
+ "TlsAdvancedConfiguration",
197
250
  # Response
198
251
  "OK",
199
252
  "TClusterResponse",
@@ -243,11 +296,11 @@ __all__ = [
243
296
  "GeoSearchCount",
244
297
  "GeoUnit",
245
298
  "GeospatialData",
299
+ "HashFieldConditionalChange",
246
300
  "AggregationType",
247
301
  "InfBound",
248
302
  "InfoSection",
249
303
  "InsertPosition",
250
- "ft",
251
304
  "LexBoundary",
252
305
  "Limit",
253
306
  "ListDirection",
@@ -303,6 +356,7 @@ __all__ = [
303
356
  "RequestError",
304
357
  "TimeoutError",
305
358
  # Ft
359
+ "ft",
306
360
  "DataType",
307
361
  "DistanceMetricType",
308
362
  "Field",
@@ -4,27 +4,28 @@ from __future__ import annotations
4
4
 
5
5
  from typing import Dict, List, Mapping, Optional, Union, cast
6
6
 
7
- from glide.async_commands.batch import ClusterBatch
8
- from glide.async_commands.command_args import ObjectType
9
- from glide.async_commands.core import (
10
- CoreCommands,
7
+ from glide.glide import ClusterScanCursor, Script
8
+ from glide_shared.commands.batch import ClusterBatch
9
+ from glide_shared.commands.batch_options import ClusterBatchOptions
10
+ from glide_shared.commands.command_args import ObjectType
11
+ from glide_shared.commands.core_options import (
11
12
  FlushMode,
12
13
  FunctionRestorePolicy,
13
14
  InfoSection,
14
15
  )
15
- from glide.constants import (
16
+ from glide_shared.constants import (
16
17
  TOK,
17
18
  TClusterResponse,
18
19
  TEncodable,
19
20
  TFunctionListResponse,
20
21
  TFunctionStatsSingleNodeResponse,
21
22
  TResult,
22
- TSingleNodeRoute,
23
23
  )
24
- from glide.protobuf.command_request_pb2 import RequestType
25
- from glide.routes import Route
24
+ from glide_shared.exceptions import RequestError
25
+ from glide_shared.protobuf.command_request_pb2 import RequestType
26
+ from glide_shared.routes import Route
26
27
 
27
- from ..glide import ClusterScanCursor, Script
28
+ from .core import CoreCommands
28
29
 
29
30
 
30
31
  class ClusterCommands(CoreCommands):
@@ -74,8 +75,8 @@ class ClusterCommands(CoreCommands):
74
75
  Args:
75
76
  sections (Optional[List[InfoSection]]): A list of InfoSection values specifying which sections of
76
77
  information to retrieve. When no parameter is provided, the default option is assumed.
77
- route (Optional[Route]): The command will be routed to all primaries, unless `route` is provided, in which
78
- case the client will route the command to the nodes defined by `route`. Defaults to None.
78
+ route (Optional[Route]): The command will be routed to all primaries, unless `route` is provided, in
79
+ which case the client will route the command to the nodes defined by `route`. Defaults to None.
79
80
 
80
81
  Returns:
81
82
  TClusterResponse[bytes]: If a single node route is requested, returns a bytes string containing the information for
@@ -94,128 +95,109 @@ class ClusterCommands(CoreCommands):
94
95
  self,
95
96
  batch: ClusterBatch,
96
97
  raise_on_error: bool,
97
- route: Optional[TSingleNodeRoute] = None,
98
- timeout: Optional[int] = None,
99
- retry_server_error: bool = False,
100
- retry_connection_error: bool = False,
98
+ options: Optional[ClusterBatchOptions] = None,
101
99
  ) -> Optional[List[TResult]]:
102
100
  """
103
101
  Executes a batch by processing the queued commands.
104
102
 
105
- See [Valkey Transactions (Atomic Batches)](https://valkey.io/docs/topics/transactions/) for details.
106
- See [Valkey Pipelines (Non-Atomic Batches)](https://valkey.io/docs/topics/pipelining/) for details.
107
-
108
- #### Routing Behavior:
109
-
110
- - If a `route` is specified:
111
- - The entire batch is sent to the specified node.
103
+ **Routing Behavior:**
112
104
 
105
+ - If a `route` is specified in `ClusterBatchOptions`, the entire batch is sent
106
+ to the specified node.
113
107
  - If no `route` is specified:
114
- - Atomic batches (Transactions): Routed to the slot owner of the first key in the batch.
115
- If no key is found, the request is sent to a random node.
116
- - Non-atomic batches (Pipelines): Each command is routed to the node owning the corresponding
117
- key's slot. If no key is present, routing follows the command's default request policy.
118
- Multi-node commands are automatically split and dispatched to the appropriate nodes.
108
+ - **Atomic batches (Transactions):** Routed to the slot owner of the
109
+ first key in the batch. If no key is found, the request is sent to a random node.
110
+ - **Non-atomic batches (Pipelines):** Each command is routed to the node
111
+ owning the corresponding key's slot. If no key is present, routing follows the
112
+ command's request policy. Multi-node commands are automatically split and
113
+ dispatched to the appropriate nodes.
119
114
 
120
- #### Behavior notes:
115
+ **Behavior notes:**
121
116
 
122
- - Atomic Batches (Transactions): All key-based commands must map to the same hash slot.
123
- If keys span different slots, the transaction will fail. If the transaction fails due to a
124
- `WATCH` command, `exec` will return `None`.
117
+ - **Atomic Batches (Transactions):** All key-based commands must map to the
118
+ same hash slot. If keys span different slots, the transaction will fail. If the
119
+ transaction fails due to a `WATCH` command, `EXEC` will return `None`.
125
120
 
126
- #### Retry and Redirection:
121
+ **Retry and Redirection:**
127
122
 
128
123
  - If a redirection error occurs:
129
- - Atomic batches (Transactions): The entire transaction will be redirected.
130
- - Non-atomic batches (Pipelines): Only commands that encountered redirection errors will be redirected.
131
-
132
- - Retries for failures will be handled according to the `retry_server_error` and
133
- `retry_connection_error` parameters.
124
+ - **Atomic batches (Transactions):** The entire transaction will be
125
+ redirected.
126
+ - **Non-atomic batches:** Only commands that encountered redirection
127
+ errors will be redirected.
128
+ - Retries for failures will be handled according to the configured `BatchRetryStrategy`.
134
129
 
135
130
  Args:
136
- batch (ClusterBatch): A `ClusterBatch` object containing a list of commands to be executed.
137
- raise_on_error (bool): Determines how errors are handled within the batch response. When set to
138
- `True`, the first encountered error in the batch will be raised as a `RequestError`
139
- exception after all retries and reconnections have been executed. When set to `False`,
140
- errors will be included as part of the batch response array, allowing the caller to process both
141
- successful and failed commands together. In this case, error details will be provided as
142
- instances of `RequestError`.
143
- route (Optional[TSingleNodeRoute]): Configures single-node routing for the batch request. The client
144
- will send the batch to the specified node defined by `route`.
145
-
146
- If a redirection error occurs:
147
- - For Atomic Batches (Transactions), the entire transaction will be redirected.
148
- - For Non-Atomic Batches (Pipelines), only the commands that encountered redirection errors
149
- will be redirected.
150
- timeout (Optional[int]): The duration in milliseconds that the client should wait for the batch request
151
- to complete. This duration encompasses sending the request, awaiting a response from the server,
152
- and any required reconnections or retries.
153
-
154
- If the specified timeout is exceeded, a timeout error will be raised. If not explicitly set,
155
- the client's default request timeout will be used.
156
- retry_server_error (bool): If `True`, retriable server errors (e.g., `TRYAGAIN`) will trigger a retry.
157
- Warning: Retrying server errors may cause commands targeting the same slot to execute out of order.
158
- Note: Currently supported only for non-atomic batches. Recommended to increase timeout when enabled.
159
- retry_connection_error (bool): If `True`, connection failures will trigger a retry. Warning:
160
- Retrying connection errors may lead to duplicate executions, as it is unclear which commands have
161
- already been processed. Note: Currently supported only for non-atomic batches. Recommended to increase
162
- timeout when enabled.
131
+ batch (ClusterBatch): A `ClusterBatch` containing the commands to execute.
132
+ raise_on_error (bool): Determines how errors are handled within the batch response.
133
+ When set to `True`, the first encountered error in the batch will be raised as an
134
+ exception of type `RequestError` after all retries and reconnections have been
135
+ executed.
136
+ When set to `False`, errors will be included as part of the batch response,
137
+ allowing the caller to process both successful and failed commands together. In this case,
138
+ error details will be provided as instances of `RequestError`.
139
+ options (Optional[ClusterBatchOptions]): A `ClusterBatchOptions` object containing execution options.
163
140
 
164
141
  Returns:
165
- Optional[List[TResult]]: A list of results corresponding to the execution of each command in the batch.
166
- If a command returns a value, it will be included in the list. If a command doesn't return a value,
167
- the list entry will be `None`. If the batch failed due to a `WATCH` command, `exec` will return
168
- `None`.
169
-
170
- Examples:
171
- # Example 1: Atomic Batch (Transaction)
172
- >>> atomic_batch = ClusterBatch(is_atomic=True) # Atomic (Transaction)
173
- >>> atomic_batch.set("key", "1")
174
- >>> atomic_batch.incr("key")
175
- >>> atomic_batch.get("key")
176
- >>> atomic_result = await cluster_client.exec(atomic_batch, false)
177
- >>> print(f"Atomic Batch Result: {atomic_result}")
178
- # Expected Output: Atomic Batch Result: [OK, 2, 2]
142
+ Optional[List[TResult]]: An array of results, where each entry
143
+ corresponds to a command's execution result.
179
144
 
180
- # Example 2: Non-Atomic Batch (Pipeline)
181
- >>> non_atomic_batch = ClusterBatch(is_atomic=False) # Non-Atomic (Pipeline)
182
- >>> non_atomic_batch.set("key1", "value1")
183
- >>> non_atomic_batch.set("key2", "value2")
184
- >>> non_atomic_batch.get("key1")
185
- >>> non_atomic_batch.get("key2")
186
- >>> non_atomic_result = await cluster_client.exec(non_atomic_batch, false)
187
- >>> print(f"Non-Atomic Batch Result: {non_atomic_result}")
188
- # Expected Output: Non-Atomic Batch Result: [OK, OK, value1, value2]
145
+ See Also:
146
+ [Valkey Transactions (Atomic Batches)](https://valkey.io/docs/topics/transactions/)
147
+ [Valkey Pipelines (Non-Atomic Batches)](https://valkey.io/docs/topics/pipelining/)
189
148
 
190
- # Example 3: Atomic batch with options
149
+ Examples:
150
+ # Atomic batch (transaction): all keys must share the same hash slot
151
+ >>> options = ClusterBatchOptions(timeout=1000) # Set a timeout of 1000 milliseconds
191
152
  >>> atomic_batch = ClusterBatch(is_atomic=True)
192
153
  >>> atomic_batch.set("key", "1")
193
154
  >>> atomic_batch.incr("key")
194
155
  >>> atomic_batch.get("key")
195
- >>> atomic_result = await cluster_client.exec(
196
- ... atomic_batch,
197
- ... timeout=1000, # Set a timeout of 1000 milliseconds
198
- ... raise_on_error=False # Do not raise an error on failure
199
- ... )
156
+ >>> atomic_result = await cluster_client.exec(atomic_batch, False, options)
200
157
  >>> print(f"Atomic Batch Result: {atomic_result}")
201
158
  # Output: Atomic Batch Result: [OK, 2, 2]
202
159
 
203
- # Example 4: Non-atomic batch with retry options
160
+ # Non-atomic batch (pipeline): keys may span different hash slots
161
+ >>> retry_strategy = BatchRetryStrategy(retry_server_error=True, retry_connection_error=False)
162
+ >>> pipeline_options = ClusterBatchOptions(retry_strategy=retry_strategy)
204
163
  >>> non_atomic_batch = ClusterBatch(is_atomic=False)
205
164
  >>> non_atomic_batch.set("key1", "value1")
206
165
  >>> non_atomic_batch.set("key2", "value2")
207
166
  >>> non_atomic_batch.get("key1")
208
167
  >>> non_atomic_batch.get("key2")
209
- >>> non_atomic_result = await cluster_client.exec(
210
- ... non_atomic_batch,
211
- ... raise_on_error=False,
212
- ... retry_server_error=True,
213
- ... retry_connection_error=False
214
- ... )
168
+ >>> non_atomic_result = await cluster_client.exec(non_atomic_batch, False, pipeline_options)
215
169
  >>> print(f"Non-Atomic Batch Result: {non_atomic_result}")
216
170
  # Output: Non-Atomic Batch Result: [OK, OK, value1, value2]
217
171
  """
218
172
  commands = batch.commands[:]
173
+
174
+ if (
175
+ batch.is_atomic
176
+ and options
177
+ and options.retry_strategy
178
+ and (
179
+ options.retry_strategy.retry_server_error
180
+ or options.retry_strategy.retry_connection_error
181
+ )
182
+ ):
183
+ raise RequestError(
184
+ "Retry strategies are not supported for atomic batches (transactions). "
185
+ )
186
+
187
+ # Extract values to make the _execute_batch call cleaner
188
+ retry_server_error = (
189
+ options.retry_strategy.retry_server_error
190
+ if options and options.retry_strategy
191
+ else False
192
+ )
193
+ retry_connection_error = (
194
+ options.retry_strategy.retry_connection_error
195
+ if options and options.retry_strategy
196
+ else False
197
+ )
198
+ route = options.route if options else None
199
+ timeout = options.timeout if options else None
200
+
219
201
  return await self._execute_batch(
220
202
  commands,
221
203
  batch.is_atomic,
@@ -1084,11 +1066,17 @@ class ClusterCommands(CoreCommands):
1084
1066
  self,
1085
1067
  source: TEncodable,
1086
1068
  destination: TEncodable,
1069
+ # TODO next major release the arguments replace and destinationDB must have their order
1070
+ # swapped to align with the standalone order.
1071
+ # At the moment of the patch release 2.1.1. we can't have a breaking change
1087
1072
  replace: Optional[bool] = None,
1073
+ destinationDB: Optional[int] = None,
1088
1074
  ) -> bool:
1089
1075
  """
1090
- Copies the value stored at the `source` to the `destination` key. When `replace` is True,
1091
- removes the `destination` key first if it already exists, otherwise performs no action.
1076
+ Copies the value stored at the `source` to the `destination` key. If `destinationDB`
1077
+ is specified, the value will be copied to the database specified by `destinationDB`,
1078
+ otherwise the current database will be used. When `replace` is True, removes the
1079
+ `destination` key first if it already exists, otherwise performs no action.
1092
1080
 
1093
1081
  See [valkey.io](https://valkey.io/commands/copy) for more details.
1094
1082
 
@@ -1099,6 +1087,7 @@ class ClusterCommands(CoreCommands):
1099
1087
  source (TEncodable): The key to the source value.
1100
1088
  destination (TEncodable): The key where the value should be copied to.
1101
1089
  replace (Optional[bool]): If the destination key should be removed before copying the value to it.
1090
+ destinationDB (Optional[int]): The alternative logical database index for the destination key.
1102
1091
 
1103
1092
  Returns:
1104
1093
  bool: True if the source was copied. Otherwise, returns False.
@@ -1107,12 +1096,20 @@ class ClusterCommands(CoreCommands):
1107
1096
  >>> await client.set("source", "sheep")
1108
1097
  >>> await client.copy(b"source", b"destination")
1109
1098
  True # Source was copied
1099
+ >>> await client.copy(b"source", b"destination", destinationDB=1)
1100
+ True # Source was copied to DB 1
1101
+ >>> await client.select(1)
1110
1102
  >>> await client.get("destination")
1111
1103
  b"sheep"
1112
1104
 
1113
1105
  Since: Valkey version 6.2.0.
1106
+ The destinationDB argument is available since Valkey 9.0.0
1114
1107
  """
1108
+
1109
+ # Build command arguments
1115
1110
  args: List[TEncodable] = [source, destination]
1111
+ if destinationDB is not None:
1112
+ args.extend(["DB", str(destinationDB)])
1116
1113
  if replace is True:
1117
1114
  args.append("REPLACE")
1118
1115
  return cast(
@@ -1159,7 +1156,7 @@ class ClusterCommands(CoreCommands):
1159
1156
  args.extend(["VERSION", str(version)])
1160
1157
  if parameters:
1161
1158
  for var in parameters:
1162
- args.extend(str(var))
1159
+ args.append(str(var))
1163
1160
  return cast(
1164
1161
  TClusterResponse[bytes],
1165
1162
  await self._execute_command(RequestType.Lolwut, args, route),
@@ -1439,7 +1436,7 @@ class ClusterCommands(CoreCommands):
1439
1436
 
1440
1437
  Examples:
1441
1438
  >>> lua_script = Script("return { KEYS[1], ARGV[1] }")
1442
- >>> await client.invoke_script(lua_script, keys=["foo"], args=["bar"] );
1439
+ >>> await client.invoke_script(lua_script, keys=["foo"], args=["bar"])
1443
1440
  [b"foo", b"bar"]
1444
1441
  """
1445
1442
  return await self._execute_script(script.get_hash(), keys, args)