12
12
from typing_extensions import final
13
13
14
14
15
+ if sys .version_info >= (3 , 11 ):
16
+
17
+ def _uncancel_task (task : "asyncio.Task[object]" ) -> None :
18
+ task .uncancel ()
19
+
20
+ else :
21
+
22
+ def _uncancel_task (task : "asyncio.Task[object]" ) -> None :
23
+ pass
24
+
25
+
15
26
__version__ = "4.0.2"
16
27
17
28
@@ -84,14 +95,15 @@ class Timeout:
84
95
# The purpose is to time out as soon as possible
85
96
# without waiting for the next await expression.
86
97
87
- __slots__ = ("_deadline" , "_loop" , "_state" , "_timeout_handler" )
98
+ __slots__ = ("_deadline" , "_loop" , "_state" , "_timeout_handler" , "_task" )
88
99
89
100
def __init__ (
90
101
self , deadline : Optional [float ], loop : asyncio .AbstractEventLoop
91
102
) -> None :
92
103
self ._loop = loop
93
104
self ._state = _State .INIT
94
105
106
+ self ._task : Optional ["asyncio.Task[object]" ] = None
95
107
self ._timeout_handler = None # type: Optional[asyncio.Handle]
96
108
if deadline is None :
97
109
self ._deadline = None # type: Optional[float]
@@ -147,6 +159,7 @@ def reject(self) -> None:
147
159
self ._reject ()
148
160
149
161
def _reject (self ) -> None :
162
+ self ._task = None
150
163
if self ._timeout_handler is not None :
151
164
self ._timeout_handler .cancel ()
152
165
self ._timeout_handler = None
@@ -194,11 +207,11 @@ def _reschedule(self) -> None:
194
207
if self ._timeout_handler is not None :
195
208
self ._timeout_handler .cancel ()
196
209
197
- task = asyncio .current_task ()
210
+ self . _task = asyncio .current_task ()
198
211
if deadline <= now :
199
- self ._timeout_handler = self ._loop .call_soon (self ._on_timeout , task )
212
+ self ._timeout_handler = self ._loop .call_soon (self ._on_timeout )
200
213
else :
201
- self ._timeout_handler = self ._loop .call_at (deadline , self ._on_timeout , task )
214
+ self ._timeout_handler = self ._loop .call_at (deadline , self ._on_timeout )
202
215
203
216
def _do_enter (self ) -> None :
204
217
if self ._state != _State .INIT :
@@ -208,15 +221,19 @@ def _do_enter(self) -> None:
208
221
209
222
def _do_exit (self , exc_type : Optional [Type [BaseException ]]) -> None :
210
223
if exc_type is asyncio .CancelledError and self ._state == _State .TIMEOUT :
224
+ assert self ._task is not None
225
+ _uncancel_task (self ._task )
211
226
self ._timeout_handler = None
227
+ self ._task = None
212
228
raise asyncio .TimeoutError
213
229
# timeout has not expired
214
230
self ._state = _State .EXIT
215
231
self ._reject ()
216
232
return None
217
233
218
- def _on_timeout (self , task : "asyncio.Task[None]" ) -> None :
219
- task .cancel ()
234
+ def _on_timeout (self ) -> None :
235
+ assert self ._task is not None
236
+ self ._task .cancel ()
220
237
self ._state = _State .TIMEOUT
221
238
# drop the reference early
222
239
self ._timeout_handler = None
0 commit comments