@@ -293,6 +293,8 @@ It is recommended that coroutines use ``try/finally`` blocks to robustly
293293perform clean-up logic. In case :exc: `asyncio.CancelledError `
294294is explicitly caught, it should generally be propagated when
295295clean-up is complete. Most code can safely ignore :exc: `asyncio.CancelledError `.
296+ If a task needs to continue despite receiving an :exc: `asyncio.CancelledError `,
297+ it should :func: `uncancel itself <asyncio.Task.uncancel> `.
296298
297299Important asyncio components, like :class: `asyncio.TaskGroup ` and the
298300:func: `asyncio.timeout ` context manager, are implemented using cancellation
@@ -1064,6 +1066,36 @@ Task Object
10641066 :meth: `cancel ` and the wrapped coroutine propagated the
10651067 :exc: `CancelledError ` exception thrown into it.
10661068
1069+ .. method :: cancelling()
1070+
1071+ Return the number of cancellation requests to this Task, i.e.,
1072+ the number of calls to :meth: `cancel `.
1073+
1074+ Note that if this number is greater than zero but the Task is
1075+ still executing, :meth: `cancelled ` will still return ``False ``.
1076+ It's because this number can be lowered by calling :meth: `uncancel `,
1077+ which can lead to the task not being cancelled after all if the
1078+ cancellation requests go down to zero.
1079+
1080+ .. method :: uncancel()
1081+
1082+ Decrement the count of cancellation requests to this Task.
1083+
1084+ Returns the remaining number of cancellation requests.
1085+
1086+ This should be used by tasks that catch :exc: `CancelledError `
1087+ and wish to continue indefinitely until they are cancelled again::
1088+
1089+ async def resilient_task():
1090+ try:
1091+ await do_work()
1092+ except asyncio.CancelledError:
1093+ asyncio.current_task().uncancel()
1094+ await do_work()
1095+
1096+ Note that once execution of a cancelled task completed, further
1097+ calls to :meth: `uncancel ` are ineffective.
1098+
10671099 .. method :: done()
10681100
10691101 Return ``True `` if the Task is *done *.
0 commit comments