diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 5bde6870717c90..83380ada67838c 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -43,6 +43,20 @@ always available. functions will not see the hook. +.. function:: addpendingcall(callback) + + Schedule a *callback* to eventually execute in the main thread. + + A :exc:`RuntimeError` is raised if the *callback* could not be + scheduled. + + If *callback* raises an exception it is converted into an + *unraisable exception*, see :func:`sys.unraisablehook` for more + details. + + .. versionadded:: 3.8 + + .. data:: argv The list of command line arguments passed to a Python script. ``argv[0]`` is the diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-05-29-18-47-09.bpo-37088.ZsTtci.rst b/Misc/NEWS.d/next/Core and Builtins/2019-05-29-18-47-09.bpo-37088.ZsTtci.rst new file mode 100644 index 00000000000000..2542ef76ff80de --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2019-05-29-18-47-09.bpo-37088.ZsTtci.rst @@ -0,0 +1 @@ +Add the sys.addpendingcall() function. diff --git a/Python/clinic/sysmodule.c.h b/Python/clinic/sysmodule.c.h index 6f248ff18d9d7f..372352d752797e 100644 --- a/Python/clinic/sysmodule.c.h +++ b/Python/clinic/sysmodule.c.h @@ -1051,6 +1051,38 @@ sys_getandroidapilevel(PyObject *module, PyObject *Py_UNUSED(ignored)) #endif /* defined(ANDROID_API_LEVEL) */ +PyDoc_STRVAR(sys_addpendingcall__doc__, +"addpendingcall($module, /, callback)\n" +"--\n" +"\n" +"Schedule a *callback* to eventually execute in the main thread."); + +#define SYS_ADDPENDINGCALL_METHODDEF \ + {"addpendingcall", (PyCFunction)(void(*)(void))sys_addpendingcall, METH_FASTCALL|METH_KEYWORDS, sys_addpendingcall__doc__}, + +static PyObject * +sys_addpendingcall_impl(PyObject *module, PyObject *callback); + +static PyObject * +sys_addpendingcall(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"callback", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "addpendingcall", 0}; + PyObject *argsbuf[1]; + PyObject *callback; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + callback = args[0]; + return_value = sys_addpendingcall_impl(module, callback); + +exit: + return return_value; +} + #ifndef SYS_GETWINDOWSVERSION_METHODDEF #define SYS_GETWINDOWSVERSION_METHODDEF #endif /* !defined(SYS_GETWINDOWSVERSION_METHODDEF) */ @@ -1082,4 +1114,4 @@ sys_getandroidapilevel(PyObject *module, PyObject *Py_UNUSED(ignored)) #ifndef SYS_GETANDROIDAPILEVEL_METHODDEF #define SYS_GETANDROIDAPILEVEL_METHODDEF #endif /* !defined(SYS_GETANDROIDAPILEVEL_METHODDEF) */ -/*[clinic end generated code: output=43c4fde7b5783d8d input=a9049054013a1b77]*/ +/*[clinic end generated code: output=d09a9c68a5603785 input=a9049054013a1b77]*/ diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 343601ec8596f1..7d975f593327ae 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1895,6 +1895,44 @@ sys_getandroidapilevel_impl(PyObject *module) #endif /* ANDROID_API_LEVEL */ +static int +_call_pending_pycallback(void *arg) +{ + PyObject *callback = (PyObject *)arg; + PyObject *res = PyObject_CallFunctionObjArgs(callback, NULL); + + if (res == NULL) { + PyErr_WriteUnraisable(callback); + } + else { + Py_DECREF(res); + } + + return 0; +} + + +/*[clinic input] +sys.addpendingcall + + callback: object + +Schedule a *callback* to eventually execute in the main thread. +[clinic start generated code]*/ + +static PyObject * +sys_addpendingcall_impl(PyObject *module, PyObject *callback) +/*[clinic end generated code: output=8af6dede85199179 input=edaaec4bd3f2c753]*/ +{ + if (Py_AddPendingCall(&_call_pending_pycallback, (void *)callback)) { + PyErr_SetString(PyExc_RuntimeError, + "failed to add a pending callback"); + return NULL; + } + + Py_RETURN_NONE; +} + static PyMethodDef sys_methods[] = { /* Might as well keep this in alphabetic order */ @@ -1902,6 +1940,7 @@ static PyMethodDef sys_methods[] = { {"audit", (PyCFunction)(void(*)(void))sys_audit, METH_FASTCALL, audit_doc }, {"breakpointhook", (PyCFunction)(void(*)(void))sys_breakpointhook, METH_FASTCALL | METH_KEYWORDS, breakpointhook_doc}, + SYS_ADDPENDINGCALL_METHODDEF SYS_CALLSTATS_METHODDEF SYS__CLEAR_TYPE_CACHE_METHODDEF SYS__CURRENT_FRAMES_METHODDEF