diff options
author | Guido van Rossum <guido@python.org> | 2022-02-15 23:42:04 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-02-15 23:42:04 (GMT) |
commit | 602630ac1855e38ef06361c68f6e216375a06180 (patch) | |
tree | 58a3f509fd92945d2676b0030c251713461460b6 /Modules/clinic/_asynciomodule.c.h | |
parent | 08ec80113b3b7f7a9eaa3d217494536b63305181 (diff) | |
download | cpython-602630ac1855e38ef06361c68f6e216375a06180.zip cpython-602630ac1855e38ef06361c68f6e216375a06180.tar.gz cpython-602630ac1855e38ef06361c68f6e216375a06180.tar.bz2 |
bpo-46752: Add TaskGroup; add Task..cancelled(),.uncancel() (GH-31270)
asyncio/taskgroups.py is an adaptation of taskgroup.py from EdgeDb, with the following key changes:
- Allow creating new tasks as long as the last task hasn't finished
- Raise [Base]ExceptionGroup (directly) rather than TaskGroupError deriving from MultiError
- Instead of monkey-patching the parent task's cancel() method,
add a new public API to Task
The Task class has a new internal flag, `_cancel_requested`, which is set when `.cancel()` is called successfully. The `.cancelling()` method returns the value of this flag. Further `.cancel()` calls while this flag is set return False. To reset this flag, call `.uncancel()`.
Thus, a Task that catches and ignores `CancelledError` should call `.uncancel()` if it wants to be cancellable again; until it does so, it is deemed to be busy with uninterruptible cleanup.
This new Task API helps solve the problem where TaskGroup needs to distinguish between whether the parent task being cancelled "from the outside" vs. "from inside".
Co-authored-by: Yury Selivanov <yury@edgedb.com>
Co-authored-by: Andrew Svetlov <andrew.svetlov@gmail.com>
Diffstat (limited to 'Modules/clinic/_asynciomodule.c.h')
-rw-r--r-- | Modules/clinic/_asynciomodule.c.h | 49 |
1 files changed, 48 insertions, 1 deletions
diff --git a/Modules/clinic/_asynciomodule.c.h b/Modules/clinic/_asynciomodule.c.h index c472e65..5648e14 100644 --- a/Modules/clinic/_asynciomodule.c.h +++ b/Modules/clinic/_asynciomodule.c.h @@ -447,6 +447,53 @@ exit: return return_value; } +PyDoc_STRVAR(_asyncio_Task_cancelling__doc__, +"cancelling($self, /)\n" +"--\n" +"\n" +"Return True if the task is in the process of being cancelled.\n" +"\n" +"This is set once .cancel() is called\n" +"and remains set until .uncancel() is called.\n" +"\n" +"As long as this flag is set, further .cancel() calls will be ignored,\n" +"until .uncancel() is called to reset it."); + +#define _ASYNCIO_TASK_CANCELLING_METHODDEF \ + {"cancelling", (PyCFunction)_asyncio_Task_cancelling, METH_NOARGS, _asyncio_Task_cancelling__doc__}, + +static PyObject * +_asyncio_Task_cancelling_impl(TaskObj *self); + +static PyObject * +_asyncio_Task_cancelling(TaskObj *self, PyObject *Py_UNUSED(ignored)) +{ + return _asyncio_Task_cancelling_impl(self); +} + +PyDoc_STRVAR(_asyncio_Task_uncancel__doc__, +"uncancel($self, /)\n" +"--\n" +"\n" +"Reset the flag returned by cancelling().\n" +"\n" +"This should be used by tasks that catch CancelledError\n" +"and wish to continue indefinitely until they are cancelled again.\n" +"\n" +"Returns the previous value of the flag."); + +#define _ASYNCIO_TASK_UNCANCEL_METHODDEF \ + {"uncancel", (PyCFunction)_asyncio_Task_uncancel, METH_NOARGS, _asyncio_Task_uncancel__doc__}, + +static PyObject * +_asyncio_Task_uncancel_impl(TaskObj *self); + +static PyObject * +_asyncio_Task_uncancel(TaskObj *self, PyObject *Py_UNUSED(ignored)) +{ + return _asyncio_Task_uncancel_impl(self); +} + PyDoc_STRVAR(_asyncio_Task_get_stack__doc__, "get_stack($self, /, *, limit=None)\n" "--\n" @@ -871,4 +918,4 @@ _asyncio__leave_task(PyObject *module, PyObject *const *args, Py_ssize_t nargs, exit: return return_value; } -/*[clinic end generated code: output=0d127162ac92e0c0 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=c02708a9d6a774cc input=a9049054013a1b77]*/ |