redis 5.3.0b4__tar.gz → 5.3.0b5__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 (159) hide show
  1. {redis-5.3.0b4/redis.egg-info → redis-5.3.0b5}/PKG-INFO +1 -1
  2. {redis-5.3.0b4 → redis-5.3.0b5}/redis/asyncio/client.py +1 -1
  3. {redis-5.3.0b4 → redis-5.3.0b5}/redis/client.py +59 -45
  4. {redis-5.3.0b4 → redis-5.3.0b5}/redis/cluster.py +3 -3
  5. {redis-5.3.0b4 → redis-5.3.0b5}/redis/connection.py +11 -4
  6. {redis-5.3.0b4 → redis-5.3.0b5}/redis/typing.py +1 -1
  7. {redis-5.3.0b4 → redis-5.3.0b5/redis.egg-info}/PKG-INFO +1 -1
  8. {redis-5.3.0b4 → redis-5.3.0b5}/setup.py +1 -1
  9. {redis-5.3.0b4 → redis-5.3.0b5}/tests/conftest.py +62 -37
  10. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_asyncio/conftest.py +61 -36
  11. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_asyncio/test_connection.py +14 -16
  12. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_auth/test_token_manager.py +15 -21
  13. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_commands.py +1 -1
  14. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_connection.py +10 -15
  15. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_connection_pool.py +24 -4
  16. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_multiprocessing.py +4 -0
  17. {redis-5.3.0b4 → redis-5.3.0b5}/INSTALL +0 -0
  18. {redis-5.3.0b4 → redis-5.3.0b5}/LICENSE +0 -0
  19. {redis-5.3.0b4 → redis-5.3.0b5}/MANIFEST.in +0 -0
  20. {redis-5.3.0b4 → redis-5.3.0b5}/README.md +0 -0
  21. {redis-5.3.0b4 → redis-5.3.0b5}/redis/__init__.py +0 -0
  22. {redis-5.3.0b4 → redis-5.3.0b5}/redis/_parsers/__init__.py +0 -0
  23. {redis-5.3.0b4 → redis-5.3.0b5}/redis/_parsers/base.py +0 -0
  24. {redis-5.3.0b4 → redis-5.3.0b5}/redis/_parsers/commands.py +0 -0
  25. {redis-5.3.0b4 → redis-5.3.0b5}/redis/_parsers/encoders.py +0 -0
  26. {redis-5.3.0b4 → redis-5.3.0b5}/redis/_parsers/helpers.py +0 -0
  27. {redis-5.3.0b4 → redis-5.3.0b5}/redis/_parsers/hiredis.py +0 -0
  28. {redis-5.3.0b4 → redis-5.3.0b5}/redis/_parsers/resp2.py +0 -0
  29. {redis-5.3.0b4 → redis-5.3.0b5}/redis/_parsers/resp3.py +0 -0
  30. {redis-5.3.0b4 → redis-5.3.0b5}/redis/_parsers/socket.py +0 -0
  31. {redis-5.3.0b4 → redis-5.3.0b5}/redis/asyncio/__init__.py +0 -0
  32. {redis-5.3.0b4 → redis-5.3.0b5}/redis/asyncio/cluster.py +0 -0
  33. {redis-5.3.0b4 → redis-5.3.0b5}/redis/asyncio/connection.py +0 -0
  34. {redis-5.3.0b4 → redis-5.3.0b5}/redis/asyncio/lock.py +0 -0
  35. {redis-5.3.0b4 → redis-5.3.0b5}/redis/asyncio/retry.py +0 -0
  36. {redis-5.3.0b4 → redis-5.3.0b5}/redis/asyncio/sentinel.py +0 -0
  37. {redis-5.3.0b4 → redis-5.3.0b5}/redis/asyncio/utils.py +0 -0
  38. {redis-5.3.0b4 → redis-5.3.0b5}/redis/auth/__init__.py +0 -0
  39. {redis-5.3.0b4 → redis-5.3.0b5}/redis/auth/err.py +0 -0
  40. {redis-5.3.0b4 → redis-5.3.0b5}/redis/auth/idp.py +0 -0
  41. {redis-5.3.0b4 → redis-5.3.0b5}/redis/auth/token.py +0 -0
  42. {redis-5.3.0b4 → redis-5.3.0b5}/redis/auth/token_manager.py +0 -0
  43. {redis-5.3.0b4 → redis-5.3.0b5}/redis/backoff.py +0 -0
  44. {redis-5.3.0b4 → redis-5.3.0b5}/redis/cache.py +0 -0
  45. {redis-5.3.0b4 → redis-5.3.0b5}/redis/commands/__init__.py +0 -0
  46. {redis-5.3.0b4 → redis-5.3.0b5}/redis/commands/bf/__init__.py +0 -0
  47. {redis-5.3.0b4 → redis-5.3.0b5}/redis/commands/bf/commands.py +0 -0
  48. {redis-5.3.0b4 → redis-5.3.0b5}/redis/commands/bf/info.py +0 -0
  49. {redis-5.3.0b4 → redis-5.3.0b5}/redis/commands/cluster.py +0 -0
  50. {redis-5.3.0b4 → redis-5.3.0b5}/redis/commands/core.py +0 -0
  51. {redis-5.3.0b4 → redis-5.3.0b5}/redis/commands/graph/__init__.py +0 -0
  52. {redis-5.3.0b4 → redis-5.3.0b5}/redis/commands/graph/commands.py +0 -0
  53. {redis-5.3.0b4 → redis-5.3.0b5}/redis/commands/graph/edge.py +0 -0
  54. {redis-5.3.0b4 → redis-5.3.0b5}/redis/commands/graph/exceptions.py +0 -0
  55. {redis-5.3.0b4 → redis-5.3.0b5}/redis/commands/graph/execution_plan.py +0 -0
  56. {redis-5.3.0b4 → redis-5.3.0b5}/redis/commands/graph/node.py +0 -0
  57. {redis-5.3.0b4 → redis-5.3.0b5}/redis/commands/graph/path.py +0 -0
  58. {redis-5.3.0b4 → redis-5.3.0b5}/redis/commands/graph/query_result.py +0 -0
  59. {redis-5.3.0b4 → redis-5.3.0b5}/redis/commands/helpers.py +0 -0
  60. {redis-5.3.0b4 → redis-5.3.0b5}/redis/commands/json/__init__.py +0 -0
  61. {redis-5.3.0b4 → redis-5.3.0b5}/redis/commands/json/_util.py +0 -0
  62. {redis-5.3.0b4 → redis-5.3.0b5}/redis/commands/json/commands.py +0 -0
  63. {redis-5.3.0b4 → redis-5.3.0b5}/redis/commands/json/decoders.py +0 -0
  64. {redis-5.3.0b4 → redis-5.3.0b5}/redis/commands/json/path.py +0 -0
  65. {redis-5.3.0b4 → redis-5.3.0b5}/redis/commands/redismodules.py +0 -0
  66. {redis-5.3.0b4 → redis-5.3.0b5}/redis/commands/search/__init__.py +0 -0
  67. {redis-5.3.0b4 → redis-5.3.0b5}/redis/commands/search/_util.py +0 -0
  68. {redis-5.3.0b4 → redis-5.3.0b5}/redis/commands/search/aggregation.py +0 -0
  69. {redis-5.3.0b4 → redis-5.3.0b5}/redis/commands/search/commands.py +0 -0
  70. {redis-5.3.0b4 → redis-5.3.0b5}/redis/commands/search/document.py +0 -0
  71. {redis-5.3.0b4 → redis-5.3.0b5}/redis/commands/search/field.py +0 -0
  72. {redis-5.3.0b4 → redis-5.3.0b5}/redis/commands/search/indexDefinition.py +0 -0
  73. {redis-5.3.0b4 → redis-5.3.0b5}/redis/commands/search/query.py +0 -0
  74. {redis-5.3.0b4 → redis-5.3.0b5}/redis/commands/search/querystring.py +0 -0
  75. {redis-5.3.0b4 → redis-5.3.0b5}/redis/commands/search/reducers.py +0 -0
  76. {redis-5.3.0b4 → redis-5.3.0b5}/redis/commands/search/result.py +0 -0
  77. {redis-5.3.0b4 → redis-5.3.0b5}/redis/commands/search/suggestion.py +0 -0
  78. {redis-5.3.0b4 → redis-5.3.0b5}/redis/commands/sentinel.py +0 -0
  79. {redis-5.3.0b4 → redis-5.3.0b5}/redis/commands/timeseries/__init__.py +0 -0
  80. {redis-5.3.0b4 → redis-5.3.0b5}/redis/commands/timeseries/commands.py +0 -0
  81. {redis-5.3.0b4 → redis-5.3.0b5}/redis/commands/timeseries/info.py +0 -0
  82. {redis-5.3.0b4 → redis-5.3.0b5}/redis/commands/timeseries/utils.py +0 -0
  83. {redis-5.3.0b4 → redis-5.3.0b5}/redis/crc.py +0 -0
  84. {redis-5.3.0b4 → redis-5.3.0b5}/redis/credentials.py +0 -0
  85. {redis-5.3.0b4 → redis-5.3.0b5}/redis/event.py +0 -0
  86. {redis-5.3.0b4 → redis-5.3.0b5}/redis/exceptions.py +0 -0
  87. {redis-5.3.0b4 → redis-5.3.0b5}/redis/lock.py +0 -0
  88. {redis-5.3.0b4 → redis-5.3.0b5}/redis/ocsp.py +0 -0
  89. {redis-5.3.0b4 → redis-5.3.0b5}/redis/retry.py +0 -0
  90. {redis-5.3.0b4 → redis-5.3.0b5}/redis/sentinel.py +0 -0
  91. {redis-5.3.0b4 → redis-5.3.0b5}/redis/utils.py +0 -0
  92. {redis-5.3.0b4 → redis-5.3.0b5}/redis.egg-info/SOURCES.txt +0 -0
  93. {redis-5.3.0b4 → redis-5.3.0b5}/redis.egg-info/dependency_links.txt +0 -0
  94. {redis-5.3.0b4 → redis-5.3.0b5}/redis.egg-info/requires.txt +0 -0
  95. {redis-5.3.0b4 → redis-5.3.0b5}/redis.egg-info/top_level.txt +0 -0
  96. {redis-5.3.0b4 → redis-5.3.0b5}/setup.cfg +0 -0
  97. {redis-5.3.0b4 → redis-5.3.0b5}/tests/__init__.py +0 -0
  98. {redis-5.3.0b4 → redis-5.3.0b5}/tests/mocks.py +0 -0
  99. {redis-5.3.0b4 → redis-5.3.0b5}/tests/ssl_utils.py +0 -0
  100. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_asyncio/__init__.py +0 -0
  101. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_asyncio/compat.py +0 -0
  102. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_asyncio/mocks.py +0 -0
  103. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_asyncio/test_bloom.py +0 -0
  104. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_asyncio/test_cluster.py +0 -0
  105. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_asyncio/test_commands.py +0 -0
  106. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_asyncio/test_connect.py +0 -0
  107. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_asyncio/test_connection_pool.py +0 -0
  108. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_asyncio/test_credentials.py +0 -0
  109. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_asyncio/test_cwe_404.py +0 -0
  110. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_asyncio/test_encoding.py +0 -0
  111. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_asyncio/test_graph.py +0 -0
  112. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_asyncio/test_hash.py +0 -0
  113. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_asyncio/test_json.py +0 -0
  114. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_asyncio/test_lock.py +0 -0
  115. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_asyncio/test_monitor.py +0 -0
  116. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_asyncio/test_pipeline.py +0 -0
  117. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_asyncio/test_pubsub.py +0 -0
  118. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_asyncio/test_retry.py +0 -0
  119. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_asyncio/test_scripting.py +0 -0
  120. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_asyncio/test_search.py +0 -0
  121. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_asyncio/test_sentinel.py +0 -0
  122. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_asyncio/test_sentinel_managed_connection.py +0 -0
  123. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_asyncio/test_timeseries.py +0 -0
  124. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_asyncio/testdata/jsontestdata.py +0 -0
  125. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_asyncio/testdata/titles.csv +0 -0
  126. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_asyncio/testdata/will_play_text.csv.bz2 +0 -0
  127. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_auth/__init__.py +0 -0
  128. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_auth/test_token.py +0 -0
  129. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_bloom.py +0 -0
  130. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_cache.py +0 -0
  131. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_cluster.py +0 -0
  132. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_command_parser.py +0 -0
  133. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_connect.py +0 -0
  134. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_credentials.py +0 -0
  135. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_encoding.py +0 -0
  136. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_function.py +0 -0
  137. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_graph.py +0 -0
  138. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_graph_utils/__init__.py +0 -0
  139. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_graph_utils/test_edge.py +0 -0
  140. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_graph_utils/test_node.py +0 -0
  141. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_graph_utils/test_path.py +0 -0
  142. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_hash.py +0 -0
  143. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_helpers.py +0 -0
  144. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_json.py +0 -0
  145. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_lock.py +0 -0
  146. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_monitor.py +0 -0
  147. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_parsers/test_helpers.py +0 -0
  148. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_pipeline.py +0 -0
  149. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_pubsub.py +0 -0
  150. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_retry.py +0 -0
  151. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_scripting.py +0 -0
  152. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_search.py +0 -0
  153. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_sentinel.py +0 -0
  154. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_ssl.py +0 -0
  155. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_timeseries.py +0 -0
  156. {redis-5.3.0b4 → redis-5.3.0b5}/tests/test_utils.py +0 -0
  157. {redis-5.3.0b4 → redis-5.3.0b5}/tests/testdata/jsontestdata.py +0 -0
  158. {redis-5.3.0b4 → redis-5.3.0b5}/tests/testdata/titles.csv +0 -0
  159. {redis-5.3.0b4 → redis-5.3.0b5}/tests/testdata/will_play_text.csv.bz2 +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: redis
3
- Version: 5.3.0b4
3
+ Version: 5.3.0b5
4
4
  Summary: Python client for Redis database and key-value store
5
5
  Home-page: https://github.com/redis/redis-py
6
6
  Author: Redis Inc.
@@ -1554,7 +1554,7 @@ class Pipeline(Redis): # lgtm [py/init-calls-subclass]
1554
1554
  await self.reset()
1555
1555
  raise
1556
1556
 
1557
- async def execute(self, raise_on_error: bool = True):
1557
+ async def execute(self, raise_on_error: bool = True) -> List[Any]:
1558
1558
  """Execute all the commands in the current pipeline"""
1559
1559
  stack = self.command_stack
1560
1560
  if not stack and not self.watching:
@@ -4,7 +4,17 @@ import threading
4
4
  import time
5
5
  import warnings
6
6
  from itertools import chain
7
- from typing import Any, Callable, Dict, List, Optional, Type, Union
7
+ from typing import (
8
+ TYPE_CHECKING,
9
+ Any,
10
+ Callable,
11
+ Dict,
12
+ List,
13
+ Mapping,
14
+ Optional,
15
+ Type,
16
+ Union,
17
+ )
8
18
 
9
19
  from redis._parsers.encoders import Encoder
10
20
  from redis._parsers.helpers import (
@@ -53,6 +63,11 @@ from redis.utils import (
53
63
  str_if_bytes,
54
64
  )
55
65
 
66
+ if TYPE_CHECKING:
67
+ import ssl
68
+
69
+ import OpenSSL
70
+
56
71
  SYM_EMPTY = b""
57
72
  EMPTY_RESPONSE = "EMPTY_RESPONSE"
58
73
 
@@ -175,47 +190,47 @@ class Redis(RedisModuleCommands, CoreCommands, SentinelCommands):
175
190
 
176
191
  def __init__(
177
192
  self,
178
- host="localhost",
179
- port=6379,
180
- db=0,
181
- password=None,
182
- socket_timeout=None,
183
- socket_connect_timeout=None,
184
- socket_keepalive=None,
185
- socket_keepalive_options=None,
186
- connection_pool=None,
187
- unix_socket_path=None,
188
- encoding="utf-8",
189
- encoding_errors="strict",
190
- charset=None,
191
- errors=None,
192
- decode_responses=False,
193
- retry_on_timeout=False,
194
- retry_on_error=None,
195
- ssl=False,
196
- ssl_keyfile=None,
197
- ssl_certfile=None,
198
- ssl_cert_reqs="required",
199
- ssl_ca_certs=None,
200
- ssl_ca_path=None,
201
- ssl_ca_data=None,
202
- ssl_check_hostname=False,
203
- ssl_password=None,
204
- ssl_validate_ocsp=False,
205
- ssl_validate_ocsp_stapled=False,
206
- ssl_ocsp_context=None,
207
- ssl_ocsp_expected_cert=None,
208
- ssl_min_version=None,
209
- ssl_ciphers=None,
210
- max_connections=None,
211
- single_connection_client=False,
212
- health_check_interval=0,
213
- client_name=None,
214
- lib_name="redis-py",
215
- lib_version=get_lib_version(),
216
- username=None,
217
- retry=None,
218
- redis_connect_func=None,
193
+ host: str = "localhost",
194
+ port: int = 6379,
195
+ db: int = 0,
196
+ password: Optional[str] = None,
197
+ socket_timeout: Optional[float] = None,
198
+ socket_connect_timeout: Optional[float] = None,
199
+ socket_keepalive: Optional[bool] = None,
200
+ socket_keepalive_options: Optional[Mapping[int, Union[int, bytes]]] = None,
201
+ connection_pool: Optional[ConnectionPool] = None,
202
+ unix_socket_path: Optional[str] = None,
203
+ encoding: str = "utf-8",
204
+ encoding_errors: str = "strict",
205
+ charset: Optional[str] = None,
206
+ errors: Optional[str] = None,
207
+ decode_responses: bool = False,
208
+ retry_on_timeout: bool = False,
209
+ retry_on_error: Optional[List[Type[Exception]]] = None,
210
+ ssl: bool = False,
211
+ ssl_keyfile: Optional[str] = None,
212
+ ssl_certfile: Optional[str] = None,
213
+ ssl_cert_reqs: str = "required",
214
+ ssl_ca_certs: Optional[str] = None,
215
+ ssl_ca_path: Optional[str] = None,
216
+ ssl_ca_data: Optional[str] = None,
217
+ ssl_check_hostname: bool = False,
218
+ ssl_password: Optional[str] = None,
219
+ ssl_validate_ocsp: bool = False,
220
+ ssl_validate_ocsp_stapled: bool = False,
221
+ ssl_ocsp_context: Optional["OpenSSL.SSL.Context"] = None,
222
+ ssl_ocsp_expected_cert: Optional[str] = None,
223
+ ssl_min_version: Optional["ssl.TLSVersion"] = None,
224
+ ssl_ciphers: Optional[str] = None,
225
+ max_connections: Optional[int] = None,
226
+ single_connection_client: bool = False,
227
+ health_check_interval: int = 0,
228
+ client_name: Optional[str] = None,
229
+ lib_name: Optional[str] = "redis-py",
230
+ lib_version: Optional[str] = get_lib_version(),
231
+ username: Optional[str] = None,
232
+ retry: Optional[Retry] = None,
233
+ redis_connect_func: Optional[Callable[[], None]] = None,
219
234
  credential_provider: Optional[CredentialProvider] = None,
220
235
  protocol: Optional[int] = 2,
221
236
  cache: Optional[CacheInterface] = None,
@@ -550,7 +565,7 @@ class Redis(RedisModuleCommands, CoreCommands, SentinelCommands):
550
565
  def __del__(self):
551
566
  self.close()
552
567
 
553
- def close(self):
568
+ def close(self) -> None:
554
569
  # In case a connection property does not yet exist
555
570
  # (due to a crash earlier in the Redis() constructor), return
556
571
  # immediately as there is nothing to clean-up.
@@ -1551,11 +1566,10 @@ class Pipeline(Redis):
1551
1566
  conn.retry_on_error is None
1552
1567
  or isinstance(error, tuple(conn.retry_on_error)) is False
1553
1568
  ):
1554
-
1555
1569
  self.reset()
1556
1570
  raise error
1557
1571
 
1558
- def execute(self, raise_on_error=True):
1572
+ def execute(self, raise_on_error: bool = True) -> List[Any]:
1559
1573
  """Execute all the commands in the current pipeline"""
1560
1574
  stack = self.command_stack
1561
1575
  if not stack and not self.watching:
@@ -1244,7 +1244,7 @@ class RedisCluster(AbstractRedisCluster, RedisClusterCommands):
1244
1244
 
1245
1245
  raise ClusterError("TTL exhausted.")
1246
1246
 
1247
- def close(self):
1247
+ def close(self) -> None:
1248
1248
  try:
1249
1249
  with self._lock:
1250
1250
  if self.nodes_manager:
@@ -1686,7 +1686,7 @@ class NodesManager:
1686
1686
  # If initialize was called after a MovedError, clear it
1687
1687
  self._moved_exception = None
1688
1688
 
1689
- def close(self):
1689
+ def close(self) -> None:
1690
1690
  self.default_node = None
1691
1691
  for node in self.nodes_cache.values():
1692
1692
  if node.redis_connection:
@@ -2067,7 +2067,7 @@ class ClusterPipeline(RedisCluster):
2067
2067
  )
2068
2068
  exception.args = (msg,) + exception.args[1:]
2069
2069
 
2070
- def execute(self, raise_on_error=True):
2070
+ def execute(self, raise_on_error: bool = True) -> List[Any]:
2071
2071
  """
2072
2072
  Execute all the commands in the current pipeline
2073
2073
  """
@@ -9,7 +9,7 @@ from abc import abstractmethod
9
9
  from itertools import chain
10
10
  from queue import Empty, Full, LifoQueue
11
11
  from time import time
12
- from typing import Any, Callable, Dict, List, Optional, Type, Union
12
+ from typing import Any, Callable, Dict, List, Optional, Type, TypeVar, Union
13
13
  from urllib.parse import parse_qs, unquote, urlparse
14
14
 
15
15
  from redis.cache import (
@@ -904,9 +904,11 @@ class CacheProxyConnection(ConnectionInterface):
904
904
  and self._cache.get(self._current_command_cache_key).status
905
905
  != CacheEntryStatus.IN_PROGRESS
906
906
  ):
907
- return copy.deepcopy(
907
+ res = copy.deepcopy(
908
908
  self._cache.get(self._current_command_cache_key).cache_value
909
909
  )
910
+ self._current_command_cache_key = None
911
+ return res
910
912
 
911
913
  response = self._conn.read_response(
912
914
  disable_decoding=disable_decoding,
@@ -932,6 +934,8 @@ class CacheProxyConnection(ConnectionInterface):
932
934
  cache_entry.cache_value = response
933
935
  self._cache.set(cache_entry)
934
936
 
937
+ self._current_command_cache_key = None
938
+
935
939
  return response
936
940
 
937
941
  def pack_command(self, *args):
@@ -1259,6 +1263,9 @@ def parse_url(url):
1259
1263
  return kwargs
1260
1264
 
1261
1265
 
1266
+ _CP = TypeVar("_CP", bound="ConnectionPool")
1267
+
1268
+
1262
1269
  class ConnectionPool:
1263
1270
  """
1264
1271
  Create a connection pool. ``If max_connections`` is set, then this
@@ -1274,7 +1281,7 @@ class ConnectionPool:
1274
1281
  """
1275
1282
 
1276
1283
  @classmethod
1277
- def from_url(cls, url, **kwargs):
1284
+ def from_url(cls: Type[_CP], url: str, **kwargs) -> _CP:
1278
1285
  """
1279
1286
  Return a connection pool configured from the given URL.
1280
1287
 
@@ -1374,6 +1381,7 @@ class ConnectionPool:
1374
1381
  # will notice the first thread already did the work and simply
1375
1382
  # release the lock.
1376
1383
  self._fork_lock = threading.Lock()
1384
+ self._lock = threading.Lock()
1377
1385
  self.reset()
1378
1386
 
1379
1387
  def __repr__(self) -> (str, str):
@@ -1391,7 +1399,6 @@ class ConnectionPool:
1391
1399
  return self.connection_kwargs.get("protocol", None)
1392
1400
 
1393
1401
  def reset(self) -> None:
1394
- self._lock = threading.Lock()
1395
1402
  self._created_connections = 0
1396
1403
  self._available_connections = []
1397
1404
  self._in_use_connections = set()
@@ -20,7 +20,7 @@ if TYPE_CHECKING:
20
20
 
21
21
 
22
22
  Number = Union[int, float]
23
- EncodedT = Union[bytes, memoryview]
23
+ EncodedT = Union[bytes, bytearray, memoryview]
24
24
  DecodedT = Union[str, int, float]
25
25
  EncodableT = Union[EncodedT, DecodedT]
26
26
  AbsExpiryT = Union[int, datetime]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: redis
3
- Version: 5.3.0b4
3
+ Version: 5.3.0b5
4
4
  Summary: Python client for Redis database and key-value store
5
5
  Home-page: https://github.com/redis/redis-py
6
6
  Author: Redis Inc.
@@ -8,7 +8,7 @@ setup(
8
8
  long_description_content_type="text/markdown",
9
9
  keywords=["Redis", "key-value store", "database"],
10
10
  license="MIT",
11
- version="5.3.0b4",
11
+ version="5.3.0b5",
12
12
  packages=find_packages(
13
13
  include=[
14
14
  "redis",
@@ -5,7 +5,7 @@ import random
5
5
  import time
6
6
  from datetime import datetime, timezone
7
7
  from enum import Enum
8
- from typing import Callable, TypeVar
8
+ from typing import Callable, TypeVar, Union
9
9
  from unittest import mock
10
10
  from unittest.mock import Mock
11
11
  from urllib.parse import urlparse
@@ -17,6 +17,7 @@ from packaging.version import Version
17
17
  from redis import Sentinel
18
18
  from redis.auth.idp import IdentityProviderInterface
19
19
  from redis.auth.token import JWToken
20
+ from redis.auth.token_manager import RetryPolicy, TokenManagerConfig
20
21
  from redis.backoff import NoBackoff
21
22
  from redis.cache import (
22
23
  CacheConfig,
@@ -29,12 +30,21 @@ from redis.connection import Connection, ConnectionInterface, SSLConnection, par
29
30
  from redis.credentials import CredentialProvider
30
31
  from redis.exceptions import RedisClusterException
31
32
  from redis.retry import Retry
32
- from redis_entraid.cred_provider import EntraIdCredentialsProvider, TokenAuthConfig
33
+ from redis_entraid.cred_provider import (
34
+ DEFAULT_DELAY_IN_MS,
35
+ DEFAULT_EXPIRATION_REFRESH_RATIO,
36
+ DEFAULT_LOWER_REFRESH_BOUND_MILLIS,
37
+ DEFAULT_MAX_ATTEMPTS,
38
+ DEFAULT_TOKEN_REQUEST_EXECUTION_TIMEOUT_IN_MS,
39
+ EntraIdCredentialsProvider,
40
+ )
33
41
  from redis_entraid.identity_provider import (
34
42
  ManagedIdentityIdType,
43
+ ManagedIdentityProviderConfig,
35
44
  ManagedIdentityType,
36
- create_provider_from_managed_identity,
37
- create_provider_from_service_principal,
45
+ ServicePrincipalIdentityProviderConfig,
46
+ _create_provider_from_managed_identity,
47
+ _create_provider_from_service_principal,
38
48
  )
39
49
  from tests.ssl_utils import get_tls_certificates
40
50
 
@@ -623,17 +633,33 @@ def identity_provider(request) -> IdentityProviderInterface:
623
633
  return mock_identity_provider()
624
634
 
625
635
  auth_type = kwargs.pop("auth_type", AuthType.SERVICE_PRINCIPAL)
636
+ config = get_identity_provider_config(request=request)
626
637
 
627
638
  if auth_type == "MANAGED_IDENTITY":
628
- return _get_managed_identity_provider(request)
639
+ return _create_provider_from_managed_identity(config)
640
+
641
+ return _create_provider_from_service_principal(config)
629
642
 
630
- return _get_service_principal_provider(request)
631
643
 
644
+ def get_identity_provider_config(
645
+ request,
646
+ ) -> Union[ManagedIdentityProviderConfig, ServicePrincipalIdentityProviderConfig]:
647
+ if hasattr(request, "param"):
648
+ kwargs = request.param.get("idp_kwargs", {})
649
+ else:
650
+ kwargs = {}
651
+
652
+ auth_type = kwargs.pop("auth_type", AuthType.SERVICE_PRINCIPAL)
632
653
 
633
- def _get_managed_identity_provider(request):
634
- authority = os.getenv("AZURE_AUTHORITY")
654
+ if auth_type == AuthType.MANAGED_IDENTITY:
655
+ return _get_managed_identity_provider_config(request)
656
+
657
+ return _get_service_principal_provider_config(request)
658
+
659
+
660
+ def _get_managed_identity_provider_config(request) -> ManagedIdentityProviderConfig:
635
661
  resource = os.getenv("AZURE_RESOURCE")
636
- id_value = os.getenv("AZURE_ID_VALUE", None)
662
+ id_value = os.getenv("AZURE_USER_ASSIGNED_MANAGED_ID", None)
637
663
 
638
664
  if hasattr(request, "param"):
639
665
  kwargs = request.param.get("idp_kwargs", {})
@@ -641,23 +667,24 @@ def _get_managed_identity_provider(request):
641
667
  kwargs = {}
642
668
 
643
669
  identity_type = kwargs.pop("identity_type", ManagedIdentityType.SYSTEM_ASSIGNED)
644
- id_type = kwargs.pop("id_type", ManagedIdentityIdType.CLIENT_ID)
670
+ id_type = kwargs.pop("id_type", ManagedIdentityIdType.OBJECT_ID)
645
671
 
646
- return create_provider_from_managed_identity(
672
+ return ManagedIdentityProviderConfig(
647
673
  identity_type=identity_type,
648
674
  resource=resource,
649
675
  id_type=id_type,
650
676
  id_value=id_value,
651
- authority=authority,
652
- **kwargs,
677
+ kwargs=kwargs,
653
678
  )
654
679
 
655
680
 
656
- def _get_service_principal_provider(request):
681
+ def _get_service_principal_provider_config(
682
+ request,
683
+ ) -> ServicePrincipalIdentityProviderConfig:
657
684
  client_id = os.getenv("AZURE_CLIENT_ID")
658
685
  client_credential = os.getenv("AZURE_CLIENT_SECRET")
659
- authority = os.getenv("AZURE_AUTHORITY")
660
- scopes = os.getenv("AZURE_REDIS_SCOPES", [])
686
+ tenant_id = os.getenv("AZURE_TENANT_ID")
687
+ scopes = os.getenv("AZURE_REDIS_SCOPES", None)
661
688
 
662
689
  if hasattr(request, "param"):
663
690
  kwargs = request.param.get("idp_kwargs", {})
@@ -671,14 +698,14 @@ def _get_service_principal_provider(request):
671
698
  if isinstance(scopes, str):
672
699
  scopes = scopes.split(",")
673
700
 
674
- return create_provider_from_service_principal(
701
+ return ServicePrincipalIdentityProviderConfig(
675
702
  client_id=client_id,
676
703
  client_credential=client_credential,
677
704
  scopes=scopes,
678
705
  timeout=timeout,
679
706
  token_kwargs=token_kwargs,
680
- authority=authority,
681
- **kwargs,
707
+ tenant_id=tenant_id,
708
+ app_kwargs=kwargs,
682
709
  )
683
710
 
684
711
 
@@ -690,31 +717,29 @@ def get_credential_provider(request) -> CredentialProvider:
690
717
  return cred_provider_class(**cred_provider_kwargs)
691
718
 
692
719
  idp = identity_provider(request)
693
- initial_delay_in_ms = cred_provider_kwargs.get("initial_delay_in_ms", 0)
694
- block_for_initial = cred_provider_kwargs.get("block_for_initial", False)
695
720
  expiration_refresh_ratio = cred_provider_kwargs.get(
696
- "expiration_refresh_ratio", TokenAuthConfig.DEFAULT_EXPIRATION_REFRESH_RATIO
721
+ "expiration_refresh_ratio", DEFAULT_EXPIRATION_REFRESH_RATIO
697
722
  )
698
723
  lower_refresh_bound_millis = cred_provider_kwargs.get(
699
- "lower_refresh_bound_millis", TokenAuthConfig.DEFAULT_LOWER_REFRESH_BOUND_MILLIS
700
- )
701
- max_attempts = cred_provider_kwargs.get(
702
- "max_attempts", TokenAuthConfig.DEFAULT_MAX_ATTEMPTS
724
+ "lower_refresh_bound_millis", DEFAULT_LOWER_REFRESH_BOUND_MILLIS
703
725
  )
704
- delay_in_ms = cred_provider_kwargs.get(
705
- "delay_in_ms", TokenAuthConfig.DEFAULT_DELAY_IN_MS
726
+ max_attempts = cred_provider_kwargs.get("max_attempts", DEFAULT_MAX_ATTEMPTS)
727
+ delay_in_ms = cred_provider_kwargs.get("delay_in_ms", DEFAULT_DELAY_IN_MS)
728
+
729
+ token_mgr_config = TokenManagerConfig(
730
+ expiration_refresh_ratio=expiration_refresh_ratio,
731
+ lower_refresh_bound_millis=lower_refresh_bound_millis,
732
+ token_request_execution_timeout_in_ms=DEFAULT_TOKEN_REQUEST_EXECUTION_TIMEOUT_IN_MS, # noqa
733
+ retry_policy=RetryPolicy(
734
+ max_attempts=max_attempts,
735
+ delay_in_ms=delay_in_ms,
736
+ ),
706
737
  )
707
738
 
708
- auth_config = TokenAuthConfig(idp)
709
- auth_config.expiration_refresh_ratio = expiration_refresh_ratio
710
- auth_config.lower_refresh_bound_millis = lower_refresh_bound_millis
711
- auth_config.max_attempts = max_attempts
712
- auth_config.delay_in_ms = delay_in_ms
713
-
714
739
  return EntraIdCredentialsProvider(
715
- config=auth_config,
716
- initial_delay_in_ms=initial_delay_in_ms,
717
- block_for_initial=block_for_initial,
740
+ identity_provider=idp,
741
+ token_manager_config=token_mgr_config,
742
+ initial_delay_in_ms=delay_in_ms,
718
743
  )
719
744
 
720
745
 
@@ -17,14 +17,24 @@ from redis.asyncio.connection import Connection, parse_url
17
17
  from redis.asyncio.retry import Retry
18
18
  from redis.auth.idp import IdentityProviderInterface
19
19
  from redis.auth.token import JWToken
20
+ from redis.auth.token_manager import RetryPolicy, TokenManagerConfig
20
21
  from redis.backoff import NoBackoff
21
22
  from redis.credentials import CredentialProvider
22
- from redis_entraid.cred_provider import EntraIdCredentialsProvider, TokenAuthConfig
23
+ from redis_entraid.cred_provider import (
24
+ DEFAULT_DELAY_IN_MS,
25
+ DEFAULT_EXPIRATION_REFRESH_RATIO,
26
+ DEFAULT_LOWER_REFRESH_BOUND_MILLIS,
27
+ DEFAULT_MAX_ATTEMPTS,
28
+ DEFAULT_TOKEN_REQUEST_EXECUTION_TIMEOUT_IN_MS,
29
+ EntraIdCredentialsProvider,
30
+ )
23
31
  from redis_entraid.identity_provider import (
24
32
  ManagedIdentityIdType,
33
+ ManagedIdentityProviderConfig,
25
34
  ManagedIdentityType,
26
- create_provider_from_managed_identity,
27
- create_provider_from_service_principal,
35
+ ServicePrincipalIdentityProviderConfig,
36
+ _create_provider_from_managed_identity,
37
+ _create_provider_from_service_principal,
28
38
  )
29
39
  from tests.conftest import REDIS_INFO
30
40
 
@@ -255,17 +265,33 @@ def identity_provider(request) -> IdentityProviderInterface:
255
265
  return mock_identity_provider()
256
266
 
257
267
  auth_type = kwargs.pop("auth_type", AuthType.SERVICE_PRINCIPAL)
268
+ config = get_identity_provider_config(request=request)
258
269
 
259
270
  if auth_type == "MANAGED_IDENTITY":
260
- return _get_managed_identity_provider(request)
271
+ return _create_provider_from_managed_identity(config)
272
+
273
+ return _create_provider_from_service_principal(config)
274
+
275
+
276
+ def get_identity_provider_config(
277
+ request,
278
+ ) -> Union[ManagedIdentityProviderConfig, ServicePrincipalIdentityProviderConfig]:
279
+ if hasattr(request, "param"):
280
+ kwargs = request.param.get("idp_kwargs", {})
281
+ else:
282
+ kwargs = {}
261
283
 
262
- return _get_service_principal_provider(request)
284
+ auth_type = kwargs.pop("auth_type", AuthType.SERVICE_PRINCIPAL)
285
+
286
+ if auth_type == AuthType.MANAGED_IDENTITY:
287
+ return _get_managed_identity_provider_config(request)
263
288
 
289
+ return _get_service_principal_provider_config(request)
264
290
 
265
- def _get_managed_identity_provider(request):
266
- authority = os.getenv("AZURE_AUTHORITY")
291
+
292
+ def _get_managed_identity_provider_config(request) -> ManagedIdentityProviderConfig:
267
293
  resource = os.getenv("AZURE_RESOURCE")
268
- id_value = os.getenv("AZURE_ID_VALUE", None)
294
+ id_value = os.getenv("AZURE_USER_ASSIGNED_MANAGED_ID", None)
269
295
 
270
296
  if hasattr(request, "param"):
271
297
  kwargs = request.param.get("idp_kwargs", {})
@@ -273,23 +299,24 @@ def _get_managed_identity_provider(request):
273
299
  kwargs = {}
274
300
 
275
301
  identity_type = kwargs.pop("identity_type", ManagedIdentityType.SYSTEM_ASSIGNED)
276
- id_type = kwargs.pop("id_type", ManagedIdentityIdType.CLIENT_ID)
302
+ id_type = kwargs.pop("id_type", ManagedIdentityIdType.OBJECT_ID)
277
303
 
278
- return create_provider_from_managed_identity(
304
+ return ManagedIdentityProviderConfig(
279
305
  identity_type=identity_type,
280
306
  resource=resource,
281
307
  id_type=id_type,
282
308
  id_value=id_value,
283
- authority=authority,
284
- **kwargs,
309
+ kwargs=kwargs,
285
310
  )
286
311
 
287
312
 
288
- def _get_service_principal_provider(request):
313
+ def _get_service_principal_provider_config(
314
+ request,
315
+ ) -> ServicePrincipalIdentityProviderConfig:
289
316
  client_id = os.getenv("AZURE_CLIENT_ID")
290
317
  client_credential = os.getenv("AZURE_CLIENT_SECRET")
291
- authority = os.getenv("AZURE_AUTHORITY")
292
- scopes = os.getenv("AZURE_REDIS_SCOPES", [])
318
+ tenant_id = os.getenv("AZURE_TENANT_ID")
319
+ scopes = os.getenv("AZURE_REDIS_SCOPES", None)
293
320
 
294
321
  if hasattr(request, "param"):
295
322
  kwargs = request.param.get("idp_kwargs", {})
@@ -303,14 +330,14 @@ def _get_service_principal_provider(request):
303
330
  if isinstance(scopes, str):
304
331
  scopes = scopes.split(",")
305
332
 
306
- return create_provider_from_service_principal(
333
+ return ServicePrincipalIdentityProviderConfig(
307
334
  client_id=client_id,
308
335
  client_credential=client_credential,
309
336
  scopes=scopes,
310
337
  timeout=timeout,
311
338
  token_kwargs=token_kwargs,
312
- authority=authority,
313
- **kwargs,
339
+ tenant_id=tenant_id,
340
+ app_kwargs=kwargs,
314
341
  )
315
342
 
316
343
 
@@ -322,31 +349,29 @@ def get_credential_provider(request) -> CredentialProvider:
322
349
  return cred_provider_class(**cred_provider_kwargs)
323
350
 
324
351
  idp = identity_provider(request)
325
- initial_delay_in_ms = cred_provider_kwargs.get("initial_delay_in_ms", 0)
326
- block_for_initial = cred_provider_kwargs.get("block_for_initial", False)
327
352
  expiration_refresh_ratio = cred_provider_kwargs.get(
328
- "expiration_refresh_ratio", TokenAuthConfig.DEFAULT_EXPIRATION_REFRESH_RATIO
353
+ "expiration_refresh_ratio", DEFAULT_EXPIRATION_REFRESH_RATIO
329
354
  )
330
355
  lower_refresh_bound_millis = cred_provider_kwargs.get(
331
- "lower_refresh_bound_millis", TokenAuthConfig.DEFAULT_LOWER_REFRESH_BOUND_MILLIS
332
- )
333
- max_attempts = cred_provider_kwargs.get(
334
- "max_attempts", TokenAuthConfig.DEFAULT_MAX_ATTEMPTS
356
+ "lower_refresh_bound_millis", DEFAULT_LOWER_REFRESH_BOUND_MILLIS
335
357
  )
336
- delay_in_ms = cred_provider_kwargs.get(
337
- "delay_in_ms", TokenAuthConfig.DEFAULT_DELAY_IN_MS
358
+ max_attempts = cred_provider_kwargs.get("max_attempts", DEFAULT_MAX_ATTEMPTS)
359
+ delay_in_ms = cred_provider_kwargs.get("delay_in_ms", DEFAULT_DELAY_IN_MS)
360
+
361
+ token_mgr_config = TokenManagerConfig(
362
+ expiration_refresh_ratio=expiration_refresh_ratio,
363
+ lower_refresh_bound_millis=lower_refresh_bound_millis,
364
+ token_request_execution_timeout_in_ms=DEFAULT_TOKEN_REQUEST_EXECUTION_TIMEOUT_IN_MS, # noqa
365
+ retry_policy=RetryPolicy(
366
+ max_attempts=max_attempts,
367
+ delay_in_ms=delay_in_ms,
368
+ ),
338
369
  )
339
370
 
340
- auth_config = TokenAuthConfig(idp)
341
- auth_config.expiration_refresh_ratio = expiration_refresh_ratio
342
- auth_config.lower_refresh_bound_millis = lower_refresh_bound_millis
343
- auth_config.max_attempts = max_attempts
344
- auth_config.delay_in_ms = delay_in_ms
345
-
346
371
  return EntraIdCredentialsProvider(
347
- config=auth_config,
348
- initial_delay_in_ms=initial_delay_in_ms,
349
- block_for_initial=block_for_initial,
372
+ identity_provider=idp,
373
+ token_manager_config=token_mgr_config,
374
+ initial_delay_in_ms=delay_in_ms,
350
375
  )
351
376
 
352
377