redis 5.2.1__py3-none-any.whl → 5.3.0b1__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.
redis/connection.py CHANGED
@@ -22,8 +22,10 @@ from redis.cache import (
22
22
  )
23
23
 
24
24
  from ._parsers import Encoder, _HiredisParser, _RESP2Parser, _RESP3Parser
25
+ from .auth.token import TokenInterface
25
26
  from .backoff import NoBackoff
26
27
  from .credentials import CredentialProvider, UsernamePasswordCredentialProvider
28
+ from .event import AfterConnectionReleasedEvent, EventDispatcher
27
29
  from .exceptions import (
28
30
  AuthenticationError,
29
31
  AuthenticationWrongNumberOfArgsError,
@@ -151,6 +153,10 @@ class ConnectionInterface:
151
153
  def set_parser(self, parser_class):
152
154
  pass
153
155
 
156
+ @abstractmethod
157
+ def get_protocol(self):
158
+ pass
159
+
154
160
  @abstractmethod
155
161
  def connect(self):
156
162
  pass
@@ -202,6 +208,14 @@ class ConnectionInterface:
202
208
  def handshake_metadata(self) -> Union[Dict[bytes, bytes], Dict[str, str]]:
203
209
  pass
204
210
 
211
+ @abstractmethod
212
+ def set_re_auth_token(self, token: TokenInterface):
213
+ pass
214
+
215
+ @abstractmethod
216
+ def re_auth(self):
217
+ pass
218
+
205
219
 
206
220
  class AbstractConnection(ConnectionInterface):
207
221
  "Manages communication to and from a Redis server"
@@ -229,6 +243,7 @@ class AbstractConnection(ConnectionInterface):
229
243
  credential_provider: Optional[CredentialProvider] = None,
230
244
  protocol: Optional[int] = 2,
231
245
  command_packer: Optional[Callable[[], None]] = None,
246
+ event_dispatcher: Optional[EventDispatcher] = None,
232
247
  ):
233
248
  """
234
249
  Initialize a new Connection.
@@ -244,6 +259,10 @@ class AbstractConnection(ConnectionInterface):
244
259
  "1. 'password' and (optional) 'username'\n"
245
260
  "2. 'credential_provider'"
246
261
  )
262
+ if event_dispatcher is None:
263
+ self._event_dispatcher = EventDispatcher()
264
+ else:
265
+ self._event_dispatcher = event_dispatcher
247
266
  self.pid = os.getpid()
248
267
  self.db = db
249
268
  self.client_name = client_name
@@ -283,6 +302,7 @@ class AbstractConnection(ConnectionInterface):
283
302
  self.set_parser(parser_class)
284
303
  self._connect_callbacks = []
285
304
  self._buffer_cutoff = 6000
305
+ self._re_auth_token: Optional[TokenInterface] = None
286
306
  try:
287
307
  p = int(protocol)
288
308
  except TypeError:
@@ -663,6 +683,19 @@ class AbstractConnection(ConnectionInterface):
663
683
  def handshake_metadata(self, value: Union[Dict[bytes, bytes], Dict[str, str]]):
664
684
  self._handshake_metadata = value
665
685
 
686
+ def set_re_auth_token(self, token: TokenInterface):
687
+ self._re_auth_token = token
688
+
689
+ def re_auth(self):
690
+ if self._re_auth_token is not None:
691
+ self.send_command(
692
+ "AUTH",
693
+ self._re_auth_token.try_get("oid"),
694
+ self._re_auth_token.get_value(),
695
+ )
696
+ self.read_response()
697
+ self._re_auth_token = None
698
+
666
699
 
667
700
  class Connection(AbstractConnection):
668
701
  "Manages TCP communication to and from a Redis server"
@@ -750,6 +783,7 @@ class CacheProxyConnection(ConnectionInterface):
750
783
  self.retry = self._conn.retry
751
784
  self.host = self._conn.host
752
785
  self.port = self._conn.port
786
+ self.credential_provider = conn.credential_provider
753
787
  self._pool_lock = pool_lock
754
788
  self._cache = cache
755
789
  self._cache_lock = threading.Lock()
@@ -933,6 +967,15 @@ class CacheProxyConnection(ConnectionInterface):
933
967
  else:
934
968
  self._cache.delete_by_redis_keys(data[1])
935
969
 
970
+ def get_protocol(self):
971
+ return self._conn.get_protocol()
972
+
973
+ def set_re_auth_token(self, token: TokenInterface):
974
+ self._conn.set_re_auth_token(token)
975
+
976
+ def re_auth(self):
977
+ self._conn.re_auth()
978
+
936
979
 
937
980
  class SSLConnection(Connection):
938
981
  """Manages SSL connections to and from the Redis server(s).
@@ -1318,6 +1361,10 @@ class ConnectionPool:
1318
1361
  connection_kwargs.pop("cache", None)
1319
1362
  connection_kwargs.pop("cache_config", None)
1320
1363
 
1364
+ self._event_dispatcher = self.connection_kwargs.get("event_dispatcher", None)
1365
+ if self._event_dispatcher is None:
1366
+ self._event_dispatcher = EventDispatcher()
1367
+
1321
1368
  # a lock to protect the critical section in _checkpid().
1322
1369
  # this lock is acquired when the process id changes, such as
1323
1370
  # after a fork. during this time, multiple threads in the child
@@ -1475,6 +1522,9 @@ class ConnectionPool:
1475
1522
 
1476
1523
  if self.owns_connection(connection):
1477
1524
  self._available_connections.append(connection)
1525
+ self._event_dispatcher.dispatch(
1526
+ AfterConnectionReleasedEvent(connection)
1527
+ )
1478
1528
  else:
1479
1529
  # pool doesn't own this connection. do not add it back
1480
1530
  # to the pool and decrement the count so that another
@@ -1517,6 +1567,29 @@ class ConnectionPool:
1517
1567
  for conn in self._in_use_connections:
1518
1568
  conn.retry = retry
1519
1569
 
1570
+ def re_auth_callback(self, token: TokenInterface):
1571
+ with self._lock:
1572
+ for conn in self._available_connections:
1573
+ conn.retry.call_with_retry(
1574
+ lambda: conn.send_command(
1575
+ "AUTH", token.try_get("oid"), token.get_value()
1576
+ ),
1577
+ lambda error: self._mock(error),
1578
+ )
1579
+ conn.retry.call_with_retry(
1580
+ lambda: conn.read_response(), lambda error: self._mock(error)
1581
+ )
1582
+ for conn in self._in_use_connections:
1583
+ conn.set_re_auth_token(token)
1584
+
1585
+ async def _mock(self, error: RedisError):
1586
+ """
1587
+ Dummy functions, needs to be passed as error callback to retry object.
1588
+ :param error:
1589
+ :return:
1590
+ """
1591
+ pass
1592
+
1520
1593
 
1521
1594
  class BlockingConnectionPool(ConnectionPool):
1522
1595
  """
redis/credentials.py CHANGED
@@ -1,4 +1,8 @@
1
- from typing import Optional, Tuple, Union
1
+ import logging
2
+ from abc import ABC, abstractmethod
3
+ from typing import Any, Callable, Optional, Tuple, Union
4
+
5
+ logger = logging.getLogger(__name__)
2
6
 
3
7
 
4
8
  class CredentialProvider:
@@ -9,6 +13,38 @@ class CredentialProvider:
9
13
  def get_credentials(self) -> Union[Tuple[str], Tuple[str, str]]:
10
14
  raise NotImplementedError("get_credentials must be implemented")
11
15
 
16
+ async def get_credentials_async(self) -> Union[Tuple[str], Tuple[str, str]]:
17
+ logger.warning(
18
+ "This method is added for backward compatability. "
19
+ "Please override it in your implementation."
20
+ )
21
+ return self.get_credentials()
22
+
23
+
24
+ class StreamingCredentialProvider(CredentialProvider, ABC):
25
+ """
26
+ Credential provider that streams credentials in the background.
27
+ """
28
+
29
+ @abstractmethod
30
+ def on_next(self, callback: Callable[[Any], None]):
31
+ """
32
+ Specifies the callback that should be invoked
33
+ when the next credentials will be retrieved.
34
+
35
+ :param callback: Callback with
36
+ :return:
37
+ """
38
+ pass
39
+
40
+ @abstractmethod
41
+ def on_error(self, callback: Callable[[Exception], None]):
42
+ pass
43
+
44
+ @abstractmethod
45
+ def is_streaming(self) -> bool:
46
+ pass
47
+
12
48
 
13
49
  class UsernamePasswordCredentialProvider(CredentialProvider):
14
50
  """
@@ -24,3 +60,6 @@ class UsernamePasswordCredentialProvider(CredentialProvider):
24
60
  if self.username:
25
61
  return self.username, self.password
26
62
  return (self.password,)
63
+
64
+ async def get_credentials_async(self) -> Union[Tuple[str], Tuple[str, str]]:
65
+ return self.get_credentials()
redis/event.py ADDED
@@ -0,0 +1,394 @@
1
+ import asyncio
2
+ import threading
3
+ from abc import ABC, abstractmethod
4
+ from enum import Enum
5
+ from typing import List, Optional, Union
6
+
7
+ from redis.auth.token import TokenInterface
8
+ from redis.credentials import CredentialProvider, StreamingCredentialProvider
9
+
10
+
11
+ class EventListenerInterface(ABC):
12
+ """
13
+ Represents a listener for given event object.
14
+ """
15
+
16
+ @abstractmethod
17
+ def listen(self, event: object):
18
+ pass
19
+
20
+
21
+ class AsyncEventListenerInterface(ABC):
22
+ """
23
+ Represents an async listener for given event object.
24
+ """
25
+
26
+ @abstractmethod
27
+ async def listen(self, event: object):
28
+ pass
29
+
30
+
31
+ class EventDispatcherInterface(ABC):
32
+ """
33
+ Represents a dispatcher that dispatches events to listeners
34
+ associated with given event.
35
+ """
36
+
37
+ @abstractmethod
38
+ def dispatch(self, event: object):
39
+ pass
40
+
41
+ @abstractmethod
42
+ async def dispatch_async(self, event: object):
43
+ pass
44
+
45
+
46
+ class EventException(Exception):
47
+ """
48
+ Exception wrapper that adds an event object into exception context.
49
+ """
50
+
51
+ def __init__(self, exception: Exception, event: object):
52
+ self.exception = exception
53
+ self.event = event
54
+ super().__init__(exception)
55
+
56
+
57
+ class EventDispatcher(EventDispatcherInterface):
58
+ # TODO: Make dispatcher to accept external mappings.
59
+ def __init__(self):
60
+ """
61
+ Mapping should be extended for any new events or listeners to be added.
62
+ """
63
+ self._event_listeners_mapping = {
64
+ AfterConnectionReleasedEvent: [
65
+ ReAuthConnectionListener(),
66
+ ],
67
+ AfterPooledConnectionsInstantiationEvent: [
68
+ RegisterReAuthForPooledConnections()
69
+ ],
70
+ AfterSingleConnectionInstantiationEvent: [
71
+ RegisterReAuthForSingleConnection()
72
+ ],
73
+ AfterPubSubConnectionInstantiationEvent: [RegisterReAuthForPubSub()],
74
+ AfterAsyncClusterInstantiationEvent: [RegisterReAuthForAsyncClusterNodes()],
75
+ AsyncAfterConnectionReleasedEvent: [
76
+ AsyncReAuthConnectionListener(),
77
+ ],
78
+ }
79
+
80
+ def dispatch(self, event: object):
81
+ listeners = self._event_listeners_mapping.get(type(event))
82
+
83
+ for listener in listeners:
84
+ listener.listen(event)
85
+
86
+ async def dispatch_async(self, event: object):
87
+ listeners = self._event_listeners_mapping.get(type(event))
88
+
89
+ for listener in listeners:
90
+ await listener.listen(event)
91
+
92
+
93
+ class AfterConnectionReleasedEvent:
94
+ """
95
+ Event that will be fired before each command execution.
96
+ """
97
+
98
+ def __init__(self, connection):
99
+ self._connection = connection
100
+
101
+ @property
102
+ def connection(self):
103
+ return self._connection
104
+
105
+
106
+ class AsyncAfterConnectionReleasedEvent(AfterConnectionReleasedEvent):
107
+ pass
108
+
109
+
110
+ class ClientType(Enum):
111
+ SYNC = ("sync",)
112
+ ASYNC = ("async",)
113
+
114
+
115
+ class AfterPooledConnectionsInstantiationEvent:
116
+ """
117
+ Event that will be fired after pooled connection instances was created.
118
+ """
119
+
120
+ def __init__(
121
+ self,
122
+ connection_pools: List,
123
+ client_type: ClientType,
124
+ credential_provider: Optional[CredentialProvider] = None,
125
+ ):
126
+ self._connection_pools = connection_pools
127
+ self._client_type = client_type
128
+ self._credential_provider = credential_provider
129
+
130
+ @property
131
+ def connection_pools(self):
132
+ return self._connection_pools
133
+
134
+ @property
135
+ def client_type(self) -> ClientType:
136
+ return self._client_type
137
+
138
+ @property
139
+ def credential_provider(self) -> Union[CredentialProvider, None]:
140
+ return self._credential_provider
141
+
142
+
143
+ class AfterSingleConnectionInstantiationEvent:
144
+ """
145
+ Event that will be fired after single connection instances was created.
146
+
147
+ :param connection_lock: For sync client thread-lock should be provided,
148
+ for async asyncio.Lock
149
+ """
150
+
151
+ def __init__(
152
+ self,
153
+ connection,
154
+ client_type: ClientType,
155
+ connection_lock: Union[threading.Lock, asyncio.Lock],
156
+ ):
157
+ self._connection = connection
158
+ self._client_type = client_type
159
+ self._connection_lock = connection_lock
160
+
161
+ @property
162
+ def connection(self):
163
+ return self._connection
164
+
165
+ @property
166
+ def client_type(self) -> ClientType:
167
+ return self._client_type
168
+
169
+ @property
170
+ def connection_lock(self) -> Union[threading.Lock, asyncio.Lock]:
171
+ return self._connection_lock
172
+
173
+
174
+ class AfterPubSubConnectionInstantiationEvent:
175
+ def __init__(
176
+ self,
177
+ pubsub_connection,
178
+ connection_pool,
179
+ client_type: ClientType,
180
+ connection_lock: Union[threading.Lock, asyncio.Lock],
181
+ ):
182
+ self._pubsub_connection = pubsub_connection
183
+ self._connection_pool = connection_pool
184
+ self._client_type = client_type
185
+ self._connection_lock = connection_lock
186
+
187
+ @property
188
+ def pubsub_connection(self):
189
+ return self._pubsub_connection
190
+
191
+ @property
192
+ def connection_pool(self):
193
+ return self._connection_pool
194
+
195
+ @property
196
+ def client_type(self) -> ClientType:
197
+ return self._client_type
198
+
199
+ @property
200
+ def connection_lock(self) -> Union[threading.Lock, asyncio.Lock]:
201
+ return self._connection_lock
202
+
203
+
204
+ class AfterAsyncClusterInstantiationEvent:
205
+ """
206
+ Event that will be fired after async cluster instance was created.
207
+
208
+ Async cluster doesn't use connection pools,
209
+ instead ClusterNode object manages connections.
210
+ """
211
+
212
+ def __init__(
213
+ self,
214
+ nodes: dict,
215
+ credential_provider: Optional[CredentialProvider] = None,
216
+ ):
217
+ self._nodes = nodes
218
+ self._credential_provider = credential_provider
219
+
220
+ @property
221
+ def nodes(self) -> dict:
222
+ return self._nodes
223
+
224
+ @property
225
+ def credential_provider(self) -> Union[CredentialProvider, None]:
226
+ return self._credential_provider
227
+
228
+
229
+ class ReAuthConnectionListener(EventListenerInterface):
230
+ """
231
+ Listener that performs re-authentication of given connection.
232
+ """
233
+
234
+ def listen(self, event: AfterConnectionReleasedEvent):
235
+ event.connection.re_auth()
236
+
237
+
238
+ class AsyncReAuthConnectionListener(AsyncEventListenerInterface):
239
+ """
240
+ Async listener that performs re-authentication of given connection.
241
+ """
242
+
243
+ async def listen(self, event: AsyncAfterConnectionReleasedEvent):
244
+ await event.connection.re_auth()
245
+
246
+
247
+ class RegisterReAuthForPooledConnections(EventListenerInterface):
248
+ """
249
+ Listener that registers a re-authentication callback for pooled connections.
250
+ Required by :class:`StreamingCredentialProvider`.
251
+ """
252
+
253
+ def __init__(self):
254
+ self._event = None
255
+
256
+ def listen(self, event: AfterPooledConnectionsInstantiationEvent):
257
+ if isinstance(event.credential_provider, StreamingCredentialProvider):
258
+ self._event = event
259
+
260
+ if event.client_type == ClientType.SYNC:
261
+ event.credential_provider.on_next(self._re_auth)
262
+ event.credential_provider.on_error(self._raise_on_error)
263
+ else:
264
+ event.credential_provider.on_next(self._re_auth_async)
265
+ event.credential_provider.on_error(self._raise_on_error_async)
266
+
267
+ def _re_auth(self, token):
268
+ for pool in self._event.connection_pools:
269
+ pool.re_auth_callback(token)
270
+
271
+ async def _re_auth_async(self, token):
272
+ for pool in self._event.connection_pools:
273
+ await pool.re_auth_callback(token)
274
+
275
+ def _raise_on_error(self, error: Exception):
276
+ raise EventException(error, self._event)
277
+
278
+ async def _raise_on_error_async(self, error: Exception):
279
+ raise EventException(error, self._event)
280
+
281
+
282
+ class RegisterReAuthForSingleConnection(EventListenerInterface):
283
+ """
284
+ Listener that registers a re-authentication callback for single connection.
285
+ Required by :class:`StreamingCredentialProvider`.
286
+ """
287
+
288
+ def __init__(self):
289
+ self._event = None
290
+
291
+ def listen(self, event: AfterSingleConnectionInstantiationEvent):
292
+ if isinstance(
293
+ event.connection.credential_provider, StreamingCredentialProvider
294
+ ):
295
+ self._event = event
296
+
297
+ if event.client_type == ClientType.SYNC:
298
+ event.connection.credential_provider.on_next(self._re_auth)
299
+ event.connection.credential_provider.on_error(self._raise_on_error)
300
+ else:
301
+ event.connection.credential_provider.on_next(self._re_auth_async)
302
+ event.connection.credential_provider.on_error(
303
+ self._raise_on_error_async
304
+ )
305
+
306
+ def _re_auth(self, token):
307
+ with self._event.connection_lock:
308
+ self._event.connection.send_command(
309
+ "AUTH", token.try_get("oid"), token.get_value()
310
+ )
311
+ self._event.connection.read_response()
312
+
313
+ async def _re_auth_async(self, token):
314
+ async with self._event.connection_lock:
315
+ await self._event.connection.send_command(
316
+ "AUTH", token.try_get("oid"), token.get_value()
317
+ )
318
+ await self._event.connection.read_response()
319
+
320
+ def _raise_on_error(self, error: Exception):
321
+ raise EventException(error, self._event)
322
+
323
+ async def _raise_on_error_async(self, error: Exception):
324
+ raise EventException(error, self._event)
325
+
326
+
327
+ class RegisterReAuthForAsyncClusterNodes(EventListenerInterface):
328
+ def __init__(self):
329
+ self._event = None
330
+
331
+ def listen(self, event: AfterAsyncClusterInstantiationEvent):
332
+ if isinstance(event.credential_provider, StreamingCredentialProvider):
333
+ self._event = event
334
+ event.credential_provider.on_next(self._re_auth)
335
+ event.credential_provider.on_error(self._raise_on_error)
336
+
337
+ async def _re_auth(self, token: TokenInterface):
338
+ for key in self._event.nodes:
339
+ await self._event.nodes[key].re_auth_callback(token)
340
+
341
+ async def _raise_on_error(self, error: Exception):
342
+ raise EventException(error, self._event)
343
+
344
+
345
+ class RegisterReAuthForPubSub(EventListenerInterface):
346
+ def __init__(self):
347
+ self._connection = None
348
+ self._connection_pool = None
349
+ self._client_type = None
350
+ self._connection_lock = None
351
+ self._event = None
352
+
353
+ def listen(self, event: AfterPubSubConnectionInstantiationEvent):
354
+ if isinstance(
355
+ event.pubsub_connection.credential_provider, StreamingCredentialProvider
356
+ ) and event.pubsub_connection.get_protocol() in [3, "3"]:
357
+ self._event = event
358
+ self._connection = event.pubsub_connection
359
+ self._connection_pool = event.connection_pool
360
+ self._client_type = event.client_type
361
+ self._connection_lock = event.connection_lock
362
+
363
+ if self._client_type == ClientType.SYNC:
364
+ self._connection.credential_provider.on_next(self._re_auth)
365
+ self._connection.credential_provider.on_error(self._raise_on_error)
366
+ else:
367
+ self._connection.credential_provider.on_next(self._re_auth_async)
368
+ self._connection.credential_provider.on_error(
369
+ self._raise_on_error_async
370
+ )
371
+
372
+ def _re_auth(self, token: TokenInterface):
373
+ with self._connection_lock:
374
+ self._connection.send_command(
375
+ "AUTH", token.try_get("oid"), token.get_value()
376
+ )
377
+ self._connection.read_response()
378
+
379
+ self._connection_pool.re_auth_callback(token)
380
+
381
+ async def _re_auth_async(self, token: TokenInterface):
382
+ async with self._connection_lock:
383
+ await self._connection.send_command(
384
+ "AUTH", token.try_get("oid"), token.get_value()
385
+ )
386
+ await self._connection.read_response()
387
+
388
+ await self._connection_pool.re_auth_callback(token)
389
+
390
+ def _raise_on_error(self, error: Exception):
391
+ raise EventException(error, self._event)
392
+
393
+ async def _raise_on_error_async(self, error: Exception):
394
+ raise EventException(error, self._event)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: redis
3
- Version: 5.2.1
3
+ Version: 5.3.0b1
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.
@@ -1,11 +1,12 @@
1
1
  redis/__init__.py,sha256=WlARnwwst8oaEyjXV5XTcmSGyEKVCn3S9N1MrHyJ8U8,2015
2
2
  redis/backoff.py,sha256=N2CZXkB3cdoHeMZ01r0zVry0bRKe8mk0ybi8hE7PvzU,3177
3
3
  redis/cache.py,sha256=68rJDNogvNwgdgBel6zSX9QziL11qsKIMhmvQvHvznM,9549
4
- redis/client.py,sha256=HbcVPvRKOA8Hd6zeMmmU7eAJ9xkSX9oqLR0ZW7r5AHI,59101
5
- redis/cluster.py,sha256=ECId2H3NdWmxktcHWRk1lWHFgRMipdj143i26xaNhaU,94317
6
- redis/connection.py,sha256=xjd9mfHGR6s0EoF80Rz1EWdzA8aBkYLI2XDhL4UGdhI,62323
4
+ redis/client.py,sha256=MMDn5Qh6rcBx2sDFU4O_Jid5TdzhA3-91_sxzmOBWAM,61055
5
+ redis/cluster.py,sha256=4UBn9HoGjKGUZ-ILROSVw-4I3Kg_9YW8r0X4COKwPsI,95882
6
+ redis/connection.py,sha256=UXrGt2T_1ebCGnpTmIzafZRLiZyqMJi4LOsRFkaFVHU,64750
7
7
  redis/crc.py,sha256=Z3kXFtkY2LdgefnQMud1xr4vG5UYvA9LCMqNMX1ywu4,729
8
- redis/credentials.py,sha256=6VvFeReFp6vernGIWlIVOm8OmbNgoFYdd1wgsjZTnlk,738
8
+ redis/credentials.py,sha256=GOnO3-LSW34efHaIrUbS742Mw8l70mRzF6UrKiKZsMY,1828
9
+ redis/event.py,sha256=urOK241IdgmCQ3fq7GqXRstZ2vcXRV14bBBMdN3latk,12129
9
10
  redis/exceptions.py,sha256=OmOGoS9EPInuTZPJT0BuDeIYuYrtRGEUT_Pu6NtEQNI,5211
10
11
  redis/lock.py,sha256=3JOC3AmYJ10zbq0blOtV4uNwuEhw4K7xuJ6nM-qv5Ig,11976
11
12
  redis/ocsp.py,sha256=4b1s43x-DJ859zRKtwGTIbNys_dyGv5YyOdWnOvigyM,11451
@@ -24,13 +25,18 @@ redis/_parsers/resp2.py,sha256=f22kH-_ZP2iNtOn6xOe65MSy_fJpu8OEn1u_hgeeojI,4813
24
25
  redis/_parsers/resp3.py,sha256=jHtL1LYJegJ_LiNTsjzIvS-kZyNR58jZ_YV4cRfwuN0,11127
25
26
  redis/_parsers/socket.py,sha256=CKD8QW_wFSNlIZzxlbNduaGpiv0I8wBcsGuAIojDfJg,5403
26
27
  redis/asyncio/__init__.py,sha256=uoDD8XYVi0Kj6mcufYwLDUTQXmBRx7a0bhKF9stZr7I,1489
27
- redis/asyncio/client.py,sha256=WIkebQoxn8GUMv2UmhQ4s81Cal6INwMc5mUohfNSTRk,59630
28
- redis/asyncio/cluster.py,sha256=qgBglEl7410K5M1CJxPH1-G3Mv2ed-S134uSJ2mmxng,63177
29
- redis/asyncio/connection.py,sha256=sErywuQxjauJVB5rx2P1AsEKD0T2Z9sTyfzF2ekrIp8,45061
28
+ redis/asyncio/client.py,sha256=xxifh7JrWJkSPpbem1qVXV6sCvAQRlq4VCYrkj84yvQ,61176
29
+ redis/asyncio/cluster.py,sha256=c3dhOQjMUdXQO0WJCOn6-DTPxk-mbcgw52OpiSDrfG8,65243
30
+ redis/asyncio/connection.py,sha256=w4yYr2Pzx_8Q7uJbeEyqZrjrqBpXaEZFYHZC5Zuv5HA,47203
30
31
  redis/asyncio/lock.py,sha256=lLasXEO2E1CskhX5ZZoaSGpmwZP1Q782R3HAUNG3wD4,11967
31
32
  redis/asyncio/retry.py,sha256=SnPPOlo5gcyIFtkC4DY7HFvmDgUaILsJ3DeHioogdB8,2219
32
33
  redis/asyncio/sentinel.py,sha256=QBpsrdlhZlFqENy_rK1IuasSicox55_xSvP_IywbhbQ,14293
33
34
  redis/asyncio/utils.py,sha256=Yxc5YQumhLjtDDwCS4mgxI6yy2Z21AzLlFxVbxCohic,704
35
+ redis/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
+ redis/auth/err.py,sha256=WYkbuDIzwp1S-eAvsya6QMlO6g9QIXbzMITOsTWX0xk,694
37
+ redis/auth/idp.py,sha256=IMDIIb9q72vbIwtFN8vPdaAKZVTdh0HuC5uj5ufqmw4,631
38
+ redis/auth/token.py,sha256=DslJx_wN8yPcrmcF-Ui8E5emcamP6OUwi9PTGSvsXQw,3125
39
+ redis/auth/token_manager.py,sha256=ShBsYXiBZBJBOMB_Y-pXfLwEOAmc9s1okaCECinNZ7g,12018
34
40
  redis/commands/__init__.py,sha256=cTUH-MGvaLYS0WuoytyqtN1wniw2A1KbkUXcpvOSY3I,576
35
41
  redis/commands/cluster.py,sha256=BBHSyXfl3OETIJs4JC5DrcfzqgF2Kt4WMEcd0WMILOU,31598
36
42
  redis/commands/core.py,sha256=YlCzD44YJnFzdEKIFDBloPh1ivgHKcFMZsxPzamE9JM,238528
@@ -69,8 +75,8 @@ redis/commands/timeseries/__init__.py,sha256=gkz6wshEzzQQryBOnrAqqQzttS-AHfXmuN_
69
75
  redis/commands/timeseries/commands.py,sha256=8Z2BEyP23qTYCJR_e9zdG11yWmIDwGBMO2PJNLtK2BA,47147
70
76
  redis/commands/timeseries/info.py,sha256=meZYdu7IV9KaUWMKZs9qW4vo3Q9MwhdY-EBtKQzls5o,3223
71
77
  redis/commands/timeseries/utils.py,sha256=NLwSOS5Dz9N8dYQSzEyBIvrItOWwfQ0xgDj8un6x3dU,1319
72
- redis-5.2.1.dist-info/LICENSE,sha256=pXslClvwPXr-VbdAYzE_Ktt7ANVGwKsUmok5gzP-PMg,1074
73
- redis-5.2.1.dist-info/METADATA,sha256=BPiJh0sxEzBec911KAZAZ0fbCI4gF46NBvYbMV0Xeco,9138
74
- redis-5.2.1.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
75
- redis-5.2.1.dist-info/top_level.txt,sha256=OMAefszlde6ZoOtlM35AWzpRIrwtcqAMHGlRit-w2-4,6
76
- redis-5.2.1.dist-info/RECORD,,
78
+ redis-5.3.0b1.dist-info/LICENSE,sha256=pXslClvwPXr-VbdAYzE_Ktt7ANVGwKsUmok5gzP-PMg,1074
79
+ redis-5.3.0b1.dist-info/METADATA,sha256=Dqwd4v-XM3SQ7zoDHNU3MBUcz15WgQdHL1JlFPOW08g,9140
80
+ redis-5.3.0b1.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
81
+ redis-5.3.0b1.dist-info/top_level.txt,sha256=OMAefszlde6ZoOtlM35AWzpRIrwtcqAMHGlRit-w2-4,6
82
+ redis-5.3.0b1.dist-info/RECORD,,
File without changes