valkey-glide 2.1.0rc3__cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl → 2.2.1rc3__cp310-cp310-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.
glide/__init__.py CHANGED
@@ -1,5 +1,9 @@
1
1
  # Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0
2
2
 
3
+ import sys
4
+ import types
5
+ import warnings
6
+
3
7
  from glide.glide import (
4
8
  ClusterScanCursor,
5
9
  OpenTelemetryConfig,
@@ -78,6 +82,7 @@ from glide_shared import (
78
82
  GlideClusterClientConfiguration,
79
83
  GlideError,
80
84
  HashFieldConditionalChange,
85
+ IamAuthConfig,
81
86
  IdBound,
82
87
  InfBound,
83
88
  InfoSection,
@@ -112,6 +117,7 @@ from glide_shared import (
112
117
  ScoreBoundary,
113
118
  ScoreFilter,
114
119
  ServerCredentials,
120
+ ServiceType,
115
121
  SignedEncoding,
116
122
  SlotIdRoute,
117
123
  SlotKeyRoute,
@@ -159,6 +165,56 @@ from .glide_client import GlideClient, GlideClusterClient, TGlideClient
159
165
  from .logger import Level as LogLevel
160
166
  from .logger import Logger
161
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)
211
+
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)
217
+
162
218
  __all__ = [
163
219
  # Client
164
220
  "TGlideClient",
@@ -181,6 +237,8 @@ __all__ = [
181
237
  "BackoffStrategy",
182
238
  "ReadFrom",
183
239
  "ServerCredentials",
240
+ "ServiceType",
241
+ "IamAuthConfig",
184
242
  "NodeAddress",
185
243
  "OpenTelemetryConfig",
186
244
  "OpenTelemetryMetricsConfig",
@@ -1066,11 +1066,17 @@ class ClusterCommands(CoreCommands):
1066
1066
  self,
1067
1067
  source: TEncodable,
1068
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
1069
1072
  replace: Optional[bool] = None,
1073
+ destinationDB: Optional[int] = None,
1070
1074
  ) -> bool:
1071
1075
  """
1072
- Copies the value stored at the `source` to the `destination` key. When `replace` is True,
1073
- 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.
1074
1080
 
1075
1081
  See [valkey.io](https://valkey.io/commands/copy) for more details.
1076
1082
 
@@ -1081,6 +1087,7 @@ class ClusterCommands(CoreCommands):
1081
1087
  source (TEncodable): The key to the source value.
1082
1088
  destination (TEncodable): The key where the value should be copied to.
1083
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.
1084
1091
 
1085
1092
  Returns:
1086
1093
  bool: True if the source was copied. Otherwise, returns False.
@@ -1089,12 +1096,20 @@ class ClusterCommands(CoreCommands):
1089
1096
  >>> await client.set("source", "sheep")
1090
1097
  >>> await client.copy(b"source", b"destination")
1091
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)
1092
1102
  >>> await client.get("destination")
1093
1103
  b"sheep"
1094
1104
 
1095
1105
  Since: Valkey version 6.2.0.
1106
+ The destinationDB argument is available since Valkey 9.0.0
1096
1107
  """
1108
+
1109
+ # Build command arguments
1097
1110
  args: List[TEncodable] = [source, destination]
1111
+ if destinationDB is not None:
1112
+ args.extend(["DB", str(destinationDB)])
1098
1113
  if replace is True:
1099
1114
  args.append("REPLACE")
1100
1115
  return cast(
@@ -1141,7 +1156,7 @@ class ClusterCommands(CoreCommands):
1141
1156
  args.extend(["VERSION", str(version)])
1142
1157
  if parameters:
1143
1158
  for var in parameters:
1144
- args.extend(str(var))
1159
+ args.append(str(var))
1145
1160
  return cast(
1146
1161
  TClusterResponse[bytes],
1147
1162
  await self._execute_command(RequestType.Lolwut, args, route),
@@ -139,6 +139,27 @@ class CoreCommands(Protocol):
139
139
  TOK, await self._update_connection_password(password, immediate_auth)
140
140
  )
141
141
 
142
+ async def _refresh_iam_token(self) -> TResult: ...
143
+
144
+ async def refresh_iam_token(self) -> TOK:
145
+ """
146
+ Manually refresh the IAM token for the current connection.
147
+
148
+ This method is only available if the client was created with IAM authentication.
149
+ It triggers an immediate refresh of the IAM token and updates the connection.
150
+
151
+ Returns:
152
+ TOK: A simple OK response on success.
153
+
154
+ Raises:
155
+ ConfigurationError: If the client is not using IAM authentication.
156
+
157
+ Example:
158
+ >>> await client.refresh_iam_token()
159
+ 'OK'
160
+ """
161
+ return cast(TOK, await self._refresh_iam_token())
162
+
142
163
  async def set(
143
164
  self,
144
165
  key: TEncodable,
@@ -430,6 +451,34 @@ class CoreCommands(Protocol):
430
451
  """
431
452
  return cast(int, await self._execute_command(RequestType.Del, keys))
432
453
 
454
+ async def move(self, key: TEncodable, db_index: int) -> bool:
455
+ """
456
+ Move key from the currently selected database to the specified destination database.
457
+
458
+ Note:
459
+ For cluster mode move command is supported since Valkey 9.0.0
460
+
461
+ See [valkey.io](https://valkey.io/commands/move/) for more details.
462
+
463
+ Args:
464
+ key (TEncodable): The key to move.
465
+ db_index (int): The destination database number.
466
+
467
+ Returns:
468
+ bool: True if the key was moved successfully, False if the key does not exist
469
+ or was already present in the destination database.
470
+
471
+ Examples:
472
+ >>> await client.move("some_key", 1)
473
+ True # The key was successfully moved to database 1
474
+ >>> await client.move("nonexistent_key", 1)
475
+ False # The key does not exist
476
+ """
477
+ return cast(
478
+ bool,
479
+ await self._execute_command(RequestType.Move, [key, str(db_index)]),
480
+ )
481
+
433
482
  async def incr(self, key: TEncodable) -> int:
434
483
  """
435
484
  Increments the number stored at `key` by one. If the key does not exist, it is set to 0 before performing the
@@ -1120,7 +1169,7 @@ class CoreCommands(Protocol):
1120
1169
  - `-2`: field does not exist or key does not exist
1121
1170
 
1122
1171
  Examples:
1123
- >>> await client.hsetex("my_hash", {"field1": "value1", "field2": "value2"}, expiry=ExpirySet(ExpiryType.EX, 10))
1172
+ >>> await client.hsetex("my_hash", {"field1": "value1", "field2": "value2"}, expiry=ExpirySet(ExpiryType.SEC, 10))
1124
1173
  >>> await client.httl("my_hash", ["field1", "field2", "non_existent_field"])
1125
1174
  [9, 9, -2] # field1 and field2 have ~9 seconds left, non_existent_field doesn't exist
1126
1175
 
@@ -1150,7 +1199,7 @@ class CoreCommands(Protocol):
1150
1199
  - `-2`: field does not exist or key does not exist
1151
1200
 
1152
1201
  Examples:
1153
- >>> await client.hsetex("my_hash", {"field1": "value1", "field2": "value2"}, expiry=ExpirySet(ExpiryType.PX, 10000))
1202
+ >>> await client.hsetex("my_hash", {"field1": "value1", "field2": "value2"}, expiry=ExpirySet(ExpiryType.MILLSEC, 10000))
1154
1203
  >>> await client.hpttl("my_hash", ["field1", "field2", "non_existent_field"])
1155
1204
  [9500, 9500, -2] # field1 and field2 have ~9500 milliseconds left, non_existent_field doesn't exist
1156
1205
 
@@ -1182,7 +1231,7 @@ class CoreCommands(Protocol):
1182
1231
  Examples:
1183
1232
  >>> import time
1184
1233
  >>> future_timestamp = int(time.time()) + 60 # 60 seconds from now
1185
- >>> await client.hsetex("my_hash", {"field1": "value1", "field2": "value2"}, expiry=ExpirySet(ExpiryType.EXAT, future_timestamp))
1234
+ >>> await client.hsetex("my_hash", {"field1": "value1", "field2": "value2"}, expiry=ExpirySet(ExpiryType.UNIX_SEC, future_timestamp))
1186
1235
  >>> await client.hexpiretime("my_hash", ["field1", "field2", "non_existent_field"])
1187
1236
  [future_timestamp, future_timestamp, -2] # field1 and field2 expire at future_timestamp, non_existent_field doesn't exist
1188
1237
 
@@ -1216,7 +1265,7 @@ class CoreCommands(Protocol):
1216
1265
  Examples:
1217
1266
  >>> import time
1218
1267
  >>> future_timestamp_ms = int(time.time() * 1000) + 60000 # 60 seconds from now in milliseconds
1219
- >>> await client.hsetex("my_hash", {"field1": "value1", "field2": "value2"}, expiry=ExpirySet(ExpiryType.PXAT, future_timestamp_ms))
1268
+ >>> await client.hsetex("my_hash", {"field1": "value1", "field2": "value2"}, expiry=ExpirySet(ExpiryType.UNIX_MILLSEC, future_timestamp_ms))
1220
1269
  >>> await client.hpexpiretime("my_hash", ["field1", "field2", "non_existent_field"])
1221
1270
  [future_timestamp_ms, future_timestamp_ms, -2] # field1 and field2 expire at future_timestamp_ms, non_existent_field doesn't exist
1222
1271
 
@@ -1249,17 +1298,17 @@ class CoreCommands(Protocol):
1249
1298
  - ONLY_IF_ALL_EXIST (FXX): Only set fields if all of them already exist.
1250
1299
  - ONLY_IF_NONE_EXIST (FNX): Only set fields if none of them already exist.
1251
1300
  expiry (Optional[ExpirySet]): Expiration options for the fields:
1252
- - EX: Expiration time in seconds.
1253
- - PX: Expiration time in milliseconds.
1254
- - EXAT: Absolute expiration time in seconds (Unix timestamp).
1255
- - PXAT: Absolute expiration time in milliseconds (Unix timestamp).
1256
- - KEEPTTL: Retain existing TTL.
1301
+ - SEC (EX): Expiration time in seconds.
1302
+ - MILLSEC (PX): Expiration time in milliseconds.
1303
+ - UNIX_SEC (EXAT): Absolute expiration time in seconds (Unix timestamp).
1304
+ - UNIX_MILLSEC (PXAT): Absolute expiration time in milliseconds (Unix timestamp).
1305
+ - KEEP_TTL (KEEPTTL): Retain existing TTL.
1257
1306
 
1258
1307
  Returns:
1259
1308
  int: 1 if all fields were set successfully, 0 if none were set due to conditional constraints.
1260
1309
 
1261
1310
  Examples:
1262
- >>> await client.hsetex("my_hash", {"field1": "value1", "field2": "value2"}, expiry=ExpirySet(ExpiryType.EX, 10))
1311
+ >>> await client.hsetex("my_hash", {"field1": "value1", "field2": "value2"}, expiry=ExpirySet(ExpiryType.SEC, 10))
1263
1312
  1 # All fields set with 10 second expiration
1264
1313
  >>> await client.hsetex("my_hash", {"field3": "value3"}, field_conditional_change=HashFieldConditionalChange.ONLY_IF_ALL_EXIST)
1265
1314
  1 # Field set because field already exists
@@ -1305,10 +1354,10 @@ class CoreCommands(Protocol):
1305
1354
  key (TEncodable): The key of the hash.
1306
1355
  fields (List[TEncodable]): The list of fields to retrieve from the hash.
1307
1356
  expiry (Optional[ExpiryGetEx]): Expiration options for the retrieved fields:
1308
- - EX: Expiration time in seconds.
1309
- - PX: Expiration time in milliseconds.
1310
- - EXAT: Absolute expiration time in seconds (Unix timestamp).
1311
- - PXAT: Absolute expiration time in milliseconds (Unix timestamp).
1357
+ - SEC (EX): Expiration time in seconds.
1358
+ - MILLSEC (PX): Expiration time in milliseconds.
1359
+ - UNIX_SEC (EXAT): Absolute expiration time in seconds (Unix timestamp).
1360
+ - UNIX_MILLSEC (PXAT): Absolute expiration time in milliseconds (Unix timestamp).
1312
1361
  - PERSIST: Remove expiration from the fields.
1313
1362
 
1314
1363
  Returns:
@@ -1317,10 +1366,10 @@ class CoreCommands(Protocol):
1317
1366
  If `key` does not exist, it is treated as an empty hash, and the function returns a list of null values.
1318
1367
 
1319
1368
  Examples:
1320
- >>> await client.hsetex("my_hash", {"field1": "value1", "field2": "value2"}, expiry=ExpirySet(ExpiryType.EX, 10))
1369
+ >>> await client.hsetex("my_hash", {"field1": "value1", "field2": "value2"}, expiry=ExpirySet(ExpiryType.SEC, 10))
1321
1370
  >>> await client.hgetex("my_hash", ["field1", "field2"])
1322
1371
  [b"value1", b"value2"]
1323
- >>> await client.hgetex("my_hash", ["field1"], expiry=ExpiryGetEx(ExpiryTypeGetEx.EX, 20))
1372
+ >>> await client.hgetex("my_hash", ["field1"], expiry=ExpiryGetEx(ExpiryTypeGetEx.SEC, 20))
1324
1373
  [b"value1"] # field1 now has 20 second expiration
1325
1374
  >>> await client.hgetex("my_hash", ["field1"], expiry=ExpiryGetEx(ExpiryTypeGetEx.PERSIST, None))
1326
1375
  [b"value1"] # field1 expiration removed
@@ -1374,7 +1423,7 @@ class CoreCommands(Protocol):
1374
1423
  - `2`: Field was deleted immediately (when seconds is 0 or timestamp is in the past).
1375
1424
 
1376
1425
  Examples:
1377
- >>> await client.hsetex("my_hash", {"field1": "value1", "field2": "value2"}, expiry=ExpirySet(ExpiryType.EX, 10))
1426
+ >>> await client.hsetex("my_hash", {"field1": "value1", "field2": "value2"}, expiry=ExpirySet(ExpiryType.SEC, 10))
1378
1427
  >>> await client.hexpire("my_hash", 20, ["field1", "field2"])
1379
1428
  [1, 1] # Both fields' expiration set to 20 seconds
1380
1429
  >>> await client.hexpire("my_hash", 30, ["field1"], option=ExpireOptions.NewExpiryGreaterThanCurrent)
@@ -1420,7 +1469,7 @@ class CoreCommands(Protocol):
1420
1469
  - `-2`: Field does not exist or key does not exist.
1421
1470
 
1422
1471
  Examples:
1423
- >>> await client.hsetex("my_hash", {"field1": "value1", "field2": "value2"}, expiry=ExpirySet(ExpiryType.EX, 10))
1472
+ >>> await client.hsetex("my_hash", {"field1": "value1", "field2": "value2"}, expiry=ExpirySet(ExpiryType.SEC, 10))
1424
1473
  >>> await client.hpersist("my_hash", ["field1", "field2"])
1425
1474
  [1, 1] # Both fields made persistent
1426
1475
  >>> await client.hpersist("my_hash", ["field1"])
@@ -1467,7 +1516,7 @@ class CoreCommands(Protocol):
1467
1516
  - `2`: Field was deleted immediately (when milliseconds is 0 or timestamp is in the past).
1468
1517
 
1469
1518
  Examples:
1470
- >>> await client.hsetex("my_hash", {"field1": "value1", "field2": "value2"}, expiry=ExpirySet(ExpiryType.PX, 10000))
1519
+ >>> await client.hsetex("my_hash", {"field1": "value1", "field2": "value2"}, expiry=ExpirySet(ExpiryType.MILLSEC, 10000))
1471
1520
  >>> await client.hpexpire("my_hash", 20000, ["field1", "field2"])
1472
1521
  [1, 1] # Both fields' expiration set to 20000 milliseconds
1473
1522
  >>> await client.hpexpire("my_hash", 30000, ["field1"], option=ExpireOptions.NewExpiryGreaterThanCurrent)
@@ -1528,7 +1577,7 @@ class CoreCommands(Protocol):
1528
1577
  Examples:
1529
1578
  >>> import time
1530
1579
  >>> future_timestamp = int(time.time()) + 60 # 60 seconds from now
1531
- >>> await client.hsetex("my_hash", {"field1": "value1", "field2": "value2"}, expiry=ExpirySet(ExpiryType.EX, 10))
1580
+ >>> await client.hsetex("my_hash", {"field1": "value1", "field2": "value2"}, expiry=ExpirySet(ExpiryType.SEC, 10))
1532
1581
  >>> await client.hexpireat("my_hash", future_timestamp, ["field1", "field2"])
1533
1582
  [1, 1] # Both fields' expiration set to future_timestamp
1534
1583
  >>> past_timestamp = int(time.time()) - 60 # 60 seconds ago
@@ -1588,7 +1637,7 @@ class CoreCommands(Protocol):
1588
1637
  Examples:
1589
1638
  >>> import time
1590
1639
  >>> future_timestamp_ms = int(time.time() * 1000) + 60000 # 60 seconds from now in milliseconds
1591
- >>> await client.hsetex("my_hash", {"field1": "value1", "field2": "value2"}, expiry=ExpirySet(ExpiryType.PX, 10000))
1640
+ >>> await client.hsetex("my_hash", {"field1": "value1", "field2": "value2"}, expiry=ExpirySet(ExpiryType.MILLSEC, 10000))
1592
1641
  >>> await client.hpexpireat("my_hash", future_timestamp_ms, ["field1", "field2"])
1593
1642
  [1, 1] # Both fields' expiration set to future_timestamp_ms
1594
1643
  >>> past_timestamp_ms = int(time.time() * 1000) - 60000 # 60 seconds ago in milliseconds
@@ -2242,6 +2291,20 @@ class CoreCommands(Protocol):
2242
2291
  """
2243
2292
  return cast(int, await self._execute_command(RequestType.SAdd, [key] + members))
2244
2293
 
2294
+ async def select(self, index: int) -> TOK:
2295
+ """
2296
+ Change the currently selected database.
2297
+
2298
+ See [valkey.io](https://valkey.io/commands/select/) for details.
2299
+
2300
+ Args:
2301
+ index (int): The index of the database to select.
2302
+
2303
+ Returns:
2304
+ A simple OK response.
2305
+ """
2306
+ return cast(TOK, await self._execute_command(RequestType.Select, [str(index)]))
2307
+
2245
2308
  async def srem(self, key: TEncodable, members: List[TEncodable]) -> int:
2246
2309
  """
2247
2310
  Remove specified members from the set stored at `key`.
@@ -162,20 +162,6 @@ class StandaloneCommands(CoreCommands):
162
162
  timeout=timeout,
163
163
  )
164
164
 
165
- async def select(self, index: int) -> TOK:
166
- """
167
- Change the currently selected database.
168
-
169
- See [valkey.io](https://valkey.io/commands/select/) for details.
170
-
171
- Args:
172
- index (int): The index of the database to select.
173
-
174
- Returns:
175
- A simple OK response.
176
- """
177
- return cast(TOK, await self._execute_command(RequestType.Select, [str(index)]))
178
-
179
165
  async def config_resetstat(self) -> TOK:
180
166
  """
181
167
  Resets the statistics reported by the server using the INFO and LATENCY HISTOGRAM commands.
@@ -629,31 +615,6 @@ class StandaloneCommands(CoreCommands):
629
615
  await self._execute_command(RequestType.LastSave, []),
630
616
  )
631
617
 
632
- async def move(self, key: TEncodable, db_index: int) -> bool:
633
- """
634
- Move `key` from the currently selected database to the database specified by `db_index`.
635
-
636
- See [valkey.io](https://valkey.io/commands/move/) for more details.
637
-
638
- Args:
639
- key (TEncodable): The key to move.
640
- db_index (int): The index of the database to move `key` to.
641
-
642
- Returns:
643
- bool: `True` if `key` was moved.
644
-
645
- `False` if the `key` already exists in the destination database
646
- or does not exist in the source database.
647
-
648
- Example:
649
- >>> await client.move("some_key", 1)
650
- True
651
- """
652
- return cast(
653
- bool,
654
- await self._execute_command(RequestType.Move, [key, str(db_index)]),
655
- )
656
-
657
618
  async def publish(self, message: TEncodable, channel: TEncodable) -> int:
658
619
  """
659
620
  Publish a message on pubsub channel.
@@ -806,7 +767,7 @@ class StandaloneCommands(CoreCommands):
806
767
  args.extend(["VERSION", str(version)])
807
768
  if parameters:
808
769
  for var in parameters:
809
- args.extend(str(var))
770
+ args.append(str(var))
810
771
  return cast(
811
772
  bytes,
812
773
  await self._execute_command(RequestType.Lolwut, args),
glide/glide_client.py CHANGED
@@ -48,6 +48,7 @@ from glide_shared.exceptions import (
48
48
  from glide_shared.protobuf.command_request_pb2 import (
49
49
  Command,
50
50
  CommandRequest,
51
+ RefreshIamToken,
51
52
  RequestType,
52
53
  )
53
54
  from glide_shared.protobuf.connection_request_pb2 import ConnectionRequest
@@ -338,7 +339,7 @@ class BaseClient(CoreCommands):
338
339
  request.callback_idx if isinstance(request, CommandRequest) else 0
339
340
  )
340
341
  res_future = self._available_futures.pop(callback_idx, None)
341
- if res_future:
342
+ if res_future and not res_future.done():
342
343
  res_future.set_exception(e)
343
344
  else:
344
345
  ClientLogger.log(
@@ -355,7 +356,10 @@ class BaseClient(CoreCommands):
355
356
  b_arr = bytearray()
356
357
  for request in requests:
357
358
  ProtobufCodec.encode_delimited(b_arr, request)
358
- await self._stream.send(b_arr)
359
+ try:
360
+ await self._stream.send(b_arr)
361
+ except (anyio.ClosedResourceError, anyio.EndOfStream):
362
+ raise ClosingError("The communication layer was unexpectedly closed.")
359
363
 
360
364
  def _encode_arg(self, arg: TEncodable) -> bytes:
361
365
  """
@@ -754,6 +758,15 @@ class BaseClient(CoreCommands):
754
758
  self.config.credentials.password = password or ""
755
759
  return response
756
760
 
761
+ async def _refresh_iam_token(self) -> TResult:
762
+ request = CommandRequest()
763
+ request.callback_idx = self._get_callback_index()
764
+ request.refresh_iam_token.CopyFrom(
765
+ RefreshIamToken()
766
+ ) # Empty message, just triggers the refresh
767
+ response = await self._write_request_await_response(request)
768
+ return response
769
+
757
770
 
758
771
  class GlideClusterClient(BaseClient, ClusterCommands):
759
772
  """
glide/py.typed ADDED
File without changes
glide_shared/__init__.py CHANGED
@@ -119,12 +119,14 @@ from .config import (
119
119
  BackoffStrategy,
120
120
  GlideClientConfiguration,
121
121
  GlideClusterClientConfiguration,
122
+ IamAuthConfig,
122
123
  NodeAddress,
123
124
  PeriodicChecksManualInterval,
124
125
  PeriodicChecksStatus,
125
126
  ProtocolVersion,
126
127
  ReadFrom,
127
128
  ServerCredentials,
129
+ ServiceType,
128
130
  TlsAdvancedConfiguration,
129
131
  )
130
132
  from .constants import (
@@ -186,6 +188,8 @@ __all__ = [
186
188
  "BackoffStrategy",
187
189
  "ReadFrom",
188
190
  "ServerCredentials",
191
+ "ServiceType",
192
+ "IamAuthConfig",
189
193
  "NodeAddress",
190
194
  "ProtocolVersion",
191
195
  "PeriodicChecksManualInterval",
@@ -403,6 +403,27 @@ class BaseBatch:
403
403
  """
404
404
  return self.append_command(RequestType.ConfigResetStat, [])
405
405
 
406
+ def move(self: TBatch, key: TEncodable, db_index: int) -> "TBatch":
407
+ """
408
+ Move `key` from the currently selected database to the database specified by `db_index`.
409
+
410
+ Note:
411
+ For cluster mode move command is supported since Valkey 9.0.0
412
+
413
+ See [valkey.io](https://valkey.io/commands/move/) for more details.
414
+
415
+ Args:
416
+ key (TEncodable): The key to move.
417
+ db_index (int): The index of the database to move `key` to.
418
+
419
+ Commands response:
420
+ bool: True if `key` was moved.
421
+
422
+ False if the `key` already exists in the destination database
423
+ or does not exist in the source database.
424
+ """
425
+ return self.append_command(RequestType.Move, [key, str(db_index)])
426
+
406
427
  def mset(self: TBatch, key_value_map: Mapping[TEncodable, TEncodable]) -> TBatch:
407
428
  """
408
429
  Set multiple keys to multiple values in a single atomic operation.
@@ -5070,7 +5091,7 @@ class BaseBatch:
5070
5091
  args.extend(["VERSION", str(version)])
5071
5092
  if parameters:
5072
5093
  for var in parameters:
5073
- args.extend(str(var))
5094
+ args.append(str(var))
5074
5095
  return self.append_command(RequestType.Lolwut, args)
5075
5096
 
5076
5097
  def random_key(self: TBatch) -> TBatch:
@@ -5754,25 +5775,6 @@ class Batch(BaseBatch):
5754
5775
 
5755
5776
  """
5756
5777
 
5757
- # TODO: add SLAVEOF and all SENTINEL commands
5758
- def move(self, key: TEncodable, db_index: int) -> "Batch":
5759
- """
5760
- Move `key` from the currently selected database to the database specified by `db_index`.
5761
-
5762
- See [valkey.io](https://valkey.io/commands/move/) for more details.
5763
-
5764
- Args:
5765
- key (TEncodable): The key to move.
5766
- db_index (int): The index of the database to move `key` to.
5767
-
5768
- Commands response:
5769
- bool: True if `key` was moved.
5770
-
5771
- False if the `key` already exists in the destination database
5772
- or does not exist in the source database.
5773
- """
5774
- return self.append_command(RequestType.Move, [key, str(db_index)])
5775
-
5776
5778
  def select(self, index: int) -> "Batch":
5777
5779
  """
5778
5780
  Change the currently selected database.
@@ -5883,7 +5885,11 @@ class ClusterBatch(BaseBatch):
5883
5885
  self,
5884
5886
  source: TEncodable,
5885
5887
  destination: TEncodable,
5888
+ # TODO next major release the arguments replace and destinationDB must have their order
5889
+ # swapped to align with the standalone order.
5890
+ # At the moment of the patch release 2.1.1. we can't have a breaking change
5886
5891
  replace: Optional[bool] = None,
5892
+ destinationDB: Optional[int] = None,
5887
5893
  ) -> "ClusterBatch":
5888
5894
  """
5889
5895
  Copies the value stored at the `source` to the `destination` key. When `replace` is True,
@@ -5895,15 +5901,17 @@ class ClusterBatch(BaseBatch):
5895
5901
  source (TEncodable): The key to the source value.
5896
5902
  destination (TEncodable): The key where the value should be copied to.
5897
5903
  replace (Optional[bool]): If the destination key should be removed before copying the value to it.
5898
-
5904
+ destinationDB (Optional[int]): The alternative logical database index for the destination key.
5899
5905
  Command response:
5900
5906
  bool: True if the source was copied.
5901
5907
 
5902
5908
  Otherwise, return False.
5903
5909
 
5904
- Since: Valkey version 6.2.0.
5910
+ Since: Valkey version 9.0.0.
5905
5911
  """
5906
5912
  args = [source, destination]
5913
+ if destinationDB is not None:
5914
+ args.extend(["DB", str(destinationDB)])
5907
5915
  if replace is not None:
5908
5916
  args.append("REPLACE")
5909
5917