9
9
from typing import Optional , Type
10
10
11
11
12
- # From https://github.com/python/typing_extensions/blob/main/src/typing_extensions.py
13
- # Licensed under the Python Software Foundation License (PSF-2.0)
14
-
15
12
if sys .version_info >= (3 , 11 ):
16
13
from typing import final
17
14
else :
15
+ # From https://github.com/python/typing_extensions/blob/main/src/typing_extensions.py
16
+ # Licensed under the Python Software Foundation License (PSF-2.0)
17
+
18
18
# @final exists in 3.8+, but we backport it for all versions
19
19
# before 3.11 to keep support for the __final__ attribute.
20
20
# See https://bugs.python.org/issue46342
@@ -49,10 +49,21 @@ class Other(Leaf): # Error reported by type checker
49
49
pass
50
50
return f
51
51
52
+ # End https://github.com/python/typing_extensions/blob/main/src/typing_extensions.py
53
+
54
+
55
+ if sys .version_info >= (3 , 11 ):
56
+
57
+ def _uncancel_task (task : "asyncio.Task[object]" ) -> None :
58
+ task .uncancel ()
59
+
60
+ else :
61
+
62
+ def _uncancel_task (task : "asyncio.Task[object]" ) -> None :
63
+ pass
52
64
53
- # End https://github.com/aio-libs/async-timeout/blob/master/async_timeout/__init__.py
54
65
55
- __version__ = "4.0.2 "
66
+ __version__ = "4.0.3 "
56
67
57
68
58
69
__all__ = ("timeout" , "timeout_at" , "Timeout" )
@@ -124,14 +135,15 @@ class Timeout:
124
135
# The purpose is to time out as soon as possible
125
136
# without waiting for the next await expression.
126
137
127
- __slots__ = ("_deadline" , "_loop" , "_state" , "_timeout_handler" )
138
+ __slots__ = ("_deadline" , "_loop" , "_state" , "_timeout_handler" , "_task" )
128
139
129
140
def __init__ (
130
141
self , deadline : Optional [float ], loop : asyncio .AbstractEventLoop
131
142
) -> None :
132
143
self ._loop = loop
133
144
self ._state = _State .INIT
134
145
146
+ self ._task : Optional ["asyncio.Task[object]" ] = None
135
147
self ._timeout_handler = None # type: Optional[asyncio.Handle]
136
148
if deadline is None :
137
149
self ._deadline = None # type: Optional[float]
@@ -187,6 +199,7 @@ def reject(self) -> None:
187
199
self ._reject ()
188
200
189
201
def _reject (self ) -> None :
202
+ self ._task = None
190
203
if self ._timeout_handler is not None :
191
204
self ._timeout_handler .cancel ()
192
205
self ._timeout_handler = None
@@ -234,11 +247,11 @@ def _reschedule(self) -> None:
234
247
if self ._timeout_handler is not None :
235
248
self ._timeout_handler .cancel ()
236
249
237
- task = asyncio .current_task ()
250
+ self . _task = asyncio .current_task ()
238
251
if deadline <= now :
239
- self ._timeout_handler = self ._loop .call_soon (self ._on_timeout , task )
252
+ self ._timeout_handler = self ._loop .call_soon (self ._on_timeout )
240
253
else :
241
- self ._timeout_handler = self ._loop .call_at (deadline , self ._on_timeout , task )
254
+ self ._timeout_handler = self ._loop .call_at (deadline , self ._on_timeout )
242
255
243
256
def _do_enter (self ) -> None :
244
257
if self ._state != _State .INIT :
@@ -248,15 +261,19 @@ def _do_enter(self) -> None:
248
261
249
262
def _do_exit (self , exc_type : Optional [Type [BaseException ]]) -> None :
250
263
if exc_type is asyncio .CancelledError and self ._state == _State .TIMEOUT :
264
+ assert self ._task is not None
265
+ _uncancel_task (self ._task )
251
266
self ._timeout_handler = None
267
+ self ._task = None
252
268
raise asyncio .TimeoutError
253
269
# timeout has not expired
254
270
self ._state = _State .EXIT
255
271
self ._reject ()
256
272
return None
257
273
258
- def _on_timeout (self , task : "asyncio.Task[None]" ) -> None :
259
- task .cancel ()
274
+ def _on_timeout (self ) -> None :
275
+ assert self ._task is not None
276
+ self ._task .cancel ()
260
277
self ._state = _State .TIMEOUT
261
278
# drop the reference early
262
279
self ._timeout_handler = None
0 commit comments