Skip to content

Commit 25e85e5

Browse files
authored
fix: replace async_timeout by asyncio.timeout (#2602)
async_timeout does not support python 3.11 aio-libs/async-timeout#295 And have two years old annoying bugs: aio-libs/async-timeout#229 #2551 Since asyncio.timeout has been shipped in python 3.11, we should start using it. Partially fixes 2551
1 parent 91ab12a commit 25e85e5

File tree

4 files changed

+28
-18
lines changed

4 files changed

+28
-18
lines changed

Diff for: CHANGES

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
* Use asyncio.timeout() instead of async_timeout.timeout() for python >= 3.11 (#2602)
12
* Add test and fix async HiredisParser when reading during a disconnect() (#2349)
23
* Use hiredis-py pack_command if available.
34
* Support `.unlink()` in ClusterPipeline

Diff for: redis/asyncio/connection.py

+13-8
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import os
66
import socket
77
import ssl
8+
import sys
89
import threading
910
import weakref
1011
from itertools import chain
@@ -24,7 +25,11 @@
2425
)
2526
from urllib.parse import ParseResult, parse_qs, unquote, urlparse
2627

27-
import async_timeout
28+
if sys.version_info.major >= 3 and sys.version_info.minor >= 11:
29+
from asyncio import timeout as async_timeout
30+
else:
31+
from async_timeout import timeout as async_timeout
32+
2833

2934
from redis.asyncio.retry import Retry
3035
from redis.backoff import NoBackoff
@@ -242,7 +247,7 @@ async def can_read_destructive(self) -> bool:
242247
if self._stream is None:
243248
raise RedisError("Buffer is closed.")
244249
try:
245-
async with async_timeout.timeout(0):
250+
async with async_timeout(0):
246251
return await self._stream.read(1)
247252
except asyncio.TimeoutError:
248253
return False
@@ -380,7 +385,7 @@ async def can_read_destructive(self):
380385
if self._reader.gets():
381386
return True
382387
try:
383-
async with async_timeout.timeout(0):
388+
async with async_timeout(0):
384389
return await self.read_from_socket()
385390
except asyncio.TimeoutError:
386391
return False
@@ -635,7 +640,7 @@ async def connect(self):
635640

636641
async def _connect(self):
637642
"""Create a TCP socket connection"""
638-
async with async_timeout.timeout(self.socket_connect_timeout):
643+
async with async_timeout(self.socket_connect_timeout):
639644
reader, writer = await asyncio.open_connection(
640645
host=self.host,
641646
port=self.port,
@@ -722,7 +727,7 @@ async def on_connect(self) -> None:
722727
async def disconnect(self, nowait: bool = False) -> None:
723728
"""Disconnects from the Redis server"""
724729
try:
725-
async with async_timeout.timeout(self.socket_connect_timeout):
730+
async with async_timeout(self.socket_connect_timeout):
726731
self._parser.on_disconnect()
727732
if not self.is_connected:
728733
return
@@ -827,7 +832,7 @@ async def read_response(
827832
read_timeout = timeout if timeout is not None else self.socket_timeout
828833
try:
829834
if read_timeout is not None:
830-
async with async_timeout.timeout(read_timeout):
835+
async with async_timeout(read_timeout):
831836
response = await self._parser.read_response(
832837
disable_decoding=disable_decoding
833838
)
@@ -1118,7 +1123,7 @@ def repr_pieces(self) -> Iterable[Tuple[str, Union[str, int]]]:
11181123
return pieces
11191124

11201125
async def _connect(self):
1121-
async with async_timeout.timeout(self.socket_connect_timeout):
1126+
async with async_timeout(self.socket_connect_timeout):
11221127
reader, writer = await asyncio.open_unix_connection(path=self.path)
11231128
self._reader = reader
11241129
self._writer = writer
@@ -1589,7 +1594,7 @@ async def get_connection(self, command_name, *keys, **options):
15891594
# self.timeout then raise a ``ConnectionError``.
15901595
connection = None
15911596
try:
1592-
async with async_timeout.timeout(self.timeout):
1597+
async with async_timeout(self.timeout):
15931598
connection = await self.pool.get()
15941599
except (asyncio.QueueEmpty, asyncio.TimeoutError):
15951600
# Note that this is not caught by the redis client and will be

Diff for: setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
install_requires=[
3535
'importlib-metadata >= 1.0; python_version < "3.8"',
3636
'typing-extensions; python_version<"3.8"',
37-
"async-timeout>=4.0.2",
37+
'async-timeout>=4.0.2; python_version<"3.11"',
3838
],
3939
classifiers=[
4040
"Development Status :: 5 - Production/Stable",

Diff for: tests/test_asyncio/test_pubsub.py

+13-9
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@
55
from typing import Optional
66
from unittest.mock import patch
77

8-
import async_timeout
8+
if sys.version_info.major >= 3 and sys.version_info.minor >= 11:
9+
from asyncio import timeout as async_timeout
10+
else:
11+
from async_timeout import timeout as async_timeout
12+
913
import pytest
1014
import pytest_asyncio
1115

@@ -21,7 +25,7 @@ def with_timeout(t):
2125
def wrapper(corofunc):
2226
@functools.wraps(corofunc)
2327
async def run(*args, **kwargs):
24-
async with async_timeout.timeout(t):
28+
async with async_timeout(t):
2529
return await corofunc(*args, **kwargs)
2630

2731
return run
@@ -648,7 +652,7 @@ async def test_reconnect_listen(self, r: redis.Redis, pubsub):
648652

649653
async def loop():
650654
# must make sure the task exits
651-
async with async_timeout.timeout(2):
655+
async with async_timeout(2):
652656
nonlocal interrupt
653657
await pubsub.subscribe("foo")
654658
while True:
@@ -677,7 +681,7 @@ async def loop_step():
677681

678682
task = asyncio.get_running_loop().create_task(loop())
679683
# get the initial connect message
680-
async with async_timeout.timeout(1):
684+
async with async_timeout(1):
681685
message = await messages.get()
682686
assert message == {
683687
"channel": b"foo",
@@ -776,7 +780,7 @@ def callback(message):
776780
if n == 1:
777781
break
778782
await asyncio.sleep(0.1)
779-
async with async_timeout.timeout(0.1):
783+
async with async_timeout(0.1):
780784
message = await messages.get()
781785
task.cancel()
782786
# we expect a cancelled error, not the Runtime error
@@ -839,7 +843,7 @@ async def test_reconnect_socket_error(self, r: redis.Redis, method):
839843
Test that a socket error will cause reconnect
840844
"""
841845
try:
842-
async with async_timeout.timeout(self.timeout):
846+
async with async_timeout(self.timeout):
843847
await self.mysetup(r, method)
844848
# now, disconnect the connection, and wait for it to be re-established
845849
async with self.cond:
@@ -868,7 +872,7 @@ async def test_reconnect_disconnect(self, r: redis.Redis, method):
868872
Test that a manual disconnect() will cause reconnect
869873
"""
870874
try:
871-
async with async_timeout.timeout(self.timeout):
875+
async with async_timeout(self.timeout):
872876
await self.mysetup(r, method)
873877
# now, disconnect the connection, and wait for it to be re-established
874878
async with self.cond:
@@ -923,7 +927,7 @@ async def loop_step_get_message(self):
923927
async def loop_step_listen(self):
924928
# get a single message via listen()
925929
try:
926-
async with async_timeout.timeout(0.1):
930+
async with async_timeout(0.1):
927931
async for message in self.pubsub.listen():
928932
await self.messages.put(message)
929933
return True
@@ -947,7 +951,7 @@ async def test_outer_timeout(self, r: redis.Redis):
947951
assert pubsub.connection.is_connected
948952

949953
async def get_msg_or_timeout(timeout=0.1):
950-
async with async_timeout.timeout(timeout):
954+
async with async_timeout(timeout):
951955
# blocking method to return messages
952956
while True:
953957
response = await pubsub.parse_response(block=True)

0 commit comments

Comments
 (0)