From 2442d0236dfef71dbb93b2fcb9b78ace91c60f6e Mon Sep 17 00:00:00 2001 From: littlebutt Date: Sun, 9 Jul 2023 10:45:17 +0800 Subject: [PATCH 1/6] gh-104469 Convert_testcapi/vectorcall.c to use AC --- Modules/_testcapi/clinic/vectorcall.c.h | 110 +++++++++++++++++++++++- Modules/_testcapi/vectorcall.c | 65 ++++++++------ 2 files changed, 150 insertions(+), 25 deletions(-) diff --git a/Modules/_testcapi/clinic/vectorcall.c.h b/Modules/_testcapi/clinic/vectorcall.c.h index 765afeda9b306c..295a4c04633c0c 100644 --- a/Modules/_testcapi/clinic/vectorcall.c.h +++ b/Modules/_testcapi/clinic/vectorcall.c.h @@ -8,6 +8,114 @@ preserve #endif +PyDoc_STRVAR(_testcapi_test_pyobject_fastcalldict__doc__, +"test_pyobject_fastcalldict($module, func, func_args, kwargs, /)\n" +"--\n" +"\n"); + +#define _TESTCAPI_TEST_PYOBJECT_FASTCALLDICT_METHODDEF \ + {"test_pyobject_fastcalldict", _PyCFunction_CAST(_testcapi_test_pyobject_fastcalldict), METH_FASTCALL, _testcapi_test_pyobject_fastcalldict__doc__}, + +static PyObject * +_testcapi_test_pyobject_fastcalldict_impl(PyObject *module, PyObject *func, + PyObject *func_args, + PyObject *kwargs); + +static PyObject * +_testcapi_test_pyobject_fastcalldict(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *func; + PyObject *func_args; + PyObject *__clinic_kwargs; + + if (!_PyArg_CheckPositional("test_pyobject_fastcalldict", nargs, 3, 3)) { + goto exit; + } + func = args[0]; + func_args = args[1]; + __clinic_kwargs = args[2]; + return_value = _testcapi_test_pyobject_fastcalldict_impl(module, func, func_args, __clinic_kwargs); + +exit: + return return_value; +} + +PyDoc_STRVAR(_testcapi_test_pyobject_vectorcall__doc__, +"test_pyobject_vectorcall($module, func, func_args,\n" +" kwnames=, /)\n" +"--\n" +"\n"); + +#define _TESTCAPI_TEST_PYOBJECT_VECTORCALL_METHODDEF \ + {"test_pyobject_vectorcall", _PyCFunction_CAST(_testcapi_test_pyobject_vectorcall), METH_FASTCALL, _testcapi_test_pyobject_vectorcall__doc__}, + +static PyObject * +_testcapi_test_pyobject_vectorcall_impl(PyObject *module, PyObject *func, + PyObject *func_args, + PyObject *kwnames); + +static PyObject * +_testcapi_test_pyobject_vectorcall(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *func; + PyObject *func_args; + PyObject *__clinic_kwnames = NULL; + + if (!_PyArg_CheckPositional("test_pyobject_vectorcall", nargs, 2, 3)) { + goto exit; + } + func = args[0]; + func_args = args[1]; + if (nargs < 3) { + goto skip_optional; + } + __clinic_kwnames = args[2]; +skip_optional: + return_value = _testcapi_test_pyobject_vectorcall_impl(module, func, func_args, __clinic_kwnames); + +exit: + return return_value; +} + +PyDoc_STRVAR(_testcapi_test_pyvectorcall_call__doc__, +"test_pyvectorcall_call($module, func, argstuple,\n" +" kwargs=, /)\n" +"--\n" +"\n"); + +#define _TESTCAPI_TEST_PYVECTORCALL_CALL_METHODDEF \ + {"test_pyvectorcall_call", _PyCFunction_CAST(_testcapi_test_pyvectorcall_call), METH_FASTCALL, _testcapi_test_pyvectorcall_call__doc__}, + +static PyObject * +_testcapi_test_pyvectorcall_call_impl(PyObject *module, PyObject *func, + PyObject *argstuple, PyObject *kwargs); + +static PyObject * +_testcapi_test_pyvectorcall_call(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *func; + PyObject *argstuple; + PyObject *__clinic_kwargs = NULL; + + if (!_PyArg_CheckPositional("test_pyvectorcall_call", nargs, 2, 3)) { + goto exit; + } + func = args[0]; + argstuple = args[1]; + if (nargs < 3) { + goto skip_optional; + } + __clinic_kwargs = args[2]; +skip_optional: + return_value = _testcapi_test_pyvectorcall_call_impl(module, func, argstuple, __clinic_kwargs); + +exit: + return return_value; +} + PyDoc_STRVAR(_testcapi_VectorCallClass_set_vectorcall__doc__, "set_vectorcall($self, type, /)\n" "--\n" @@ -110,4 +218,4 @@ _testcapi_has_vectorcall_flag(PyObject *module, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=609569aa9942584f input=a9049054013a1b77]*/ +/*[clinic end generated code: output=5960972282b4bd2f input=a9049054013a1b77]*/ diff --git a/Modules/_testcapi/vectorcall.c b/Modules/_testcapi/vectorcall.c index 4935fd1b6a7ba3..abf5c24ea770ab 100644 --- a/Modules/_testcapi/vectorcall.c +++ b/Modules/_testcapi/vectorcall.c @@ -4,6 +4,10 @@ #include "structmember.h" // PyMemberDef #include // offsetof +/*[clinic input] +module _testcapi +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=6361033e795369fc]*/ /* Test PEP 590 - Vectorcall */ @@ -25,18 +29,23 @@ fastcall_args(PyObject *args, PyObject ***stack, Py_ssize_t *nargs) return 0; } +/*[clinic input] +_testcapi.test_pyobject_fastcalldict + func: object + func_args: object + kwargs: object + / +[clinic start generated code]*/ static PyObject * -test_pyobject_fastcalldict(PyObject *self, PyObject *args) +_testcapi_test_pyobject_fastcalldict_impl(PyObject *module, PyObject *func, + PyObject *func_args, + PyObject *kwargs) +/*[clinic end generated code: output=a39da56b27d27212 input=94464574e929fbe5]*/ { - PyObject *func, *func_args, *kwargs; PyObject **stack; Py_ssize_t nargs; - if (!PyArg_ParseTuple(args, "OOO", &func, &func_args, &kwargs)) { - return NULL; - } - if (fastcall_args(func_args, &stack, &nargs) < 0) { return NULL; } @@ -52,17 +61,23 @@ test_pyobject_fastcalldict(PyObject *self, PyObject *args) return PyObject_VectorcallDict(func, stack, nargs, kwargs); } +/*[clinic input] +_testcapi.test_pyobject_vectorcall + func: object + func_args: object + kwnames: object = NULL + / +[clinic start generated code]*/ + static PyObject * -test_pyobject_vectorcall(PyObject *self, PyObject *args) +_testcapi_test_pyobject_vectorcall_impl(PyObject *module, PyObject *func, + PyObject *func_args, + PyObject *kwnames) +/*[clinic end generated code: output=bb25a5410142b848 input=14dd1f8bbc465b49]*/ { - PyObject *func, *func_args, *kwnames = NULL; PyObject **stack; Py_ssize_t nargs, nkw; - if (!PyArg_ParseTuple(args, "OOO", &func, &func_args, &kwnames)) { - return NULL; - } - if (fastcall_args(func_args, &stack, &nargs) < 0) { return NULL; } @@ -103,17 +118,19 @@ function_setvectorcall(PyObject *self, PyObject *func) Py_RETURN_NONE; } +/*[clinic input] +_testcapi.test_pyvectorcall_call + func: object + argstuple: object + kwargs: object = NULL + / +[clinic start generated code]*/ + static PyObject * -test_pyvectorcall_call(PyObject *self, PyObject *args) +_testcapi_test_pyvectorcall_call_impl(PyObject *module, PyObject *func, + PyObject *argstuple, PyObject *kwargs) +/*[clinic end generated code: output=f9f5cbdfe90dd6d6 input=4cc647aa0c81365a]*/ { - PyObject *func; - PyObject *argstuple; - PyObject *kwargs = NULL; - - if (!PyArg_ParseTuple(args, "OO|O", &func, &argstuple, &kwargs)) { - return NULL; - } - if (!PyTuple_Check(argstuple)) { PyErr_SetString(PyExc_TypeError, "args must be a tuple"); return NULL; @@ -242,10 +259,10 @@ _testcapi_has_vectorcall_flag_impl(PyObject *module, PyTypeObject *type) } static PyMethodDef TestMethods[] = { - {"pyobject_fastcalldict", test_pyobject_fastcalldict, METH_VARARGS}, - {"pyobject_vectorcall", test_pyobject_vectorcall, METH_VARARGS}, + _TESTCAPI_TEST_PYOBJECT_FASTCALLDICT_METHODDEF + _TESTCAPI_TEST_PYOBJECT_VECTORCALL_METHODDEF {"function_setvectorcall", function_setvectorcall, METH_O}, - {"pyvectorcall_call", test_pyvectorcall_call, METH_VARARGS}, + _TESTCAPI_TEST_PYVECTORCALL_CALL_METHODDEF _TESTCAPI_MAKE_VECTORCALL_CLASS_METHODDEF _TESTCAPI_HAS_VECTORCALL_FLAG_METHODDEF {NULL}, From 291f92f1e380450cfdc8168d63379829fe4affad Mon Sep 17 00:00:00 2001 From: littlebutt Date: Sun, 9 Jul 2023 14:21:47 +0800 Subject: [PATCH 2/6] fix method names --- Modules/_testcapi/clinic/vectorcall.c.h | 62 ++++++++++++------------- Modules/_testcapi/vectorcall.c | 34 +++++++------- 2 files changed, 45 insertions(+), 51 deletions(-) diff --git a/Modules/_testcapi/clinic/vectorcall.c.h b/Modules/_testcapi/clinic/vectorcall.c.h index 295a4c04633c0c..aa307c86cba03d 100644 --- a/Modules/_testcapi/clinic/vectorcall.c.h +++ b/Modules/_testcapi/clinic/vectorcall.c.h @@ -8,62 +8,59 @@ preserve #endif -PyDoc_STRVAR(_testcapi_test_pyobject_fastcalldict__doc__, -"test_pyobject_fastcalldict($module, func, func_args, kwargs, /)\n" +PyDoc_STRVAR(_testcapi_pyobject_fastcalldict__doc__, +"pyobject_fastcalldict($module, func, func_args, kwargs, /)\n" "--\n" "\n"); -#define _TESTCAPI_TEST_PYOBJECT_FASTCALLDICT_METHODDEF \ - {"test_pyobject_fastcalldict", _PyCFunction_CAST(_testcapi_test_pyobject_fastcalldict), METH_FASTCALL, _testcapi_test_pyobject_fastcalldict__doc__}, +#define _TESTCAPI_PYOBJECT_FASTCALLDICT_METHODDEF \ + {"pyobject_fastcalldict", _PyCFunction_CAST(_testcapi_pyobject_fastcalldict), METH_FASTCALL, _testcapi_pyobject_fastcalldict__doc__}, static PyObject * -_testcapi_test_pyobject_fastcalldict_impl(PyObject *module, PyObject *func, - PyObject *func_args, - PyObject *kwargs); +_testcapi_pyobject_fastcalldict_impl(PyObject *module, PyObject *func, + PyObject *func_args, PyObject *kwargs); static PyObject * -_testcapi_test_pyobject_fastcalldict(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +_testcapi_pyobject_fastcalldict(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyObject *func; PyObject *func_args; PyObject *__clinic_kwargs; - if (!_PyArg_CheckPositional("test_pyobject_fastcalldict", nargs, 3, 3)) { + if (!_PyArg_CheckPositional("pyobject_fastcalldict", nargs, 3, 3)) { goto exit; } func = args[0]; func_args = args[1]; __clinic_kwargs = args[2]; - return_value = _testcapi_test_pyobject_fastcalldict_impl(module, func, func_args, __clinic_kwargs); + return_value = _testcapi_pyobject_fastcalldict_impl(module, func, func_args, __clinic_kwargs); exit: return return_value; } -PyDoc_STRVAR(_testcapi_test_pyobject_vectorcall__doc__, -"test_pyobject_vectorcall($module, func, func_args,\n" -" kwnames=, /)\n" +PyDoc_STRVAR(_testcapi_pyobject_vectorcall__doc__, +"pyobject_vectorcall($module, func, func_args, kwnames=None, /)\n" "--\n" "\n"); -#define _TESTCAPI_TEST_PYOBJECT_VECTORCALL_METHODDEF \ - {"test_pyobject_vectorcall", _PyCFunction_CAST(_testcapi_test_pyobject_vectorcall), METH_FASTCALL, _testcapi_test_pyobject_vectorcall__doc__}, +#define _TESTCAPI_PYOBJECT_VECTORCALL_METHODDEF \ + {"pyobject_vectorcall", _PyCFunction_CAST(_testcapi_pyobject_vectorcall), METH_FASTCALL, _testcapi_pyobject_vectorcall__doc__}, static PyObject * -_testcapi_test_pyobject_vectorcall_impl(PyObject *module, PyObject *func, - PyObject *func_args, - PyObject *kwnames); +_testcapi_pyobject_vectorcall_impl(PyObject *module, PyObject *func, + PyObject *func_args, PyObject *kwnames); static PyObject * -_testcapi_test_pyobject_vectorcall(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +_testcapi_pyobject_vectorcall(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyObject *func; PyObject *func_args; - PyObject *__clinic_kwnames = NULL; + PyObject *__clinic_kwnames = Py_None; - if (!_PyArg_CheckPositional("test_pyobject_vectorcall", nargs, 2, 3)) { + if (!_PyArg_CheckPositional("pyobject_vectorcall", nargs, 2, 3)) { goto exit; } func = args[0]; @@ -73,34 +70,33 @@ _testcapi_test_pyobject_vectorcall(PyObject *module, PyObject *const *args, Py_s } __clinic_kwnames = args[2]; skip_optional: - return_value = _testcapi_test_pyobject_vectorcall_impl(module, func, func_args, __clinic_kwnames); + return_value = _testcapi_pyobject_vectorcall_impl(module, func, func_args, __clinic_kwnames); exit: return return_value; } -PyDoc_STRVAR(_testcapi_test_pyvectorcall_call__doc__, -"test_pyvectorcall_call($module, func, argstuple,\n" -" kwargs=, /)\n" +PyDoc_STRVAR(_testcapi_pyvectorcall_call__doc__, +"pyvectorcall_call($module, func, argstuple, kwargs=, /)\n" "--\n" "\n"); -#define _TESTCAPI_TEST_PYVECTORCALL_CALL_METHODDEF \ - {"test_pyvectorcall_call", _PyCFunction_CAST(_testcapi_test_pyvectorcall_call), METH_FASTCALL, _testcapi_test_pyvectorcall_call__doc__}, +#define _TESTCAPI_PYVECTORCALL_CALL_METHODDEF \ + {"pyvectorcall_call", _PyCFunction_CAST(_testcapi_pyvectorcall_call), METH_FASTCALL, _testcapi_pyvectorcall_call__doc__}, static PyObject * -_testcapi_test_pyvectorcall_call_impl(PyObject *module, PyObject *func, - PyObject *argstuple, PyObject *kwargs); +_testcapi_pyvectorcall_call_impl(PyObject *module, PyObject *func, + PyObject *argstuple, PyObject *kwargs); static PyObject * -_testcapi_test_pyvectorcall_call(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +_testcapi_pyvectorcall_call(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyObject *func; PyObject *argstuple; PyObject *__clinic_kwargs = NULL; - if (!_PyArg_CheckPositional("test_pyvectorcall_call", nargs, 2, 3)) { + if (!_PyArg_CheckPositional("pyvectorcall_call", nargs, 2, 3)) { goto exit; } func = args[0]; @@ -110,7 +106,7 @@ _testcapi_test_pyvectorcall_call(PyObject *module, PyObject *const *args, Py_ssi } __clinic_kwargs = args[2]; skip_optional: - return_value = _testcapi_test_pyvectorcall_call_impl(module, func, argstuple, __clinic_kwargs); + return_value = _testcapi_pyvectorcall_call_impl(module, func, argstuple, __clinic_kwargs); exit: return return_value; @@ -218,4 +214,4 @@ _testcapi_has_vectorcall_flag(PyObject *module, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=5960972282b4bd2f input=a9049054013a1b77]*/ +/*[clinic end generated code: output=a7c09c9060137f4a input=a9049054013a1b77]*/ diff --git a/Modules/_testcapi/vectorcall.c b/Modules/_testcapi/vectorcall.c index abf5c24ea770ab..b6adffc04ec25a 100644 --- a/Modules/_testcapi/vectorcall.c +++ b/Modules/_testcapi/vectorcall.c @@ -30,7 +30,7 @@ fastcall_args(PyObject *args, PyObject ***stack, Py_ssize_t *nargs) } /*[clinic input] -_testcapi.test_pyobject_fastcalldict +_testcapi.pyobject_fastcalldict func: object func_args: object kwargs: object @@ -38,10 +38,9 @@ _testcapi.test_pyobject_fastcalldict [clinic start generated code]*/ static PyObject * -_testcapi_test_pyobject_fastcalldict_impl(PyObject *module, PyObject *func, - PyObject *func_args, - PyObject *kwargs) -/*[clinic end generated code: output=a39da56b27d27212 input=94464574e929fbe5]*/ +_testcapi_pyobject_fastcalldict_impl(PyObject *module, PyObject *func, + PyObject *func_args, PyObject *kwargs) +/*[clinic end generated code: output=35902ece94de4418 input=b9c0196ca7d5f9e4]*/ { PyObject **stack; Py_ssize_t nargs; @@ -62,18 +61,17 @@ _testcapi_test_pyobject_fastcalldict_impl(PyObject *module, PyObject *func, } /*[clinic input] -_testcapi.test_pyobject_vectorcall +_testcapi.pyobject_vectorcall func: object func_args: object - kwnames: object = NULL + kwnames: object = None / [clinic start generated code]*/ static PyObject * -_testcapi_test_pyobject_vectorcall_impl(PyObject *module, PyObject *func, - PyObject *func_args, - PyObject *kwnames) -/*[clinic end generated code: output=bb25a5410142b848 input=14dd1f8bbc465b49]*/ +_testcapi_pyobject_vectorcall_impl(PyObject *module, PyObject *func, + PyObject *func_args, PyObject *kwnames) +/*[clinic end generated code: output=ff77245bc6afe0d8 input=c427975e9408ca84]*/ { PyObject **stack; Py_ssize_t nargs, nkw; @@ -119,7 +117,7 @@ function_setvectorcall(PyObject *self, PyObject *func) } /*[clinic input] -_testcapi.test_pyvectorcall_call +_testcapi.pyvectorcall_call func: object argstuple: object kwargs: object = NULL @@ -127,9 +125,9 @@ _testcapi.test_pyvectorcall_call [clinic start generated code]*/ static PyObject * -_testcapi_test_pyvectorcall_call_impl(PyObject *module, PyObject *func, - PyObject *argstuple, PyObject *kwargs) -/*[clinic end generated code: output=f9f5cbdfe90dd6d6 input=4cc647aa0c81365a]*/ +_testcapi_pyvectorcall_call_impl(PyObject *module, PyObject *func, + PyObject *argstuple, PyObject *kwargs) +/*[clinic end generated code: output=809046fe78511306 input=4376ee7cabd698ce]*/ { if (!PyTuple_Check(argstuple)) { PyErr_SetString(PyExc_TypeError, "args must be a tuple"); @@ -259,10 +257,10 @@ _testcapi_has_vectorcall_flag_impl(PyObject *module, PyTypeObject *type) } static PyMethodDef TestMethods[] = { - _TESTCAPI_TEST_PYOBJECT_FASTCALLDICT_METHODDEF - _TESTCAPI_TEST_PYOBJECT_VECTORCALL_METHODDEF + _TESTCAPI_PYOBJECT_FASTCALLDICT_METHODDEF + _TESTCAPI_PYOBJECT_VECTORCALL_METHODDEF {"function_setvectorcall", function_setvectorcall, METH_O}, - _TESTCAPI_TEST_PYVECTORCALL_CALL_METHODDEF + _TESTCAPI_PYVECTORCALL_CALL_METHODDEF _TESTCAPI_MAKE_VECTORCALL_CLASS_METHODDEF _TESTCAPI_HAS_VECTORCALL_FLAG_METHODDEF {NULL}, From fcf998f1f66872a8531c3ed4eb118c1ca3496eb4 Mon Sep 17 00:00:00 2001 From: littlebutt's workshop Date: Sun, 9 Jul 2023 08:01:55 +0000 Subject: [PATCH 3/6] Update Modules/_testcapi/vectorcall.c Co-authored-by: Dong-hee Na --- Modules/_testcapi/vectorcall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_testcapi/vectorcall.c b/Modules/_testcapi/vectorcall.c index b6adffc04ec25a..442e0ade5189fb 100644 --- a/Modules/_testcapi/vectorcall.c +++ b/Modules/_testcapi/vectorcall.c @@ -64,7 +64,7 @@ _testcapi_pyobject_fastcalldict_impl(PyObject *module, PyObject *func, _testcapi.pyobject_vectorcall func: object func_args: object - kwnames: object = None + kwnames: object / [clinic start generated code]*/ From 5ee06e73de4e0f84d9d4451a2ff1f719bd791d9c Mon Sep 17 00:00:00 2001 From: littlebutt Date: Sun, 9 Jul 2023 16:33:23 +0800 Subject: [PATCH 4/6] run ``build.bat --regen`` to fix CI --- Modules/_testcapi/clinic/vectorcall.c.h | 12 ++++-------- Modules/_testcapi/vectorcall.c | 2 +- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/Modules/_testcapi/clinic/vectorcall.c.h b/Modules/_testcapi/clinic/vectorcall.c.h index aa307c86cba03d..728c0d382565a7 100644 --- a/Modules/_testcapi/clinic/vectorcall.c.h +++ b/Modules/_testcapi/clinic/vectorcall.c.h @@ -41,7 +41,7 @@ _testcapi_pyobject_fastcalldict(PyObject *module, PyObject *const *args, Py_ssiz } PyDoc_STRVAR(_testcapi_pyobject_vectorcall__doc__, -"pyobject_vectorcall($module, func, func_args, kwnames=None, /)\n" +"pyobject_vectorcall($module, func, func_args, kwnames, /)\n" "--\n" "\n"); @@ -58,18 +58,14 @@ _testcapi_pyobject_vectorcall(PyObject *module, PyObject *const *args, Py_ssize_ PyObject *return_value = NULL; PyObject *func; PyObject *func_args; - PyObject *__clinic_kwnames = Py_None; + PyObject *__clinic_kwnames; - if (!_PyArg_CheckPositional("pyobject_vectorcall", nargs, 2, 3)) { + if (!_PyArg_CheckPositional("pyobject_vectorcall", nargs, 3, 3)) { goto exit; } func = args[0]; func_args = args[1]; - if (nargs < 3) { - goto skip_optional; - } __clinic_kwnames = args[2]; -skip_optional: return_value = _testcapi_pyobject_vectorcall_impl(module, func, func_args, __clinic_kwnames); exit: @@ -214,4 +210,4 @@ _testcapi_has_vectorcall_flag(PyObject *module, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=a7c09c9060137f4a input=a9049054013a1b77]*/ +/*[clinic end generated code: output=beaf6beac3d13c25 input=a9049054013a1b77]*/ diff --git a/Modules/_testcapi/vectorcall.c b/Modules/_testcapi/vectorcall.c index 442e0ade5189fb..5ee468bd28c853 100644 --- a/Modules/_testcapi/vectorcall.c +++ b/Modules/_testcapi/vectorcall.c @@ -71,7 +71,7 @@ _testcapi.pyobject_vectorcall static PyObject * _testcapi_pyobject_vectorcall_impl(PyObject *module, PyObject *func, PyObject *func_args, PyObject *kwnames) -/*[clinic end generated code: output=ff77245bc6afe0d8 input=c427975e9408ca84]*/ +/*[clinic end generated code: output=ff77245bc6afe0d8 input=a0668dfef625764c]*/ { PyObject **stack; Py_ssize_t nargs, nkw; From cf11d8d0bfe087263a7341c59ab8ffc18ad41b36 Mon Sep 17 00:00:00 2001 From: littlebutt Date: Sun, 16 Jul 2023 13:08:50 +0800 Subject: [PATCH 5/6] gh-106799: pick another method to illustrate AC --- Doc/howto/clinic.rst | 217 +++++++++++++++++++++++++++---------------- 1 file changed, 138 insertions(+), 79 deletions(-) diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst index 0f99cb64994ab2..6bd72d1c6efb25 100644 --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -162,7 +162,7 @@ Let's dive in! 1. Find a Python builtin that calls either :c:func:`PyArg_ParseTuple` or :c:func:`PyArg_ParseTupleAndKeywords`, and hasn't been converted to work with Argument Clinic yet. - For my example I'm using ``_pickle.Pickler.dump()``. + For my example I'm using ``_asyncio.Future.add_done_callback()``. 2. If the call to the ``PyArg_Parse`` function uses any of the following format units: @@ -208,7 +208,7 @@ Let's dive in! Sample:: /*[clinic input] - Write a pickled representation of obj to the open file. + Add a callback to be run when the future becomes done. [clinic start generated code]*/ 5. If your docstring doesn't have a "summary" line, Argument Clinic will @@ -216,8 +216,15 @@ Let's dive in! be a paragraph consisting of a single 80-column line at the beginning of the docstring. - (Our example docstring consists solely of a summary line, so the sample - code doesn't have to change for this step.) + Sample:: + + /*[clinic input] + Add a callback to be run when the future becomes done. + + The callback is called with a single argument - the future object. If + the future is already done when this is called, the callback is + scheduled with call_soon. + [clinic start generated code]*/ 6. Above the docstring, enter the name of the function, followed by a blank line. This should be the Python name of the function, @@ -229,9 +236,13 @@ Let's dive in! Sample:: /*[clinic input] - _pickle.Pickler.dump + _asyncio.Future.add_done_callback - Write a pickled representation of obj to the open file. + Add a callback to be run when the future becomes done. + + The callback is called with a single argument - the future object. If + the future is already done when this is called, the callback is + scheduled with call_soon. [clinic start generated code]*/ 7. If this is the first time that module or class has been used with Argument @@ -253,14 +264,17 @@ Let's dive in! Sample:: /*[clinic input] - module _pickle - class _pickle.Pickler "PicklerObject *" "&Pickler_Type" + class _asyncio.Future "FutureObj *" "&Future_Type" [clinic start generated code]*/ /*[clinic input] - _pickle.Pickler.dump + _asyncio.Future.add_done_callback + + Add a callback to be run when the future becomes done. - Write a pickled representation of obj to the open file. + The callback is called with a single argument - the future object. If + the future is already done when this is called, the callback is + scheduled with call_soon. [clinic start generated code]*/ @@ -310,17 +324,21 @@ Let's dive in! Sample:: - /*[clinic input] - module _pickle - class _pickle.Pickler "PicklerObject *" "&Pickler_Type" - [clinic start generated code]*/ + /*[clinic input] + class _asyncio.Future "FutureObj *" "&Future_Type" + [clinic start generated code]*/ - /*[clinic input] - _pickle.Pickler.dump + /*[clinic input] + _asyncio.Future.add_done_callback + + cls: defining_class + fn: object - obj: 'O' + Add a callback to be run when the future becomes done. - Write a pickled representation of obj to the open file. + The callback is called with a single argument - the future object. If + the future is already done when this is called, the callback is + scheduled with call_soon. [clinic start generated code]*/ 9. If your function has ``|`` in the format string, meaning some @@ -333,7 +351,27 @@ Let's dive in! itself before the first keyword-only argument, indented the same as the parameter lines. - (``_pickle.Pickler.dump`` has neither, so our sample is unchanged.) + Sample:: + + /*[clinic input] + class _asyncio.Future "FutureObj *" "&Future_Type" + [clinic start generated code]*/ + + /*[clinic input] + _asyncio.Future.add_done_callback + + cls: defining_class + fn: object + + * + context: object = NULL + + Add a callback to be run when the future becomes done. + + The callback is called with a single argument - the future object. If + the future is already done when this is called, the callback is + scheduled with call_soon. + [clinic start generated code]*/ 10. If the existing C function calls :c:func:`PyArg_ParseTuple` @@ -350,19 +388,25 @@ Let's dive in! Sample:: - /*[clinic input] - module _pickle - class _pickle.Pickler "PicklerObject *" "&Pickler_Type" - [clinic start generated code]*/ + /*[clinic input] + class _asyncio.Future "FutureObj *" "&Future_Type" + [clinic start generated code]*/ - /*[clinic input] - _pickle.Pickler.dump + /*[clinic input] + _asyncio.Future.add_done_callback - obj: 'O' - / + cls: defining_class + fn: object + / + * + context: object = NULL - Write a pickled representation of obj to the open file. - [clinic start generated code]*/ + Add a callback to be run when the future becomes done. + + The callback is called with a single argument - the future object. If + the future is already done when this is called, the callback is + scheduled with call_soon. + [clinic start generated code]*/ 11. It's helpful to write a per-parameter docstring for each parameter. But per-parameter docstrings are optional; you can skip this step @@ -377,20 +421,26 @@ Let's dive in! Sample:: - /*[clinic input] - module _pickle - class _pickle.Pickler "PicklerObject *" "&Pickler_Type" - [clinic start generated code]*/ + /*[clinic input] + class _asyncio.Future "FutureObj *" "&Future_Type" + [clinic start generated code]*/ - /*[clinic input] - _pickle.Pickler.dump + /*[clinic input] + _asyncio.Future.add_done_callback - obj: 'O' - The object to be pickled. - / + cls: defining_class + fn: object + the callback function + / + * + context: object = NULL - Write a pickled representation of obj to the open file. - [clinic start generated code]*/ + Add a callback to be run when the future becomes done. + + The callback is called with a single argument - the future object. If + the future is already done when this is called, the callback is + scheduled with call_soon. + [clinic start generated code]*/ 12. Save and close the file, then run ``Tools/clinic/clinic.py`` on it. With luck everything worked---your block now has output, and @@ -398,18 +448,26 @@ Let's dive in! text editor to see:: /*[clinic input] - _pickle.Pickler.dump + _asyncio.Future.add_done_callback - obj: 'O' - The object to be pickled. + cls: defining_class + fn: object + the callback function / + * + context: object = NULL + + Add a callback to be run when the future becomes done. - Write a pickled representation of obj to the open file. + The callback is called with a single argument - the future object. If + the future is already done when this is called, the callback is + scheduled with call_soon. [clinic start generated code]*/ static PyObject * - _pickle_Pickler_dump(PicklerObject *self, PyObject *obj) - /*[clinic end generated code: output=87ecad1261e02ac7 input=552eb1c0f52260d9]*/ + _asyncio_Future_add_done_callback_impl(FutureObj *self, PyTypeObject *cls, + PyObject *fn, PyObject *context) + /*[clinic end generated code: output=922e9a4cbd601167 input=599261c521458cc2]*/ Obviously, if Argument Clinic didn't produce any output, it's because it found an error in your input. Keep fixing your errors and retrying @@ -419,7 +477,7 @@ Let's dive in! file. You'll need to include that in your original ``.c`` file, typically right after the clinic module block:: - #include "clinic/_pickle.c.h" + #include "clinic/_asynciomodule.c.h" 13. Double-check that the argument-parsing code Argument Clinic generated looks basically the same as the existing code. @@ -449,8 +507,9 @@ Let's dive in! macro defining the appropriate static :c:type:`PyMethodDef` structure for this builtin:: - #define __PICKLE_PICKLER_DUMP_METHODDEF \ - {"dump", (PyCFunction)__pickle_Pickler_dump, METH_O, __pickle_Pickler_dump__doc__}, + #define _ASYNCIO_FUTURE_ADD_DONE_CALLBACK_METHODDEF \ + {"add_done_callback", _PyCFunction_CAST(_asyncio_Future_add_done_callback), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _asyncio_Future_add_done_callback__doc__}, + This static structure should be *exactly* the same as the existing static :c:type:`PyMethodDef` structure for this builtin. @@ -484,43 +543,43 @@ Let's dive in! Sample:: /*[clinic input] - module _pickle - class _pickle.Pickler "PicklerObject *" "&Pickler_Type" + class _asyncio.Future "FutureObj *" "&Future_Type" [clinic start generated code]*/ - /*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ + /*[clinic end generated code: output=da39a3ee5e6b4b0d input=00d3e4abca711e0f]*/ /*[clinic input] - _pickle.Pickler.dump + _asyncio.Future.add_done_callback - obj: 'O' - The object to be pickled. + cls: defining_class + fn: object / + * + context: object = NULL + + Add a callback to be run when the future becomes done. - Write a pickled representation of obj to the open file. + The callback is called with a single argument - the future object. If + the future is already done when this is called, the callback is + scheduled with call_soon. [clinic start generated code]*/ - PyDoc_STRVAR(__pickle_Pickler_dump__doc__, - "Write a pickled representation of obj to the open file.\n" - "\n" - ... static PyObject * - _pickle_Pickler_dump_impl(PicklerObject *self, PyObject *obj) - /*[clinic end generated code: checksum=3bd30745bf206a48f8b576a1da3d90f55a0a4187]*/ + _asyncio_Future_add_done_callback_impl(FutureObj *self, PyTypeObject *cls, + PyObject *fn, PyObject *context) + /*[clinic end generated code: output=922e9a4cbd601167 input=599261c521458cc2]*/ { - /* Check whether the Pickler was initialized correctly (issue3664). - Developers often forget to call __init__() in their subclasses, which - would trigger a segfault without this check. */ - if (self->write == NULL) { - PyErr_Format(PicklingError, - "Pickler.__init__() was not called by %s.__init__()", - Py_TYPE(self)->tp_name); - return NULL; + asyncio_state *state = get_asyncio_state_by_cls(cls); + if (context == NULL) { + context = PyContext_CopyCurrent(); + if (context == NULL) { + return NULL; + } + PyObject *res = future_add_done_callback(state, self, fn, context); + Py_DECREF(context); + return res; } - - if (_Pickler_ClearBuffer(self) < 0) - return NULL; - - ... + return future_add_done_callback(state, self, fn, context); + } 15. Remember the macro with the :c:type:`PyMethodDef` structure for this function? Find the existing :c:type:`PyMethodDef` structure for this @@ -535,10 +594,10 @@ Let's dive in! Sample:: - static struct PyMethodDef Pickler_methods[] = { - __PICKLE_PICKLER_DUMP_METHODDEF - __PICKLE_PICKLER_CLEAR_MEMO_METHODDEF - {NULL, NULL} /* sentinel */ + static PyMethodDef FutureType_methods[] = { + _ASYNCIO_FUTURE_ADD_DONE_CALLBACK_METHODDEF + ... + {NULL, NULL} /* Sentinel */ }; From e1a05cc40ad244d8d164df0512b98372aedcaba7 Mon Sep 17 00:00:00 2001 From: littlebutt Date: Tue, 18 Jul 2023 21:00:21 +0800 Subject: [PATCH 6/6] modify the example function to fit all cases --- Doc/howto/clinic.rst | 130 +++++++++++++++++++------------------------ 1 file changed, 57 insertions(+), 73 deletions(-) diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst index 6bd72d1c6efb25..80c1e17df5d338 100644 --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -331,8 +331,7 @@ Let's dive in! /*[clinic input] _asyncio.Future.add_done_callback - cls: defining_class - fn: object + fn: 'O' Add a callback to be run when the future becomes done. @@ -360,11 +359,10 @@ Let's dive in! /*[clinic input] _asyncio.Future.add_done_callback - cls: defining_class - fn: object + fn: 'O' * - context: object = NULL + context: 'O' = NULL Add a callback to be run when the future becomes done. @@ -395,11 +393,10 @@ Let's dive in! /*[clinic input] _asyncio.Future.add_done_callback - cls: defining_class - fn: object + fn: 'O' / * - context: object = NULL + context: 'O' = NULL Add a callback to be run when the future becomes done. @@ -428,12 +425,11 @@ Let's dive in! /*[clinic input] _asyncio.Future.add_done_callback - cls: defining_class - fn: object + fn: 'O' the callback function / * - context: object = NULL + context: 'O' = NULL Add a callback to be run when the future becomes done. @@ -450,12 +446,11 @@ Let's dive in! /*[clinic input] _asyncio.Future.add_done_callback - cls: defining_class - fn: object + fn: 'O' the callback function / * - context: object = NULL + context: 'O' = NULL Add a callback to be run when the future becomes done. @@ -465,8 +460,7 @@ Let's dive in! [clinic start generated code]*/ static PyObject * - _asyncio_Future_add_done_callback_impl(FutureObj *self, PyTypeObject *cls, - PyObject *fn, PyObject *context) + _asyncio_Future_add_done_callback_impl(PyObject *fn, PyObject *context) /*[clinic end generated code: output=922e9a4cbd601167 input=599261c521458cc2]*/ Obviously, if Argument Clinic didn't produce any output, it's because @@ -550,11 +544,10 @@ Let's dive in! /*[clinic input] _asyncio.Future.add_done_callback - cls: defining_class - fn: object + fn: 'O' / * - context: object = NULL + context: 'O' = NULL Add a callback to be run when the future becomes done. @@ -564,22 +557,10 @@ Let's dive in! [clinic start generated code]*/ static PyObject * - _asyncio_Future_add_done_callback_impl(FutureObj *self, PyTypeObject *cls, - PyObject *fn, PyObject *context) + _asyncio_Future_add_done_callback_impl(PyObject *fn, PyObject *context) /*[clinic end generated code: output=922e9a4cbd601167 input=599261c521458cc2]*/ { - asyncio_state *state = get_asyncio_state_by_cls(cls); - if (context == NULL) { - context = PyContext_CopyCurrent(); - if (context == NULL) { - return NULL; - } - PyObject *res = future_add_done_callback(state, self, fn, context); - Py_DECREF(context); - return res; - } - return future_add_done_callback(state, self, fn, context); - } + ... 15. Remember the macro with the :c:type:`PyMethodDef` structure for this function? Find the existing :c:type:`PyMethodDef` structure for this @@ -654,15 +635,15 @@ Argument Clinic will use that function name for the base (generated) function, then add ``"_impl"`` to the end and use that for the name of the impl function. For example, if we wanted to rename the C function names generated for -``pickle.Pickler.dump``, it'd look like this:: +``_asyncio.Future.add_done_callback``, it'd look like this:: /*[clinic input] - pickle.Pickler.dump as pickler_dumper + _asyncio.Future.add_done_callback as future_add_done_callback ... -The base function would now be named ``pickler_dumper()``, -and the impl function would now be named ``pickler_dumper_impl()``. +The base function would now be named ``future_add_done_callback()``, +and the impl function would now be named ``future_add_done_callback_impl()``. Similarly, you may have a problem where you want to give a parameter @@ -671,16 +652,15 @@ Clinic allows you to give a parameter different names in Python and in C, using the same ``"as"`` syntax:: /*[clinic input] - pickle.Pickler.dump + _asyncio.Future.add_done_callback - obj: object - file as file_obj: object - protocol: object = NULL + fn: 'O' + / * - fix_imports: bool = True + context as ctx: 'O' = NULL Here, the name used in Python (in the signature and the ``keywords`` -array) would be ``file``, but the C variable would be named ``file_obj``. +array) would be ``context``, but the C variable would be named ``ctx``. You can use this to rename the ``self`` parameter too! @@ -937,17 +917,18 @@ on the right is the text you'd replace it with. ``'z*'`` ``Py_buffer(accept={buffer, str, NoneType})`` ========= ================================================================================= -As an example, here's our sample ``pickle.Pickler.dump`` using the proper +As an example, here's our sample ``_asyncio.Future.add_done_callback`` using the proper converter:: /*[clinic input] - pickle.Pickler.dump + _asyncio.Future.add_done_callback - obj: object - The object to be pickled. + fn: object / + * + context: object = NULL - Write a pickled representation of obj to the open file. + Add a callback to be run when the future becomes done. [clinic start generated code]*/ One advantage of real converters is that they're more flexible than legacy @@ -1258,14 +1239,15 @@ you can directly use Argument Clinic's existing ``self`` converter, passing in the type you want to use as the ``type`` parameter:: /*[clinic input] + _asyncio.Future.add_done_callback - _pickle.Pickler.dump - - self: self(type="PicklerObject *") - obj: object - / + self: self(type="FutureObj *") + fn: object + / + * + context: object = NULL - Write a pickled representation of the given object to the open file. + Add a callback to be run when the future becomes done. [clinic start generated code]*/ On the other hand, if you have a lot of functions that will use the same @@ -1273,19 +1255,20 @@ type for ``self``, it's best to create your own converter, subclassing ``self_converter`` but overwriting the ``type`` member:: /*[python input] - class PicklerObject_converter(self_converter): - type = "PicklerObject *" + class FutureObj_converter(self_converter): + type = "FutureObj *" [python start generated code]*/ /*[clinic input] + _asyncio.Future.add_done_callback - _pickle.Pickler.dump - - self: PicklerObject - obj: object - / + self: FutureObj + fn: object + / + * + context: object = NULL - Write a pickled representation of the given object to the open file. + Add a callback to be run when the future becomes done. [clinic start generated code]*/ @@ -1298,33 +1281,34 @@ module level state. Use :c:func:`PyType_FromModuleAndSpec` to associate a new heap type with a module. You can now use :c:func:`PyType_GetModuleState` on the defining class to fetch the module state, for example from a module method. -Example from ``Modules/zlibmodule.c``. First, ``defining_class`` is added to +Example from ``Modules/_asynciomodule.c``. First, ``defining_class`` is added to the clinic input:: /*[clinic input] - zlib.Compress.compress + _asyncio.Future.add_done_callback - cls: defining_class - data: Py_buffer - Binary data to be compressed. - / + cls: defining_class + fn: object + / + * + context: object = NULL + + Add a callback to be run when the future becomes done. After running the Argument Clinic tool, the following function signature is generated:: /*[clinic start generated code]*/ - static PyObject * - zlib_Compress_compress_impl(compobject *self, PyTypeObject *cls, - Py_buffer *data) + _asyncio_Future_add_done_callback_impl(FutureObj *self, PyTypeObject *cls, + PyObject *fn, PyObject *context) /*[clinic end generated code: output=6731b3f0ff357ca6 input=04d00f65ab01d260]*/ The following code can now use ``PyType_GetModuleState(cls)`` to fetch the module state:: - zlibstate *state = PyType_GetModuleState(cls); - + asyncio_state *state = get_asyncio_state_by_cls(cls); Each method may only have one argument using this converter, and it must appear after ``self``, or, if ``self`` is not used, as the first argument. The argument