redis 6.0.0b1__tar.gz → 6.0.0b2__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.
Files changed (150) hide show
  1. {redis-6.0.0b1 → redis-6.0.0b2}/PKG-INFO +1 -1
  2. {redis-6.0.0b1 → redis-6.0.0b2}/redis/__init__.py +1 -1
  3. {redis-6.0.0b1 → redis-6.0.0b2}/redis/asyncio/client.py +8 -3
  4. {redis-6.0.0b1 → redis-6.0.0b2}/redis/asyncio/cluster.py +7 -4
  5. {redis-6.0.0b1 → redis-6.0.0b2}/redis/asyncio/connection.py +36 -12
  6. {redis-6.0.0b1 → redis-6.0.0b2}/redis/asyncio/sentinel.py +2 -0
  7. {redis-6.0.0b1 → redis-6.0.0b2}/redis/client.py +4 -2
  8. {redis-6.0.0b1 → redis-6.0.0b2}/redis/cluster.py +3 -1
  9. {redis-6.0.0b1 → redis-6.0.0b2}/redis/commands/core.py +1 -1
  10. {redis-6.0.0b1 → redis-6.0.0b2}/redis/commands/redismodules.py +8 -0
  11. redis-6.0.0b2/redis/commands/vectorset/__init__.py +46 -0
  12. redis-6.0.0b2/redis/commands/vectorset/commands.py +367 -0
  13. redis-6.0.0b2/redis/commands/vectorset/utils.py +94 -0
  14. {redis-6.0.0b1 → redis-6.0.0b2}/redis/connection.py +39 -8
  15. {redis-6.0.0b1 → redis-6.0.0b2}/redis/sentinel.py +2 -0
  16. {redis-6.0.0b1 → redis-6.0.0b2}/redis/utils.py +7 -0
  17. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_asyncio/test_cluster.py +19 -0
  18. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_asyncio/test_pipeline.py +16 -0
  19. redis-6.0.0b2/tests/test_asyncio/test_vsets.py +858 -0
  20. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_cluster.py +19 -0
  21. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_pipeline.py +16 -0
  22. redis-6.0.0b2/tests/test_vsets.py +856 -0
  23. {redis-6.0.0b1 → redis-6.0.0b2}/.gitignore +0 -0
  24. {redis-6.0.0b1 → redis-6.0.0b2}/LICENSE +0 -0
  25. {redis-6.0.0b1 → redis-6.0.0b2}/README.md +0 -0
  26. {redis-6.0.0b1 → redis-6.0.0b2}/dev_requirements.txt +0 -0
  27. {redis-6.0.0b1 → redis-6.0.0b2}/pyproject.toml +0 -0
  28. {redis-6.0.0b1 → redis-6.0.0b2}/redis/_parsers/__init__.py +0 -0
  29. {redis-6.0.0b1 → redis-6.0.0b2}/redis/_parsers/base.py +0 -0
  30. {redis-6.0.0b1 → redis-6.0.0b2}/redis/_parsers/commands.py +0 -0
  31. {redis-6.0.0b1 → redis-6.0.0b2}/redis/_parsers/encoders.py +0 -0
  32. {redis-6.0.0b1 → redis-6.0.0b2}/redis/_parsers/helpers.py +0 -0
  33. {redis-6.0.0b1 → redis-6.0.0b2}/redis/_parsers/hiredis.py +0 -0
  34. {redis-6.0.0b1 → redis-6.0.0b2}/redis/_parsers/resp2.py +0 -0
  35. {redis-6.0.0b1 → redis-6.0.0b2}/redis/_parsers/resp3.py +0 -0
  36. {redis-6.0.0b1 → redis-6.0.0b2}/redis/_parsers/socket.py +0 -0
  37. {redis-6.0.0b1 → redis-6.0.0b2}/redis/asyncio/__init__.py +0 -0
  38. {redis-6.0.0b1 → redis-6.0.0b2}/redis/asyncio/lock.py +0 -0
  39. {redis-6.0.0b1 → redis-6.0.0b2}/redis/asyncio/retry.py +0 -0
  40. {redis-6.0.0b1 → redis-6.0.0b2}/redis/asyncio/utils.py +0 -0
  41. {redis-6.0.0b1 → redis-6.0.0b2}/redis/auth/__init__.py +0 -0
  42. {redis-6.0.0b1 → redis-6.0.0b2}/redis/auth/err.py +0 -0
  43. {redis-6.0.0b1 → redis-6.0.0b2}/redis/auth/idp.py +0 -0
  44. {redis-6.0.0b1 → redis-6.0.0b2}/redis/auth/token.py +0 -0
  45. {redis-6.0.0b1 → redis-6.0.0b2}/redis/auth/token_manager.py +0 -0
  46. {redis-6.0.0b1 → redis-6.0.0b2}/redis/backoff.py +0 -0
  47. {redis-6.0.0b1 → redis-6.0.0b2}/redis/cache.py +0 -0
  48. {redis-6.0.0b1 → redis-6.0.0b2}/redis/commands/__init__.py +0 -0
  49. {redis-6.0.0b1 → redis-6.0.0b2}/redis/commands/bf/__init__.py +0 -0
  50. {redis-6.0.0b1 → redis-6.0.0b2}/redis/commands/bf/commands.py +0 -0
  51. {redis-6.0.0b1 → redis-6.0.0b2}/redis/commands/bf/info.py +0 -0
  52. {redis-6.0.0b1 → redis-6.0.0b2}/redis/commands/cluster.py +0 -0
  53. {redis-6.0.0b1 → redis-6.0.0b2}/redis/commands/helpers.py +0 -0
  54. {redis-6.0.0b1 → redis-6.0.0b2}/redis/commands/json/__init__.py +0 -0
  55. {redis-6.0.0b1 → redis-6.0.0b2}/redis/commands/json/_util.py +0 -0
  56. {redis-6.0.0b1 → redis-6.0.0b2}/redis/commands/json/commands.py +0 -0
  57. {redis-6.0.0b1 → redis-6.0.0b2}/redis/commands/json/decoders.py +0 -0
  58. {redis-6.0.0b1 → redis-6.0.0b2}/redis/commands/json/path.py +0 -0
  59. {redis-6.0.0b1 → redis-6.0.0b2}/redis/commands/search/__init__.py +0 -0
  60. {redis-6.0.0b1 → redis-6.0.0b2}/redis/commands/search/_util.py +0 -0
  61. {redis-6.0.0b1 → redis-6.0.0b2}/redis/commands/search/aggregation.py +0 -0
  62. {redis-6.0.0b1 → redis-6.0.0b2}/redis/commands/search/commands.py +0 -0
  63. {redis-6.0.0b1 → redis-6.0.0b2}/redis/commands/search/dialect.py +0 -0
  64. {redis-6.0.0b1 → redis-6.0.0b2}/redis/commands/search/document.py +0 -0
  65. {redis-6.0.0b1 → redis-6.0.0b2}/redis/commands/search/field.py +0 -0
  66. {redis-6.0.0b1 → redis-6.0.0b2}/redis/commands/search/index_definition.py +0 -0
  67. {redis-6.0.0b1 → redis-6.0.0b2}/redis/commands/search/profile_information.py +0 -0
  68. {redis-6.0.0b1 → redis-6.0.0b2}/redis/commands/search/query.py +0 -0
  69. {redis-6.0.0b1 → redis-6.0.0b2}/redis/commands/search/querystring.py +0 -0
  70. {redis-6.0.0b1 → redis-6.0.0b2}/redis/commands/search/reducers.py +0 -0
  71. {redis-6.0.0b1 → redis-6.0.0b2}/redis/commands/search/result.py +0 -0
  72. {redis-6.0.0b1 → redis-6.0.0b2}/redis/commands/search/suggestion.py +0 -0
  73. {redis-6.0.0b1 → redis-6.0.0b2}/redis/commands/sentinel.py +0 -0
  74. {redis-6.0.0b1 → redis-6.0.0b2}/redis/commands/timeseries/__init__.py +0 -0
  75. {redis-6.0.0b1 → redis-6.0.0b2}/redis/commands/timeseries/commands.py +0 -0
  76. {redis-6.0.0b1 → redis-6.0.0b2}/redis/commands/timeseries/info.py +0 -0
  77. {redis-6.0.0b1 → redis-6.0.0b2}/redis/commands/timeseries/utils.py +0 -0
  78. {redis-6.0.0b1 → redis-6.0.0b2}/redis/crc.py +0 -0
  79. {redis-6.0.0b1 → redis-6.0.0b2}/redis/credentials.py +0 -0
  80. {redis-6.0.0b1 → redis-6.0.0b2}/redis/event.py +0 -0
  81. {redis-6.0.0b1 → redis-6.0.0b2}/redis/exceptions.py +0 -0
  82. {redis-6.0.0b1 → redis-6.0.0b2}/redis/lock.py +0 -0
  83. {redis-6.0.0b1 → redis-6.0.0b2}/redis/ocsp.py +0 -0
  84. {redis-6.0.0b1 → redis-6.0.0b2}/redis/py.typed +0 -0
  85. {redis-6.0.0b1 → redis-6.0.0b2}/redis/retry.py +0 -0
  86. {redis-6.0.0b1 → redis-6.0.0b2}/redis/typing.py +0 -0
  87. {redis-6.0.0b1 → redis-6.0.0b2}/tests/__init__.py +0 -0
  88. {redis-6.0.0b1 → redis-6.0.0b2}/tests/conftest.py +0 -0
  89. {redis-6.0.0b1 → redis-6.0.0b2}/tests/entraid_utils.py +0 -0
  90. {redis-6.0.0b1 → redis-6.0.0b2}/tests/mocks.py +0 -0
  91. {redis-6.0.0b1 → redis-6.0.0b2}/tests/ssl_utils.py +0 -0
  92. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_asyncio/__init__.py +0 -0
  93. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_asyncio/compat.py +0 -0
  94. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_asyncio/conftest.py +0 -0
  95. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_asyncio/mocks.py +0 -0
  96. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_asyncio/test_bloom.py +0 -0
  97. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_asyncio/test_commands.py +0 -0
  98. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_asyncio/test_connect.py +0 -0
  99. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_asyncio/test_connection.py +0 -0
  100. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_asyncio/test_connection_pool.py +0 -0
  101. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_asyncio/test_credentials.py +0 -0
  102. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_asyncio/test_cwe_404.py +0 -0
  103. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_asyncio/test_encoding.py +0 -0
  104. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_asyncio/test_hash.py +0 -0
  105. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_asyncio/test_json.py +0 -0
  106. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_asyncio/test_lock.py +0 -0
  107. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_asyncio/test_monitor.py +0 -0
  108. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_asyncio/test_pubsub.py +0 -0
  109. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_asyncio/test_retry.py +0 -0
  110. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_asyncio/test_scripting.py +0 -0
  111. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_asyncio/test_search.py +0 -0
  112. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_asyncio/test_sentinel.py +0 -0
  113. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_asyncio/test_sentinel_managed_connection.py +0 -0
  114. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_asyncio/test_timeseries.py +0 -0
  115. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_asyncio/test_utils.py +0 -0
  116. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_asyncio/testdata/jsontestdata.py +0 -0
  117. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_asyncio/testdata/titles.csv +0 -0
  118. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_asyncio/testdata/will_play_text.csv.bz2 +0 -0
  119. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_auth/__init__.py +0 -0
  120. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_auth/test_token.py +0 -0
  121. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_auth/test_token_manager.py +0 -0
  122. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_backoff.py +0 -0
  123. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_bloom.py +0 -0
  124. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_cache.py +0 -0
  125. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_command_parser.py +0 -0
  126. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_commands.py +0 -0
  127. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_connect.py +0 -0
  128. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_connection.py +0 -0
  129. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_connection_pool.py +0 -0
  130. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_credentials.py +0 -0
  131. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_encoding.py +0 -0
  132. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_function.py +0 -0
  133. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_hash.py +0 -0
  134. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_helpers.py +0 -0
  135. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_json.py +0 -0
  136. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_lock.py +0 -0
  137. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_monitor.py +0 -0
  138. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_multiprocessing.py +0 -0
  139. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_parsers/test_helpers.py +0 -0
  140. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_pubsub.py +0 -0
  141. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_retry.py +0 -0
  142. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_scripting.py +0 -0
  143. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_search.py +0 -0
  144. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_sentinel.py +0 -0
  145. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_ssl.py +0 -0
  146. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_timeseries.py +0 -0
  147. {redis-6.0.0b1 → redis-6.0.0b2}/tests/test_utils.py +0 -0
  148. {redis-6.0.0b1 → redis-6.0.0b2}/tests/testdata/jsontestdata.py +0 -0
  149. {redis-6.0.0b1 → redis-6.0.0b2}/tests/testdata/titles.csv +0 -0
  150. {redis-6.0.0b1 → redis-6.0.0b2}/tests/testdata/will_play_text.csv.bz2 +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: redis
3
- Version: 6.0.0b1
3
+ Version: 6.0.0b2
4
4
  Summary: Python client for Redis database and key-value store
5
5
  Project-URL: Changes, https://github.com/redis/redis-py/releases
6
6
  Project-URL: Code, https://github.com/redis/redis-py
@@ -42,7 +42,7 @@ def int_or_str(value):
42
42
  return value
43
43
 
44
44
 
45
- __version__ = "6.0.0b1"
45
+ __version__ = "6.0.0b2"
46
46
  VERSION = tuple(map(int_or_str, __version__.split(".")))
47
47
 
48
48
 
@@ -77,12 +77,14 @@ from redis.utils import (
77
77
  get_lib_version,
78
78
  safe_str,
79
79
  str_if_bytes,
80
+ truncate_text,
80
81
  )
81
82
 
82
83
  if TYPE_CHECKING and SSL_AVAILABLE:
83
- from ssl import TLSVersion
84
+ from ssl import TLSVersion, VerifyMode
84
85
  else:
85
86
  TLSVersion = None
87
+ VerifyMode = None
86
88
 
87
89
  PubSubHandler = Callable[[Dict[str, str]], Awaitable[None]]
88
90
  _KeyT = TypeVar("_KeyT", bound=KeyT)
@@ -227,7 +229,7 @@ class Redis(
227
229
  ssl: bool = False,
228
230
  ssl_keyfile: Optional[str] = None,
229
231
  ssl_certfile: Optional[str] = None,
230
- ssl_cert_reqs: str = "required",
232
+ ssl_cert_reqs: Union[str, VerifyMode] = "required",
231
233
  ssl_ca_certs: Optional[str] = None,
232
234
  ssl_ca_data: Optional[str] = None,
233
235
  ssl_check_hostname: bool = False,
@@ -1513,7 +1515,10 @@ class Pipeline(Redis): # lgtm [py/init-calls-subclass]
1513
1515
  self, exception: Exception, number: int, command: Iterable[object]
1514
1516
  ) -> None:
1515
1517
  cmd = " ".join(map(safe_str, command))
1516
- msg = f"Command # {number} ({cmd}) of pipeline caused error: {exception.args}"
1518
+ msg = (
1519
+ f"Command # {number} ({truncate_text(cmd)}) "
1520
+ "of pipeline caused error: {exception.args}"
1521
+ )
1517
1522
  exception.args = (msg,) + exception.args[1:]
1518
1523
 
1519
1524
  async def parse_response(
@@ -71,12 +71,14 @@ from redis.utils import (
71
71
  get_lib_version,
72
72
  safe_str,
73
73
  str_if_bytes,
74
+ truncate_text,
74
75
  )
75
76
 
76
77
  if SSL_AVAILABLE:
77
- from ssl import TLSVersion
78
+ from ssl import TLSVersion, VerifyMode
78
79
  else:
79
80
  TLSVersion = None
81
+ VerifyMode = None
80
82
 
81
83
  TargetNodesT = TypeVar(
82
84
  "TargetNodesT", str, "ClusterNode", List["ClusterNode"], Dict[Any, "ClusterNode"]
@@ -267,7 +269,7 @@ class RedisCluster(AbstractRedis, AbstractRedisCluster, AsyncRedisClusterCommand
267
269
  ssl: bool = False,
268
270
  ssl_ca_certs: Optional[str] = None,
269
271
  ssl_ca_data: Optional[str] = None,
270
- ssl_cert_reqs: str = "required",
272
+ ssl_cert_reqs: Union[str, VerifyMode] = "required",
271
273
  ssl_certfile: Optional[str] = None,
272
274
  ssl_check_hostname: bool = False,
273
275
  ssl_keyfile: Optional[str] = None,
@@ -1633,8 +1635,9 @@ class ClusterPipeline(AbstractRedis, AbstractRedisCluster, AsyncRedisClusterComm
1633
1635
  if isinstance(result, Exception):
1634
1636
  command = " ".join(map(safe_str, cmd.args))
1635
1637
  msg = (
1636
- f"Command # {cmd.position + 1} ({command}) of pipeline "
1637
- f"caused error: {result.args}"
1638
+ f"Command # {cmd.position + 1} "
1639
+ f"({truncate_text(command)}) "
1640
+ f"of pipeline caused error: {result.args}"
1638
1641
  )
1639
1642
  result.args = (msg,) + result.args[1:]
1640
1643
  raise result
@@ -293,6 +293,9 @@ class AbstractConnection:
293
293
 
294
294
  async def connect(self):
295
295
  """Connects to the Redis server if not already connected"""
296
+ await self.connect_check_health(check_health=True)
297
+
298
+ async def connect_check_health(self, check_health: bool = True):
296
299
  if self.is_connected:
297
300
  return
298
301
  try:
@@ -311,7 +314,7 @@ class AbstractConnection:
311
314
  try:
312
315
  if not self.redis_connect_func:
313
316
  # Use the default on_connect function
314
- await self.on_connect()
317
+ await self.on_connect_check_health(check_health=check_health)
315
318
  else:
316
319
  # Use the passed function redis_connect_func
317
320
  (
@@ -350,6 +353,9 @@ class AbstractConnection:
350
353
 
351
354
  async def on_connect(self) -> None:
352
355
  """Initialize the connection, authenticate and select a database"""
356
+ await self.on_connect_check_health(check_health=True)
357
+
358
+ async def on_connect_check_health(self, check_health: bool = True) -> None:
353
359
  self._parser.on_connect(self)
354
360
  parser = self._parser
355
361
 
@@ -407,7 +413,7 @@ class AbstractConnection:
407
413
  # update cluster exception classes
408
414
  self._parser.EXCEPTION_CLASSES = parser.EXCEPTION_CLASSES
409
415
  self._parser.on_connect(self)
410
- await self.send_command("HELLO", self.protocol)
416
+ await self.send_command("HELLO", self.protocol, check_health=check_health)
411
417
  response = await self.read_response()
412
418
  # if response.get(b"proto") != self.protocol and response.get(
413
419
  # "proto"
@@ -416,18 +422,35 @@ class AbstractConnection:
416
422
 
417
423
  # if a client_name is given, set it
418
424
  if self.client_name:
419
- await self.send_command("CLIENT", "SETNAME", self.client_name)
425
+ await self.send_command(
426
+ "CLIENT",
427
+ "SETNAME",
428
+ self.client_name,
429
+ check_health=check_health,
430
+ )
420
431
  if str_if_bytes(await self.read_response()) != "OK":
421
432
  raise ConnectionError("Error setting client name")
422
433
 
423
434
  # set the library name and version, pipeline for lower startup latency
424
435
  if self.lib_name:
425
- await self.send_command("CLIENT", "SETINFO", "LIB-NAME", self.lib_name)
436
+ await self.send_command(
437
+ "CLIENT",
438
+ "SETINFO",
439
+ "LIB-NAME",
440
+ self.lib_name,
441
+ check_health=check_health,
442
+ )
426
443
  if self.lib_version:
427
- await self.send_command("CLIENT", "SETINFO", "LIB-VER", self.lib_version)
444
+ await self.send_command(
445
+ "CLIENT",
446
+ "SETINFO",
447
+ "LIB-VER",
448
+ self.lib_version,
449
+ check_health=check_health,
450
+ )
428
451
  # if a database is specified, switch to it. Also pipeline this
429
452
  if self.db:
430
- await self.send_command("SELECT", self.db)
453
+ await self.send_command("SELECT", self.db, check_health=check_health)
431
454
 
432
455
  # read responses from pipeline
433
456
  for _ in (sent for sent in (self.lib_name, self.lib_version) if sent):
@@ -489,8 +512,8 @@ class AbstractConnection:
489
512
  self, command: Union[bytes, str, Iterable[bytes]], check_health: bool = True
490
513
  ) -> None:
491
514
  if not self.is_connected:
492
- await self.connect()
493
- elif check_health:
515
+ await self.connect_check_health(check_health=False)
516
+ if check_health:
494
517
  await self.check_health()
495
518
 
496
519
  try:
@@ -768,7 +791,7 @@ class SSLConnection(Connection):
768
791
  self,
769
792
  ssl_keyfile: Optional[str] = None,
770
793
  ssl_certfile: Optional[str] = None,
771
- ssl_cert_reqs: str = "required",
794
+ ssl_cert_reqs: Union[str, ssl.VerifyMode] = "required",
772
795
  ssl_ca_certs: Optional[str] = None,
773
796
  ssl_ca_data: Optional[str] = None,
774
797
  ssl_check_hostname: bool = False,
@@ -842,7 +865,7 @@ class RedisSSLContext:
842
865
  self,
843
866
  keyfile: Optional[str] = None,
844
867
  certfile: Optional[str] = None,
845
- cert_reqs: Optional[str] = None,
868
+ cert_reqs: Optional[Union[str, ssl.VerifyMode]] = None,
846
869
  ca_certs: Optional[str] = None,
847
870
  ca_data: Optional[str] = None,
848
871
  check_hostname: bool = False,
@@ -855,7 +878,7 @@ class RedisSSLContext:
855
878
  self.keyfile = keyfile
856
879
  self.certfile = certfile
857
880
  if cert_reqs is None:
858
- self.cert_reqs = ssl.CERT_NONE
881
+ cert_reqs = ssl.CERT_NONE
859
882
  elif isinstance(cert_reqs, str):
860
883
  CERT_REQS = { # noqa: N806
861
884
  "none": ssl.CERT_NONE,
@@ -866,7 +889,8 @@ class RedisSSLContext:
866
889
  raise RedisError(
867
890
  f"Invalid SSL Certificate Requirements Flag: {cert_reqs}"
868
891
  )
869
- self.cert_reqs = CERT_REQS[cert_reqs]
892
+ cert_reqs = CERT_REQS[cert_reqs]
893
+ self.cert_reqs = cert_reqs
870
894
  self.ca_certs = ca_certs
871
895
  self.ca_data = ca_data
872
896
  self.check_hostname = check_hostname
@@ -326,6 +326,8 @@ class Sentinel(AsyncSentinelCommands):
326
326
  ):
327
327
  """
328
328
  Returns a redis client instance for the ``service_name`` master.
329
+ Sentinel client will detect failover and reconnect Redis clients
330
+ automatically.
329
331
 
330
332
  A :py:class:`~redis.sentinel.SentinelConnectionPool` class is
331
333
  used to retrieve the master's address before establishing a new
@@ -61,6 +61,7 @@ from redis.utils import (
61
61
  get_lib_version,
62
62
  safe_str,
63
63
  str_if_bytes,
64
+ truncate_text,
64
65
  )
65
66
 
66
67
  if TYPE_CHECKING:
@@ -210,7 +211,7 @@ class Redis(RedisModuleCommands, CoreCommands, SentinelCommands):
210
211
  ssl: bool = False,
211
212
  ssl_keyfile: Optional[str] = None,
212
213
  ssl_certfile: Optional[str] = None,
213
- ssl_cert_reqs: str = "required",
214
+ ssl_cert_reqs: Union[str, "ssl.VerifyMode"] = "required",
214
215
  ssl_ca_certs: Optional[str] = None,
215
216
  ssl_ca_path: Optional[str] = None,
216
217
  ssl_ca_data: Optional[str] = None,
@@ -1524,7 +1525,8 @@ class Pipeline(Redis):
1524
1525
  def annotate_exception(self, exception, number, command):
1525
1526
  cmd = " ".join(map(safe_str, command))
1526
1527
  msg = (
1527
- f"Command # {number} ({cmd}) of pipeline caused error: {exception.args[0]}"
1528
+ f"Command # {number} ({truncate_text(cmd)}) of pipeline "
1529
+ f"caused error: {exception.args[0]}"
1528
1530
  )
1529
1531
  exception.args = (msg,) + exception.args[1:]
1530
1532
 
@@ -47,6 +47,7 @@ from redis.utils import (
47
47
  merge_result,
48
48
  safe_str,
49
49
  str_if_bytes,
50
+ truncate_text,
50
51
  )
51
52
 
52
53
 
@@ -2125,7 +2126,8 @@ class ClusterPipeline(RedisCluster):
2125
2126
  """
2126
2127
  cmd = " ".join(map(safe_str, command))
2127
2128
  msg = (
2128
- f"Command # {number} ({cmd}) of pipeline caused error: {exception.args[0]}"
2129
+ f"Command # {number} ({truncate_text(cmd)}) of pipeline "
2130
+ f"caused error: {exception.args[0]}"
2129
2131
  )
2130
2132
  exception.args = (msg,) + exception.args[1:]
2131
2133
 
@@ -6556,7 +6556,7 @@ class FunctionCommands:
6556
6556
  This is a read-only variant of the FCALL command that cannot
6557
6557
  execute commands that modify data.
6558
6558
 
6559
- For more information see https://redis.io/commands/fcal_ro
6559
+ For more information see https://redis.io/commands/fcall_ro
6560
6560
  """
6561
6561
  return self._fcall("FCALL_RO", function, numkeys, *keys_and_args)
6562
6562
 
@@ -72,6 +72,14 @@ class RedisModuleCommands:
72
72
  tdigest = TDigestBloom(client=self)
73
73
  return tdigest
74
74
 
75
+ def vset(self):
76
+ """Access the VectorSet commands namespace."""
77
+
78
+ from .vectorset import VectorSet
79
+
80
+ vset = VectorSet(client=self)
81
+ return vset
82
+
75
83
 
76
84
  class AsyncRedisModuleCommands(RedisModuleCommands):
77
85
  def ft(self, index_name="idx"):
@@ -0,0 +1,46 @@
1
+ import json
2
+
3
+ from redis._parsers.helpers import pairs_to_dict
4
+ from redis.commands.vectorset.utils import (
5
+ parse_vemb_result,
6
+ parse_vlinks_result,
7
+ parse_vsim_result,
8
+ )
9
+
10
+ from ..helpers import get_protocol_version
11
+ from .commands import (
12
+ VEMB_CMD,
13
+ VGETATTR_CMD,
14
+ VINFO_CMD,
15
+ VLINKS_CMD,
16
+ VSIM_CMD,
17
+ VectorSetCommands,
18
+ )
19
+
20
+
21
+ class VectorSet(VectorSetCommands):
22
+ def __init__(self, client, **kwargs):
23
+ """Create a new VectorSet client."""
24
+ # Set the module commands' callbacks
25
+ self._MODULE_CALLBACKS = {
26
+ VEMB_CMD: parse_vemb_result,
27
+ VGETATTR_CMD: lambda r: r and json.loads(r) or None,
28
+ }
29
+
30
+ self._RESP2_MODULE_CALLBACKS = {
31
+ VINFO_CMD: lambda r: r and pairs_to_dict(r) or None,
32
+ VSIM_CMD: parse_vsim_result,
33
+ VLINKS_CMD: parse_vlinks_result,
34
+ }
35
+ self._RESP3_MODULE_CALLBACKS = {}
36
+
37
+ self.client = client
38
+ self.execute_command = client.execute_command
39
+
40
+ if get_protocol_version(self.client) in ["3", 3]:
41
+ self._MODULE_CALLBACKS.update(self._RESP3_MODULE_CALLBACKS)
42
+ else:
43
+ self._MODULE_CALLBACKS.update(self._RESP2_MODULE_CALLBACKS)
44
+
45
+ for k, v in self._MODULE_CALLBACKS.items():
46
+ self.client.set_response_callback(k, v)