1212 from typing_extensions import final
1313
1414
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+
1526__version__ = "4.0.2"
1627
1728
@@ -84,14 +95,15 @@ class Timeout:
8495 # The purpose is to time out as soon as possible
8596 # without waiting for the next await expression.
8697
87- __slots__ = ("_deadline" , "_loop" , "_state" , "_timeout_handler" )
98+ __slots__ = ("_deadline" , "_loop" , "_state" , "_timeout_handler" , "_task" )
8899
89100 def __init__ (
90101 self , deadline : Optional [float ], loop : asyncio .AbstractEventLoop
91102 ) -> None :
92103 self ._loop = loop
93104 self ._state = _State .INIT
94105
106+ self ._task : Optional ["asyncio.Task[object]" ] = None
95107 self ._timeout_handler = None # type: Optional[asyncio.Handle]
96108 if deadline is None :
97109 self ._deadline = None # type: Optional[float]
@@ -147,6 +159,7 @@ def reject(self) -> None:
147159 self ._reject ()
148160
149161 def _reject (self ) -> None :
162+ self ._task = None
150163 if self ._timeout_handler is not None :
151164 self ._timeout_handler .cancel ()
152165 self ._timeout_handler = None
@@ -194,11 +207,11 @@ def _reschedule(self) -> None:
194207 if self ._timeout_handler is not None :
195208 self ._timeout_handler .cancel ()
196209
197- task = asyncio .current_task ()
210+ self . _task = asyncio .current_task ()
198211 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 )
200213 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 )
202215
203216 def _do_enter (self ) -> None :
204217 if self ._state != _State .INIT :
@@ -208,15 +221,19 @@ def _do_enter(self) -> None:
208221
209222 def _do_exit (self , exc_type : Optional [Type [BaseException ]]) -> None :
210223 if exc_type is asyncio .CancelledError and self ._state == _State .TIMEOUT :
224+ assert self ._task is not None
225+ _uncancel_task (self ._task )
211226 self ._timeout_handler = None
227+ self ._task = None
212228 raise asyncio .TimeoutError
213229 # timeout has not expired
214230 self ._state = _State .EXIT
215231 self ._reject ()
216232 return None
217233
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 ()
220237 self ._state = _State .TIMEOUT
221238 # drop the reference early
222239 self ._timeout_handler = None
0 commit comments