@@ -294,11 +294,13 @@ perform 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 `.
296296
297- Important asyncio components, like :class: `asyncio.TaskGroup ` and the
298- :func: `asyncio.timeout ` context manager, are implemented using cancellation
299- internally and might misbehave if a coroutine swallows
300- :exc: `asyncio.CancelledError `.
297+ The asyncio components that enable structured concurrency, like
298+ :class: `asyncio.TaskGroup ` and :func: `asyncio.timeout `,
299+ are implemented using cancellation internally and might misbehave if
300+ a coroutine swallows :exc: `asyncio.CancelledError `. Similarly, user code
301+ should not call :meth: `uncancel <asyncio.Task.uncancel> `.
301302
303+ .. _taskgroups :
302304
303305Task Groups
304306===========
@@ -1003,76 +1005,6 @@ Task Object
10031005 Deprecation warning is emitted if *loop * is not specified
10041006 and there is no running event loop.
10051007
1006- .. method :: cancel(msg=None)
1007-
1008- Request the Task to be cancelled.
1009-
1010- This arranges for a :exc: `CancelledError ` exception to be thrown
1011- into the wrapped coroutine on the next cycle of the event loop.
1012-
1013- The coroutine then has a chance to clean up or even deny the
1014- request by suppressing the exception with a :keyword: `try ` ...
1015- ... ``except CancelledError `` ... :keyword: `finally ` block.
1016- Therefore, unlike :meth: `Future.cancel `, :meth: `Task.cancel ` does
1017- not guarantee that the Task will be cancelled, although
1018- suppressing cancellation completely is not common and is actively
1019- discouraged.
1020-
1021- .. versionchanged :: 3.9
1022- Added the *msg * parameter.
1023-
1024- .. deprecated-removed :: 3.11 3.14
1025- *msg * parameter is ambiguous when multiple :meth: `cancel `
1026- are called with different cancellation messages.
1027- The argument will be removed.
1028-
1029- .. _asyncio_example_task_cancel :
1030-
1031- The following example illustrates how coroutines can intercept
1032- the cancellation request::
1033-
1034- async def cancel_me():
1035- print('cancel_me(): before sleep')
1036-
1037- try:
1038- # Wait for 1 hour
1039- await asyncio.sleep(3600)
1040- except asyncio.CancelledError:
1041- print('cancel_me(): cancel sleep')
1042- raise
1043- finally:
1044- print('cancel_me(): after sleep')
1045-
1046- async def main():
1047- # Create a "cancel_me" Task
1048- task = asyncio.create_task(cancel_me())
1049-
1050- # Wait for 1 second
1051- await asyncio.sleep(1)
1052-
1053- task.cancel()
1054- try:
1055- await task
1056- except asyncio.CancelledError:
1057- print("main(): cancel_me is cancelled now")
1058-
1059- asyncio.run(main())
1060-
1061- # Expected output:
1062- #
1063- # cancel_me(): before sleep
1064- # cancel_me(): cancel sleep
1065- # cancel_me(): after sleep
1066- # main(): cancel_me is cancelled now
1067-
1068- .. method :: cancelled()
1069-
1070- Return ``True `` if the Task is *cancelled *.
1071-
1072- The Task is *cancelled * when the cancellation was requested with
1073- :meth: `cancel ` and the wrapped coroutine propagated the
1074- :exc: `CancelledError ` exception thrown into it.
1075-
10761008 .. method :: done()
10771009
10781010 Return ``True `` if the Task is *done *.
@@ -1186,3 +1118,125 @@ Task Object
11861118 in the :func: `repr ` output of a task object.
11871119
11881120 .. versionadded :: 3.8
1121+
1122+ .. method :: cancel(msg=None)
1123+
1124+ Request the Task to be cancelled.
1125+
1126+ This arranges for a :exc: `CancelledError ` exception to be thrown
1127+ into the wrapped coroutine on the next cycle of the event loop.
1128+
1129+ The coroutine then has a chance to clean up or even deny the
1130+ request by suppressing the exception with a :keyword: `try ` ...
1131+ ... ``except CancelledError `` ... :keyword: `finally ` block.
1132+ Therefore, unlike :meth: `Future.cancel `, :meth: `Task.cancel ` does
1133+ not guarantee that the Task will be cancelled, although
1134+ suppressing cancellation completely is not common and is actively
1135+ discouraged.
1136+
1137+ .. versionchanged :: 3.9
1138+ Added the *msg * parameter.
1139+
1140+ .. deprecated-removed :: 3.11 3.14
1141+ *msg * parameter is ambiguous when multiple :meth: `cancel `
1142+ are called with different cancellation messages.
1143+ The argument will be removed.
1144+
1145+ .. _asyncio_example_task_cancel :
1146+
1147+ The following example illustrates how coroutines can intercept
1148+ the cancellation request::
1149+
1150+ async def cancel_me():
1151+ print('cancel_me(): before sleep')
1152+
1153+ try:
1154+ # Wait for 1 hour
1155+ await asyncio.sleep(3600)
1156+ except asyncio.CancelledError:
1157+ print('cancel_me(): cancel sleep')
1158+ raise
1159+ finally:
1160+ print('cancel_me(): after sleep')
1161+
1162+ async def main():
1163+ # Create a "cancel_me" Task
1164+ task = asyncio.create_task(cancel_me())
1165+
1166+ # Wait for 1 second
1167+ await asyncio.sleep(1)
1168+
1169+ task.cancel()
1170+ try:
1171+ await task
1172+ except asyncio.CancelledError:
1173+ print("main(): cancel_me is cancelled now")
1174+
1175+ asyncio.run(main())
1176+
1177+ # Expected output:
1178+ #
1179+ # cancel_me(): before sleep
1180+ # cancel_me(): cancel sleep
1181+ # cancel_me(): after sleep
1182+ # main(): cancel_me is cancelled now
1183+
1184+ .. method :: cancelled()
1185+
1186+ Return ``True `` if the Task is *cancelled *.
1187+
1188+ The Task is *cancelled * when the cancellation was requested with
1189+ :meth: `cancel ` and the wrapped coroutine propagated the
1190+ :exc: `CancelledError ` exception thrown into it.
1191+
1192+ .. method :: uncancel()
1193+
1194+ Decrement the count of cancellation requests to this Task.
1195+
1196+ Returns the remaining number of cancellation requests.
1197+
1198+ Note that once execution of a cancelled task completed, further
1199+ calls to :meth: `uncancel ` are ineffective.
1200+
1201+ .. versionadded :: 3.11
1202+
1203+ This method is used by asyncio's internals and isn't expected to be
1204+ used by end-user code. In particular, if a Task gets successfully
1205+ uncancelled, this allows for elements of structured concurrency like
1206+ :ref: `taskgroups ` and :func: `asyncio.timeout ` to continue running,
1207+ isolating cancellation to the respective structured block.
1208+ For example::
1209+
1210+ async def make_request_with_timeout():
1211+ try:
1212+ async with asyncio.timeout(1):
1213+ # Structured block affected by the timeout:
1214+ await make_request()
1215+ await make_another_request()
1216+ except TimeoutError:
1217+ log("There was a timeout")
1218+ # Outer code not affected by the timeout:
1219+ await unrelated_code()
1220+
1221+ While the block with ``make_request() `` and ``make_another_request() ``
1222+ might get cancelled due to the timeout, ``unrelated_code() `` should
1223+ continue running even in case of the timeout. This is implemented
1224+ with :meth: `uncancel `. :class: `TaskGroup ` context managers use
1225+ :func: `uncancel ` in a similar fashion.
1226+
1227+ .. method :: cancelling()
1228+
1229+ Return the number of pending cancellation requests to this Task, i.e.,
1230+ the number of calls to :meth: `cancel ` less the number of
1231+ :meth: `uncancel ` calls.
1232+
1233+ Note that if this number is greater than zero but the Task is
1234+ still executing, :meth: `cancelled ` will still return ``False ``.
1235+ This is because this number can be lowered by calling :meth: `uncancel `,
1236+ which can lead to the task not being cancelled after all if the
1237+ cancellation requests go down to zero.
1238+
1239+ This method is used by asyncio's internals and isn't expected to be
1240+ used by end-user code. See :meth: `uncancel ` for more details.
1241+
1242+ .. versionadded :: 3.11
0 commit comments