diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 087a3454c33272..d651cc28cf79cd 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -1666,7 +1666,7 @@ always available. ``'opcode'`` event type added; :attr:`~frame.f_trace_lines` and :attr:`~frame.f_trace_opcodes` attributes added to frames -.. function:: set_asyncgen_hooks([firstiter] [, finalizer]) +.. function:: set_asyncgen_hooks(*, firstiter=None, finalizer=None) Accepts two optional keyword arguments which are callables that accept an :term:`asynchronous generator iterator` as an argument. The *firstiter* diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index d2287687181450..20568d9582a1f3 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -946,7 +946,9 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(filter)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(filters)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(final)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(finalizer)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(find_class)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(firstiter)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(fix_imports)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(flags)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(flush)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index fb9ec44d3f52aa..f7cdb68e98d7b7 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -435,7 +435,9 @@ struct _Py_global_strings { STRUCT_FOR_ID(filter) STRUCT_FOR_ID(filters) STRUCT_FOR_ID(final) + STRUCT_FOR_ID(finalizer) STRUCT_FOR_ID(find_class) + STRUCT_FOR_ID(firstiter) STRUCT_FOR_ID(fix_imports) STRUCT_FOR_ID(flags) STRUCT_FOR_ID(flush) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index 658bf8030f661d..a4892f81dd7afa 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -944,7 +944,9 @@ extern "C" { INIT_ID(filter), \ INIT_ID(filters), \ INIT_ID(final), \ + INIT_ID(finalizer), \ INIT_ID(find_class), \ + INIT_ID(firstiter), \ INIT_ID(fix_imports), \ INIT_ID(flags), \ INIT_ID(flush), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index d72353d56eae60..58c8b48a3e28fb 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -1146,9 +1146,15 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { string = &_Py_ID(final); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); + string = &_Py_ID(finalizer); + assert(_PyUnicode_CheckConsistency(string, 1)); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(find_class); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); + string = &_Py_ID(firstiter); + assert(_PyUnicode_CheckConsistency(string, 1)); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(fix_imports); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); diff --git a/Python/clinic/sysmodule.c.h b/Python/clinic/sysmodule.c.h index 13f4ea81eb8984..89c71ce6f84b34 100644 --- a/Python/clinic/sysmodule.c.h +++ b/Python/clinic/sysmodule.c.h @@ -579,6 +579,74 @@ sys_get_coroutine_origin_tracking_depth(PyObject *module, PyObject *Py_UNUSED(ig return return_value; } +PyDoc_STRVAR(sys_set_asyncgen_hooks__doc__, +"set_asyncgen_hooks($module, /, firstiter=None, finalizer=None)\n" +"--\n" +"\n" +"Set a finalizer for async generators objects."); + +#define SYS_SET_ASYNCGEN_HOOKS_METHODDEF \ + {"set_asyncgen_hooks", _PyCFunction_CAST(sys_set_asyncgen_hooks), METH_FASTCALL|METH_KEYWORDS, sys_set_asyncgen_hooks__doc__}, + +static PyObject * +sys_set_asyncgen_hooks_impl(PyObject *module, PyObject *firstiter, + PyObject *finalizer); + +static PyObject * +sys_set_asyncgen_hooks(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(firstiter), &_Py_ID(finalizer), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"firstiter", "finalizer", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "set_asyncgen_hooks", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *firstiter = Py_None; + PyObject *finalizer = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 2, 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (args[0]) { + firstiter = args[0]; + if (!--noptargs) { + goto skip_optional_pos; + } + } + finalizer = args[1]; +skip_optional_pos: + return_value = sys_set_asyncgen_hooks_impl(module, firstiter, finalizer); + +exit: + return return_value; +} + PyDoc_STRVAR(sys_get_asyncgen_hooks__doc__, "get_asyncgen_hooks($module, /)\n" "--\n" @@ -1504,4 +1572,4 @@ sys__get_cpu_count_config(PyObject *module, PyObject *Py_UNUSED(ignored)) #ifndef SYS_GETANDROIDAPILEVEL_METHODDEF #define SYS_GETANDROIDAPILEVEL_METHODDEF #endif /* !defined(SYS_GETANDROIDAPILEVEL_METHODDEF) */ -/*[clinic end generated code: output=b8b1c53e04c3b20c input=a9049054013a1b77]*/ +/*[clinic end generated code: output=2aa9dd082c0d9464 input=a9049054013a1b77]*/ diff --git a/Python/sysmodule.c b/Python/sysmodule.c index cd193c1581c679..2abd764309787d 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1373,19 +1373,20 @@ static PyStructSequence_Desc asyncgen_hooks_desc = { 2 }; -static PyObject * -sys_set_asyncgen_hooks(PyObject *self, PyObject *args, PyObject *kw) -{ - static char *keywords[] = {"firstiter", "finalizer", NULL}; - PyObject *firstiter = NULL; - PyObject *finalizer = NULL; +/*[clinic input] +sys.set_asyncgen_hooks - if (!PyArg_ParseTupleAndKeywords( - args, kw, "|OO", keywords, - &firstiter, &finalizer)) { - return NULL; - } + firstiter: object = None + finalizer: object = None + +Set a finalizer for async generators objects. +[clinic start generated code]*/ +static PyObject * +sys_set_asyncgen_hooks_impl(PyObject *module, PyObject *firstiter, + PyObject *finalizer) +/*[clinic end generated code: output=6fe3b2dd3f9a9db5 input=3664f349bc833d43]*/ +{ if (finalizer && finalizer != Py_None) { if (!PyCallable_Check(finalizer)) { PyErr_Format(PyExc_TypeError, @@ -1419,12 +1420,6 @@ sys_set_asyncgen_hooks(PyObject *self, PyObject *args, PyObject *kw) Py_RETURN_NONE; } -PyDoc_STRVAR(set_asyncgen_hooks_doc, -"set_asyncgen_hooks([firstiter] [, finalizer])\n\ -\n\ -Set a finalizer for async generators objects." -); - /*[clinic input] sys.get_asyncgen_hooks @@ -2536,8 +2531,7 @@ static PyMethodDef sys_methods[] = { SYS__DEBUGMALLOCSTATS_METHODDEF SYS_SET_COROUTINE_ORIGIN_TRACKING_DEPTH_METHODDEF SYS_GET_COROUTINE_ORIGIN_TRACKING_DEPTH_METHODDEF - {"set_asyncgen_hooks", _PyCFunction_CAST(sys_set_asyncgen_hooks), - METH_VARARGS | METH_KEYWORDS, set_asyncgen_hooks_doc}, + SYS_SET_ASYNCGEN_HOOKS_METHODDEF SYS_GET_ASYNCGEN_HOOKS_METHODDEF SYS_GETANDROIDAPILEVEL_METHODDEF SYS_ACTIVATE_STACK_TRAMPOLINE_METHODDEF