redis 5.3.0b5__py3-none-any.whl → 6.0.0b2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. redis/__init__.py +2 -11
  2. redis/_parsers/base.py +14 -2
  3. redis/asyncio/client.py +27 -14
  4. redis/asyncio/cluster.py +85 -59
  5. redis/asyncio/connection.py +76 -23
  6. redis/asyncio/lock.py +26 -5
  7. redis/asyncio/sentinel.py +11 -1
  8. redis/asyncio/utils.py +1 -1
  9. redis/auth/token.py +6 -2
  10. redis/backoff.py +15 -0
  11. redis/client.py +23 -14
  12. redis/cluster.py +112 -48
  13. redis/commands/cluster.py +1 -11
  14. redis/commands/core.py +219 -207
  15. redis/commands/helpers.py +0 -70
  16. redis/commands/redismodules.py +5 -17
  17. redis/commands/search/aggregation.py +3 -1
  18. redis/commands/search/commands.py +41 -14
  19. redis/commands/search/dialect.py +3 -0
  20. redis/commands/search/profile_information.py +14 -0
  21. redis/commands/search/query.py +5 -1
  22. redis/commands/vectorset/__init__.py +46 -0
  23. redis/commands/vectorset/commands.py +367 -0
  24. redis/commands/vectorset/utils.py +94 -0
  25. redis/connection.py +76 -27
  26. redis/exceptions.py +4 -1
  27. redis/lock.py +24 -4
  28. redis/ocsp.py +2 -1
  29. redis/sentinel.py +3 -1
  30. redis/utils.py +114 -1
  31. {redis-5.3.0b5.dist-info → redis-6.0.0b2.dist-info}/METADATA +57 -23
  32. {redis-5.3.0b5.dist-info → redis-6.0.0b2.dist-info}/RECORD +35 -39
  33. {redis-5.3.0b5.dist-info → redis-6.0.0b2.dist-info}/WHEEL +1 -2
  34. redis/commands/graph/__init__.py +0 -263
  35. redis/commands/graph/commands.py +0 -313
  36. redis/commands/graph/edge.py +0 -91
  37. redis/commands/graph/exceptions.py +0 -3
  38. redis/commands/graph/execution_plan.py +0 -211
  39. redis/commands/graph/node.py +0 -88
  40. redis/commands/graph/path.py +0 -78
  41. redis/commands/graph/query_result.py +0 -588
  42. redis-5.3.0b5.dist-info/top_level.txt +0 -1
  43. /redis/commands/search/{indexDefinition.py → index_definition.py} +0 -0
  44. {redis-5.3.0b5.dist-info → redis-6.0.0b2.dist-info/licenses}/LICENSE +0 -0
redis/cluster.py CHANGED
@@ -4,6 +4,7 @@ import sys
4
4
  import threading
5
5
  import time
6
6
  from collections import OrderedDict
7
+ from enum import Enum
7
8
  from typing import Any, Callable, Dict, List, Optional, Tuple, Union
8
9
 
9
10
  from redis._parsers import CommandsParser, Encoder
@@ -13,7 +14,7 @@ from redis.cache import CacheConfig, CacheFactory, CacheFactoryInterface, CacheI
13
14
  from redis.client import CaseInsensitiveDict, PubSub, Redis
14
15
  from redis.commands import READ_COMMANDS, RedisClusterCommands
15
16
  from redis.commands.helpers import list_or_args
16
- from redis.connection import ConnectionPool, DefaultParser, parse_url
17
+ from redis.connection import ConnectionPool, parse_url
17
18
  from redis.crc import REDIS_CLUSTER_HASH_SLOTS, key_slot
18
19
  from redis.event import (
19
20
  AfterPooledConnectionsInstantiationEvent,
@@ -24,12 +25,10 @@ from redis.event import (
24
25
  from redis.exceptions import (
25
26
  AskError,
26
27
  AuthenticationError,
27
- ClusterCrossSlotError,
28
28
  ClusterDownError,
29
29
  ClusterError,
30
30
  ConnectionError,
31
31
  DataError,
32
- MasterDownError,
33
32
  MovedError,
34
33
  RedisClusterException,
35
34
  RedisError,
@@ -42,11 +41,13 @@ from redis.lock import Lock
42
41
  from redis.retry import Retry
43
42
  from redis.utils import (
44
43
  HIREDIS_AVAILABLE,
44
+ deprecated_args,
45
45
  dict_merge,
46
46
  list_keys_to_dict,
47
47
  merge_result,
48
48
  safe_str,
49
49
  str_if_bytes,
50
+ truncate_text,
50
51
  )
51
52
 
52
53
 
@@ -54,10 +55,13 @@ def get_node_name(host: str, port: Union[str, int]) -> str:
54
55
  return f"{host}:{port}"
55
56
 
56
57
 
58
+ @deprecated_args(
59
+ allowed_args=["redis_node"],
60
+ reason="Use get_connection(redis_node) instead",
61
+ version="5.0.3",
62
+ )
57
63
  def get_connection(redis_node, *args, **options):
58
- return redis_node.connection or redis_node.connection_pool.get_connection(
59
- args[0], **options
60
- )
64
+ return redis_node.connection or redis_node.connection_pool.get_connection()
61
65
 
62
66
 
63
67
  def parse_scan_result(command, res, **options):
@@ -193,20 +197,6 @@ def cleanup_kwargs(**kwargs):
193
197
  return connection_kwargs
194
198
 
195
199
 
196
- class ClusterParser(DefaultParser):
197
- EXCEPTION_CLASSES = dict_merge(
198
- DefaultParser.EXCEPTION_CLASSES,
199
- {
200
- "ASK": AskError,
201
- "TRYAGAIN": TryAgainError,
202
- "MOVED": MovedError,
203
- "CLUSTERDOWN": ClusterDownError,
204
- "CROSSSLOT": ClusterCrossSlotError,
205
- "MASTERDOWN": MasterDownError,
206
- },
207
- )
208
-
209
-
210
200
  class AbstractRedisCluster:
211
201
  RedisClusterRequestTTL = 16
212
202
 
@@ -300,7 +290,6 @@ class AbstractRedisCluster:
300
290
  "TFUNCTION LIST",
301
291
  "TFCALL",
302
292
  "TFCALLASYNC",
303
- "GRAPH.CONFIG",
304
293
  "LATENCY HISTORY",
305
294
  "LATENCY LATEST",
306
295
  "LATENCY RESET",
@@ -320,7 +309,6 @@ class AbstractRedisCluster:
320
309
  "FUNCTION LIST",
321
310
  "FUNCTION LOAD",
322
311
  "FUNCTION RESTORE",
323
- "REDISGEARS_2.REFRESHCLUSTER",
324
312
  "SCAN",
325
313
  "SCRIPT EXISTS",
326
314
  "SCRIPT FLUSH",
@@ -496,6 +484,11 @@ class RedisCluster(AbstractRedisCluster, RedisClusterCommands):
496
484
  """
497
485
  return cls(url=url, **kwargs)
498
486
 
487
+ @deprecated_args(
488
+ args_to_warn=["read_from_replicas"],
489
+ reason="Please configure the 'load_balancing_strategy' instead",
490
+ version="5.0.3",
491
+ )
499
492
  def __init__(
500
493
  self,
501
494
  host: Optional[str] = None,
@@ -506,6 +499,7 @@ class RedisCluster(AbstractRedisCluster, RedisClusterCommands):
506
499
  require_full_coverage: bool = False,
507
500
  reinitialize_steps: int = 5,
508
501
  read_from_replicas: bool = False,
502
+ load_balancing_strategy: Optional["LoadBalancingStrategy"] = None,
509
503
  dynamic_startup_nodes: bool = True,
510
504
  url: Optional[str] = None,
511
505
  address_remap: Optional[Callable[[Tuple[str, int]], Tuple[str, int]]] = None,
@@ -534,11 +528,16 @@ class RedisCluster(AbstractRedisCluster, RedisClusterCommands):
534
528
  cluster client. If not all slots are covered, RedisClusterException
535
529
  will be thrown.
536
530
  :param read_from_replicas:
531
+ @deprecated - please use load_balancing_strategy instead
537
532
  Enable read from replicas in READONLY mode. You can read possibly
538
533
  stale data.
539
534
  When set to true, read commands will be assigned between the
540
535
  primary and its replications in a Round-Robin manner.
541
- :param dynamic_startup_nodes:
536
+ :param load_balancing_strategy:
537
+ Enable read from replicas in READONLY mode and defines the load balancing
538
+ strategy that will be used for cluster node selection.
539
+ The data read from replicas is eventually consistent with the data in primary nodes.
540
+ :param dynamic_startup_nodes:
542
541
  Set the RedisCluster's startup nodes to all of the discovered nodes.
543
542
  If true (default value), the cluster's discovered nodes will be used to
544
543
  determine the cluster nodes-slots mapping in the next topology refresh.
@@ -643,6 +642,7 @@ class RedisCluster(AbstractRedisCluster, RedisClusterCommands):
643
642
  self.command_flags = self.__class__.COMMAND_FLAGS.copy()
644
643
  self.node_flags = self.__class__.NODE_FLAGS.copy()
645
644
  self.read_from_replicas = read_from_replicas
645
+ self.load_balancing_strategy = load_balancing_strategy
646
646
  self.reinitialize_counter = 0
647
647
  self.reinitialize_steps = reinitialize_steps
648
648
  if event_dispatcher is None:
@@ -676,7 +676,10 @@ class RedisCluster(AbstractRedisCluster, RedisClusterCommands):
676
676
  self.close()
677
677
 
678
678
  def __del__(self):
679
- self.close()
679
+ try:
680
+ self.close()
681
+ except Exception:
682
+ pass
680
683
 
681
684
  def disconnect_connection_pools(self):
682
685
  for node in self.get_nodes():
@@ -692,10 +695,9 @@ class RedisCluster(AbstractRedisCluster, RedisClusterCommands):
692
695
  Initialize the connection, authenticate and select a database and send
693
696
  READONLY if it is set during object initialization.
694
697
  """
695
- connection.set_parser(ClusterParser)
696
698
  connection.on_connect()
697
699
 
698
- if self.read_from_replicas:
700
+ if self.read_from_replicas or self.load_balancing_strategy:
699
701
  # Sending READONLY command to server to configure connection as
700
702
  # readonly. Since each cluster node may change its server type due
701
703
  # to a failover, we should establish a READONLY connection
@@ -822,6 +824,7 @@ class RedisCluster(AbstractRedisCluster, RedisClusterCommands):
822
824
  cluster_response_callbacks=self.cluster_response_callbacks,
823
825
  cluster_error_retry_attempts=self.cluster_error_retry_attempts,
824
826
  read_from_replicas=self.read_from_replicas,
827
+ load_balancing_strategy=self.load_balancing_strategy,
825
828
  reinitialize_steps=self.reinitialize_steps,
826
829
  lock=self._lock,
827
830
  )
@@ -835,6 +838,7 @@ class RedisCluster(AbstractRedisCluster, RedisClusterCommands):
835
838
  blocking_timeout=None,
836
839
  lock_class=None,
837
840
  thread_local=True,
841
+ raise_on_release_error: bool = True,
838
842
  ):
839
843
  """
840
844
  Return a new Lock object using key ``name`` that mimics
@@ -881,6 +885,11 @@ class RedisCluster(AbstractRedisCluster, RedisClusterCommands):
881
885
  thread-1 would see the token value as "xyz" and would be
882
886
  able to successfully release the thread-2's lock.
883
887
 
888
+ ``raise_on_release_error`` indicates whether to raise an exception when
889
+ the lock is no longer owned when exiting the context manager. By default,
890
+ this is True, meaning an exception will be raised. If False, the warning
891
+ will be logged and the exception will be suppressed.
892
+
884
893
  In some use cases it's necessary to disable thread local storage. For
885
894
  example, if you have code where one thread acquires a lock and passes
886
895
  that lock instance to a worker thread to release later. If thread
@@ -898,6 +907,7 @@ class RedisCluster(AbstractRedisCluster, RedisClusterCommands):
898
907
  blocking=blocking,
899
908
  blocking_timeout=blocking_timeout,
900
909
  thread_local=thread_local,
910
+ raise_on_release_error=raise_on_release_error,
901
911
  )
902
912
 
903
913
  def set_response_callback(self, command, callback):
@@ -939,7 +949,9 @@ class RedisCluster(AbstractRedisCluster, RedisClusterCommands):
939
949
  # get the node that holds the key's slot
940
950
  slot = self.determine_slot(*args)
941
951
  node = self.nodes_manager.get_node_from_slot(
942
- slot, self.read_from_replicas and command in READ_COMMANDS
952
+ slot,
953
+ self.read_from_replicas and command in READ_COMMANDS,
954
+ self.load_balancing_strategy if command in READ_COMMANDS else None,
943
955
  )
944
956
  return [node]
945
957
 
@@ -1163,12 +1175,16 @@ class RedisCluster(AbstractRedisCluster, RedisClusterCommands):
1163
1175
  # refresh the target node
1164
1176
  slot = self.determine_slot(*args)
1165
1177
  target_node = self.nodes_manager.get_node_from_slot(
1166
- slot, self.read_from_replicas and command in READ_COMMANDS
1178
+ slot,
1179
+ self.read_from_replicas and command in READ_COMMANDS,
1180
+ self.load_balancing_strategy
1181
+ if command in READ_COMMANDS
1182
+ else None,
1167
1183
  )
1168
1184
  moved = False
1169
1185
 
1170
1186
  redis_node = self.get_redis_connection(target_node)
1171
- connection = get_connection(redis_node, *args, **kwargs)
1187
+ connection = get_connection(redis_node)
1172
1188
  if asking:
1173
1189
  connection.send_command("ASKING")
1174
1190
  redis_node.parse_response(connection, "ASKING", **kwargs)
@@ -1312,6 +1328,12 @@ class ClusterNode:
1312
1328
  self.redis_connection.close()
1313
1329
 
1314
1330
 
1331
+ class LoadBalancingStrategy(Enum):
1332
+ ROUND_ROBIN = "round_robin"
1333
+ ROUND_ROBIN_REPLICAS = "round_robin_replicas"
1334
+ RANDOM_REPLICA = "random_replica"
1335
+
1336
+
1315
1337
  class LoadBalancer:
1316
1338
  """
1317
1339
  Round-Robin Load Balancing
@@ -1321,15 +1343,38 @@ class LoadBalancer:
1321
1343
  self.primary_to_idx = {}
1322
1344
  self.start_index = start_index
1323
1345
 
1324
- def get_server_index(self, primary: str, list_size: int) -> int:
1325
- server_index = self.primary_to_idx.setdefault(primary, self.start_index)
1326
- # Update the index
1327
- self.primary_to_idx[primary] = (server_index + 1) % list_size
1328
- return server_index
1346
+ def get_server_index(
1347
+ self,
1348
+ primary: str,
1349
+ list_size: int,
1350
+ load_balancing_strategy: LoadBalancingStrategy = LoadBalancingStrategy.ROUND_ROBIN,
1351
+ ) -> int:
1352
+ if load_balancing_strategy == LoadBalancingStrategy.RANDOM_REPLICA:
1353
+ return self._get_random_replica_index(list_size)
1354
+ else:
1355
+ return self._get_round_robin_index(
1356
+ primary,
1357
+ list_size,
1358
+ load_balancing_strategy == LoadBalancingStrategy.ROUND_ROBIN_REPLICAS,
1359
+ )
1329
1360
 
1330
1361
  def reset(self) -> None:
1331
1362
  self.primary_to_idx.clear()
1332
1363
 
1364
+ def _get_random_replica_index(self, list_size: int) -> int:
1365
+ return random.randint(1, list_size - 1)
1366
+
1367
+ def _get_round_robin_index(
1368
+ self, primary: str, list_size: int, replicas_only: bool
1369
+ ) -> int:
1370
+ server_index = self.primary_to_idx.setdefault(primary, self.start_index)
1371
+ if replicas_only and server_index == 0:
1372
+ # skip the primary node index
1373
+ server_index = 1
1374
+ # Update the index for the next round
1375
+ self.primary_to_idx[primary] = (server_index + 1) % list_size
1376
+ return server_index
1377
+
1333
1378
 
1334
1379
  class NodesManager:
1335
1380
  def __init__(
@@ -1433,7 +1478,21 @@ class NodesManager:
1433
1478
  # Reset moved_exception
1434
1479
  self._moved_exception = None
1435
1480
 
1436
- def get_node_from_slot(self, slot, read_from_replicas=False, server_type=None):
1481
+ @deprecated_args(
1482
+ args_to_warn=["server_type"],
1483
+ reason=(
1484
+ "In case you need select some load balancing strategy "
1485
+ "that will use replicas, please set it through 'load_balancing_strategy'"
1486
+ ),
1487
+ version="5.0.3",
1488
+ )
1489
+ def get_node_from_slot(
1490
+ self,
1491
+ slot,
1492
+ read_from_replicas=False,
1493
+ load_balancing_strategy=None,
1494
+ server_type=None,
1495
+ ):
1437
1496
  """
1438
1497
  Gets a node that servers this hash slot
1439
1498
  """
@@ -1448,11 +1507,14 @@ class NodesManager:
1448
1507
  f'"require_full_coverage={self._require_full_coverage}"'
1449
1508
  )
1450
1509
 
1451
- if read_from_replicas is True:
1452
- # get the server index in a Round-Robin manner
1510
+ if read_from_replicas is True and load_balancing_strategy is None:
1511
+ load_balancing_strategy = LoadBalancingStrategy.ROUND_ROBIN
1512
+
1513
+ if len(self.slots_cache[slot]) > 1 and load_balancing_strategy:
1514
+ # get the server index using the strategy defined in load_balancing_strategy
1453
1515
  primary_name = self.slots_cache[slot][0].name
1454
1516
  node_idx = self.read_load_balancer.get_server_index(
1455
- primary_name, len(self.slots_cache[slot])
1517
+ primary_name, len(self.slots_cache[slot]), load_balancing_strategy
1456
1518
  )
1457
1519
  elif (
1458
1520
  server_type is None
@@ -1641,7 +1703,7 @@ class NodesManager:
1641
1703
  if len(disagreements) > 5:
1642
1704
  raise RedisClusterException(
1643
1705
  f"startup_nodes could not agree on a valid "
1644
- f'slots cache: {", ".join(disagreements)}'
1706
+ f"slots cache: {', '.join(disagreements)}"
1645
1707
  )
1646
1708
 
1647
1709
  fully_covered = self.check_slots_coverage(tmp_slots)
@@ -1735,7 +1797,7 @@ class ClusterPubSub(PubSub):
1735
1797
  first command execution. The node will be determined by:
1736
1798
  1. Hashing the channel name in the request to find its keyslot
1737
1799
  2. Selecting a node that handles the keyslot: If read_from_replicas is
1738
- set to true, a replica can be selected.
1800
+ set to true or load_balancing_strategy is set, a replica can be selected.
1739
1801
 
1740
1802
  :type redis_cluster: RedisCluster
1741
1803
  :type node: ClusterNode
@@ -1831,7 +1893,9 @@ class ClusterPubSub(PubSub):
1831
1893
  channel = args[1]
1832
1894
  slot = self.cluster.keyslot(channel)
1833
1895
  node = self.cluster.nodes_manager.get_node_from_slot(
1834
- slot, self.cluster.read_from_replicas
1896
+ slot,
1897
+ self.cluster.read_from_replicas,
1898
+ self.cluster.load_balancing_strategy,
1835
1899
  )
1836
1900
  else:
1837
1901
  # Get a random node
@@ -1839,9 +1903,7 @@ class ClusterPubSub(PubSub):
1839
1903
  self.node = node
1840
1904
  redis_connection = self.cluster.get_redis_connection(node)
1841
1905
  self.connection_pool = redis_connection.connection_pool
1842
- self.connection = self.connection_pool.get_connection(
1843
- "pubsub", self.shard_hint
1844
- )
1906
+ self.connection = self.connection_pool.get_connection()
1845
1907
  # register a callback that re-subscribes to any channels we
1846
1908
  # were listening to when we were disconnected
1847
1909
  self.connection.register_connect_callback(self.on_connect)
@@ -1976,6 +2038,7 @@ class ClusterPipeline(RedisCluster):
1976
2038
  cluster_response_callbacks: Optional[Dict[str, Callable]] = None,
1977
2039
  startup_nodes: Optional[List["ClusterNode"]] = None,
1978
2040
  read_from_replicas: bool = False,
2041
+ load_balancing_strategy: Optional[LoadBalancingStrategy] = None,
1979
2042
  cluster_error_retry_attempts: int = 3,
1980
2043
  reinitialize_steps: int = 5,
1981
2044
  lock=None,
@@ -1991,6 +2054,7 @@ class ClusterPipeline(RedisCluster):
1991
2054
  )
1992
2055
  self.startup_nodes = startup_nodes if startup_nodes else []
1993
2056
  self.read_from_replicas = read_from_replicas
2057
+ self.load_balancing_strategy = load_balancing_strategy
1994
2058
  self.command_flags = self.__class__.COMMAND_FLAGS.copy()
1995
2059
  self.cluster_response_callbacks = cluster_response_callbacks
1996
2060
  self.cluster_error_retry_attempts = cluster_error_retry_attempts
@@ -2062,7 +2126,7 @@ class ClusterPipeline(RedisCluster):
2062
2126
  """
2063
2127
  cmd = " ".join(map(safe_str, command))
2064
2128
  msg = (
2065
- f"Command # {number} ({cmd}) of pipeline "
2129
+ f"Command # {number} ({truncate_text(cmd)}) of pipeline "
2066
2130
  f"caused error: {exception.args[0]}"
2067
2131
  )
2068
2132
  exception.args = (msg,) + exception.args[1:]
@@ -2137,7 +2201,7 @@ class ClusterPipeline(RedisCluster):
2137
2201
  raise_on_error=raise_on_error,
2138
2202
  allow_redirections=allow_redirections,
2139
2203
  )
2140
- except (ClusterDownError, ConnectionError) as e:
2204
+ except RedisCluster.ERRORS_ALLOW_RETRY as e:
2141
2205
  if retry_attempts > 0:
2142
2206
  # Try again with the new cluster setup. All other errors
2143
2207
  # should be raised.
@@ -2201,8 +2265,8 @@ class ClusterPipeline(RedisCluster):
2201
2265
  if node_name not in nodes:
2202
2266
  redis_node = self.get_redis_connection(node)
2203
2267
  try:
2204
- connection = get_connection(redis_node, c.args)
2205
- except ConnectionError:
2268
+ connection = get_connection(redis_node)
2269
+ except (ConnectionError, TimeoutError):
2206
2270
  for n in nodes.values():
2207
2271
  n.connection_pool.release(n.connection)
2208
2272
  # Connection retries are being handled in the node's
redis/commands/cluster.py CHANGED
@@ -31,13 +31,11 @@ from .core import (
31
31
  AsyncACLCommands,
32
32
  AsyncDataAccessCommands,
33
33
  AsyncFunctionCommands,
34
- AsyncGearsCommands,
35
34
  AsyncManagementCommands,
36
35
  AsyncModuleCommands,
37
36
  AsyncScriptCommands,
38
37
  DataAccessCommands,
39
38
  FunctionCommands,
40
- GearsCommands,
41
39
  ManagementCommands,
42
40
  ModuleCommands,
43
41
  PubSubCommands,
@@ -595,7 +593,7 @@ class ClusterManagementCommands(ManagementCommands):
595
593
  "CLUSTER SETSLOT", slot_id, state, node_id, target_nodes=target_node
596
594
  )
597
595
  elif state.upper() == "STABLE":
598
- raise RedisError('For "stable" state please use ' "cluster_setslot_stable")
596
+ raise RedisError('For "stable" state please use cluster_setslot_stable')
599
597
  else:
600
598
  raise RedisError(f"Invalid slot state: {state}")
601
599
 
@@ -693,12 +691,6 @@ class ClusterManagementCommands(ManagementCommands):
693
691
  self.read_from_replicas = False
694
692
  return self.execute_command("READWRITE", target_nodes=target_nodes)
695
693
 
696
- def gears_refresh_cluster(self, **kwargs) -> ResponseT:
697
- """
698
- On an OSS cluster, before executing any gears function, you must call this command. # noqa
699
- """
700
- return self.execute_command("REDISGEARS_2.REFRESHCLUSTER", **kwargs)
701
-
702
694
 
703
695
  class AsyncClusterManagementCommands(
704
696
  ClusterManagementCommands, AsyncManagementCommands
@@ -874,7 +866,6 @@ class RedisClusterCommands(
874
866
  ClusterDataAccessCommands,
875
867
  ScriptCommands,
876
868
  FunctionCommands,
877
- GearsCommands,
878
869
  ModuleCommands,
879
870
  RedisModuleCommands,
880
871
  ):
@@ -905,7 +896,6 @@ class AsyncRedisClusterCommands(
905
896
  AsyncClusterDataAccessCommands,
906
897
  AsyncScriptCommands,
907
898
  AsyncFunctionCommands,
908
- AsyncGearsCommands,
909
899
  AsyncModuleCommands,
910
900
  AsyncRedisModuleCommands,
911
901
  ):