diff --git a/Lib/test/clinic.test.c b/Lib/test/clinic.test.c index 3dca8b8d1ed9b99..f8b0a643c20a410 100644 --- a/Lib/test/clinic.test.c +++ b/Lib/test/clinic.test.c @@ -5741,21 +5741,15 @@ Test___init__(PyObject *self, PyObject *args, PyObject *kwargs) !_PyArg_NoKeywords("Test", kwargs)) { goto exit; } - switch (PyTuple_GET_SIZE(args)) { - case 1: - if (!PyArg_ParseTuple(args, "O:__init__", &a)) { - goto exit; - } - break; - case 2: - if (!PyArg_ParseTuple(args, "OO:__init__", &a, &b)) { - goto exit; - } - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "Test.__init__ requires 1 to 2 arguments"); - goto exit; + Py_ssize_t nargs = PyTuple_GET_SIZE(args); + if (nargs < 1 || nargs > 2) { + PyErr_SetString(PyExc_TypeError, "Test.__init__ requires 1 to 2 arguments"); + goto exit; + } + a = PyTuple_GET_ITEM(args, 0); + if (nargs >= 2) { + b = PyTuple_GET_ITEM(args, 1); + group_right_1 = 1; } return_value = Test___init___impl((TestObj *)self, a, group_right_1, b); @@ -5766,7 +5760,7 @@ Test___init__(PyObject *self, PyObject *args, PyObject *kwargs) static int Test___init___impl(TestObj *self, PyObject *a, int group_right_1, PyObject *b) -/*[clinic end generated code: output=2bbb8ea60e8f57a6 input=10f5d0f1e8e466ef]*/ +/*[clinic end generated code: output=72fdd2de63c05b9e input=10f5d0f1e8e466ef]*/ /*[clinic input] @@ -5783,30 +5777,25 @@ PyDoc_STRVAR(only_optional_group__doc__, "The only parameter is in an optional group."); #define ONLY_OPTIONAL_GROUP_METHODDEF \ - {"only_optional_group", (PyCFunction)only_optional_group, METH_VARARGS, only_optional_group__doc__}, + {"only_optional_group", _PyCFunction_CAST(only_optional_group), METH_FASTCALL, only_optional_group__doc__}, static PyObject * only_optional_group_impl(PyObject *module, int group_right_1, PyObject *a); static PyObject * -only_optional_group(PyObject *module, PyObject *args) +only_optional_group(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_right_1 = 0; PyObject *a = NULL; - switch (PyTuple_GET_SIZE(args)) { - case 0: - break; - case 1: - if (!PyArg_ParseTuple(args, "O:only_optional_group", &a)) { - goto exit; - } - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "only_optional_group requires 0 to 1 arguments"); - goto exit; + if (nargs > 1) { + PyErr_SetString(PyExc_TypeError, "only_optional_group requires 0 to 1 arguments"); + goto exit; + } + if (nargs >= 1) { + a = args[0]; + group_right_1 = 1; } return_value = only_optional_group_impl(module, group_right_1, a); @@ -5816,7 +5805,7 @@ only_optional_group(PyObject *module, PyObject *args) static PyObject * only_optional_group_impl(PyObject *module, int group_right_1, PyObject *a) -/*[clinic end generated code: output=e7546b9441793d7d input=426c64055af7bcab]*/ +/*[clinic end generated code: output=4c7959fcc06bd216 input=426c64055af7bcab]*/ /*[clinic input] @@ -5835,14 +5824,14 @@ PyDoc_STRVAR(group_and_optional_parameter__doc__, "The optional parameter can be omitted with or without the group."); #define GROUP_AND_OPTIONAL_PARAMETER_METHODDEF \ - {"group_and_optional_parameter", (PyCFunction)group_and_optional_parameter, METH_VARARGS, group_and_optional_parameter__doc__}, + {"group_and_optional_parameter", _PyCFunction_CAST(group_and_optional_parameter), METH_FASTCALL, group_and_optional_parameter__doc__}, static PyObject * group_and_optional_parameter_impl(PyObject *module, int group_left_1, PyObject *a, PyObject *b, PyObject *c); static PyObject * -group_and_optional_parameter(PyObject *module, PyObject *args) +group_and_optional_parameter(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -5850,24 +5839,22 @@ group_and_optional_parameter(PyObject *module, PyObject *args) PyObject *b = NULL; PyObject *c = Py_None; - switch (PyTuple_GET_SIZE(args)) { - case 0: - case 1: - if (!PyArg_ParseTuple(args, "|O:group_and_optional_parameter", &c)) { - goto exit; - } - break; - case 2: - case 3: - if (!PyArg_ParseTuple(args, "OO|O:group_and_optional_parameter", &a, &b, &c)) { - goto exit; - } - group_left_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "group_and_optional_parameter requires 0 to 3 arguments"); - goto exit; + Py_ssize_t offset = 0; + if (nargs > 3) { + PyErr_SetString(PyExc_TypeError, "group_and_optional_parameter requires 0 to 3 arguments"); + goto exit; } + if (nargs >= 2) { + a = args[0]; + b = args[1]; + offset += 2; + group_left_1 = 1; + } + if (nargs <= offset) { + goto skip_optional; + } + c = args[offset]; +skip_optional: return_value = group_and_optional_parameter_impl(module, group_left_1, a, b, c); exit: @@ -5877,7 +5864,7 @@ group_and_optional_parameter(PyObject *module, PyObject *args) static PyObject * group_and_optional_parameter_impl(PyObject *module, int group_left_1, PyObject *a, PyObject *b, PyObject *c) -/*[clinic end generated code: output=3faea69eafd5bbbe input=7f0fbb6124f5a972]*/ +/*[clinic end generated code: output=651f2361ffc5e256 input=7f0fbb6124f5a972]*/ /*[clinic input] @@ -5899,7 +5886,7 @@ PyDoc_STRVAR(two_groups_on_the_same_level__doc__, "Groups on the same level are independent of each other."); #define TWO_GROUPS_ON_THE_SAME_LEVEL_METHODDEF \ - {"two_groups_on_the_same_level", (PyCFunction)two_groups_on_the_same_level, METH_VARARGS, two_groups_on_the_same_level__doc__}, + {"two_groups_on_the_same_level", _PyCFunction_CAST(two_groups_on_the_same_level), METH_FASTCALL, two_groups_on_the_same_level__doc__}, static PyObject * two_groups_on_the_same_level_impl(PyObject *module, int group_left_1, @@ -5907,7 +5894,7 @@ two_groups_on_the_same_level_impl(PyObject *module, int group_left_1, PyObject *c, PyObject *d); static PyObject * -two_groups_on_the_same_level(PyObject *module, PyObject *args) +two_groups_on_the_same_level(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -5917,35 +5904,20 @@ two_groups_on_the_same_level(PyObject *module, PyObject *args) PyObject *c = NULL; PyObject *d; - switch (PyTuple_GET_SIZE(args)) { - case 1: - if (!PyArg_ParseTuple(args, "O:two_groups_on_the_same_level", &d)) { - goto exit; - } - break; - case 2: - if (!PyArg_ParseTuple(args, "OO:two_groups_on_the_same_level", &c, &d)) { - goto exit; - } - group_left_2 = 1; - break; - case 3: - if (!PyArg_ParseTuple(args, "OOO:two_groups_on_the_same_level", &a, &b, &d)) { - goto exit; - } - group_left_1 = 1; - break; - case 4: - if (!PyArg_ParseTuple(args, "OOOO:two_groups_on_the_same_level", &a, &b, &c, &d)) { - goto exit; - } - group_left_1 = 1; - group_left_2 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "two_groups_on_the_same_level requires 1 to 4 arguments"); - goto exit; + if (nargs < 1 || nargs > 4) { + PyErr_SetString(PyExc_TypeError, "two_groups_on_the_same_level requires 1 to 4 arguments"); + goto exit; + } + if (nargs >= 3) { + a = args[0]; + b = args[1]; + group_left_1 = 1; + } + if (nargs == 2 || nargs == 4) { + c = args[nargs - 2]; + group_left_2 = 1; } + d = args[nargs - 1]; return_value = two_groups_on_the_same_level_impl(module, group_left_1, a, b, group_left_2, c, d); exit: @@ -5956,7 +5928,7 @@ static PyObject * two_groups_on_the_same_level_impl(PyObject *module, int group_left_1, PyObject *a, PyObject *b, int group_left_2, PyObject *c, PyObject *d) -/*[clinic end generated code: output=508a61ee582da21e input=1b45d9b675b32d1a]*/ +/*[clinic end generated code: output=737c3f543296e916 input=1b45d9b675b32d1a]*/ /*[clinic input] diff --git a/Misc/NEWS.d/next/Tools-Demos/2026-08-08-12-40-00.gh-issue-155373.Wq3xTm.rst b/Misc/NEWS.d/next/Tools-Demos/2026-08-08-12-40-00.gh-issue-155373.Wq3xTm.rst new file mode 100644 index 000000000000000..ed02c8b9fbf4010 --- /dev/null +++ b/Misc/NEWS.d/next/Tools-Demos/2026-08-08-12-40-00.gh-issue-155373.Wq3xTm.rst @@ -0,0 +1,6 @@ +Argument Clinic now generates the inlined code of the converters for functions +with optional groups, instead of a ``PyArg_ParseTuple()`` call for every number +of arguments. +Every argument is now parsed once, most such functions now use the fastcall +convention, and the errors for a wrong type of an argument are the same as in +other functions. diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 07e924b0fc564bc..03690c7cfb2d3df 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -5117,7 +5117,8 @@ static PyMethodDef PyCursesWindow_methods[] = { {"standout", PyCursesWindow_wstandout, METH_NOARGS, "standout($self, /)\n--\n\n" "Turn on the A_STANDOUT attribute."}, - {"subpad", _curses_window_subwin, METH_VARARGS, _curses_window_subwin__doc__}, + {"subpad", _PyCFunction_CAST(_curses_window_subwin), METH_FASTCALL, + _curses_window_subwin__doc__}, _CURSES_WINDOW_SUBWIN_METHODDEF {"syncdown", PyCursesWindow_wsyncdown, METH_NOARGS, "syncdown($self, /)\n--\n\n" diff --git a/Modules/clinic/_cursesmodule.c.h b/Modules/clinic/_cursesmodule.c.h index b4cb294e3bb61a5..30d19b985b7fa7e 100644 --- a/Modules/clinic/_cursesmodule.c.h +++ b/Modules/clinic/_cursesmodule.c.h @@ -6,6 +6,7 @@ preserve # include "pycore_gc.h" // PyGC_Head # include "pycore_runtime.h" // _Py_ID() #endif +#include "pycore_long.h" // _PyLong_UnsignedInt_Converter() #include "pycore_modsupport.h" // _PyArg_UnpackKeywords() PyDoc_STRVAR(complexchar_new__doc__, @@ -207,7 +208,7 @@ PyDoc_STRVAR(_curses_window_addch__doc__, "current settings for the window object."); #define _CURSES_WINDOW_ADDCH_METHODDEF \ - {"addch", (PyCFunction)_curses_window_addch, METH_VARARGS, _curses_window_addch__doc__}, + {"addch", _PyCFunction_CAST(_curses_window_addch), METH_FASTCALL, _curses_window_addch__doc__}, static PyObject * _curses_window_addch_impl(PyCursesWindowObject *self, int group_left_1, @@ -215,7 +216,7 @@ _curses_window_addch_impl(PyCursesWindowObject *self, int group_left_1, attr_t attr); static PyObject * -_curses_window_addch(PyObject *self, PyObject *args) +_curses_window_addch(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -225,34 +226,29 @@ _curses_window_addch(PyObject *self, PyObject *args) int group_right_1 = 0; attr_t attr = 0; - switch (PyTuple_GET_SIZE(args)) { - case 1: - if (!PyArg_ParseTuple(args, "O:addch", &ch)) { - goto exit; - } - break; - case 2: - if (!PyArg_ParseTuple(args, "OO&:addch", &ch, attr_converter, &attr)) { - goto exit; - } - group_right_1 = 1; - break; - case 3: - if (!PyArg_ParseTuple(args, "iiO:addch", &y, &x, &ch)) { - goto exit; - } - group_left_1 = 1; - break; - case 4: - if (!PyArg_ParseTuple(args, "iiOO&:addch", &y, &x, &ch, attr_converter, &attr)) { - goto exit; - } - group_left_1 = 1; - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_curses.window.addch requires 1 to 4 arguments"); + Py_ssize_t offset = 0; + if (nargs < 1 || nargs > 4) { + PyErr_SetString(PyExc_TypeError, "_curses.window.addch requires 1 to 4 arguments"); + goto exit; + } + if (nargs >= 3) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { + goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { goto exit; + } + offset += 2; + group_left_1 = 1; + } + ch = args[offset]; + if (nargs == 2 || nargs == 4) { + if (!attr_converter(args[nargs - 1], &attr)) { + goto exit; + } + group_right_1 = 1; } return_value = _curses_window_addch_impl((PyCursesWindowObject *)self, group_left_1, y, x, ch, group_right_1, attr); @@ -279,7 +275,7 @@ PyDoc_STRVAR(_curses_window_addstr__doc__, "current settings for the window object."); #define _CURSES_WINDOW_ADDSTR_METHODDEF \ - {"addstr", (PyCFunction)_curses_window_addstr, METH_VARARGS, _curses_window_addstr__doc__}, + {"addstr", _PyCFunction_CAST(_curses_window_addstr), METH_FASTCALL, _curses_window_addstr__doc__}, static PyObject * _curses_window_addstr_impl(PyCursesWindowObject *self, int group_left_1, @@ -287,7 +283,7 @@ _curses_window_addstr_impl(PyCursesWindowObject *self, int group_left_1, attr_t attr); static PyObject * -_curses_window_addstr(PyObject *self, PyObject *args) +_curses_window_addstr(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -297,34 +293,29 @@ _curses_window_addstr(PyObject *self, PyObject *args) int group_right_1 = 0; attr_t attr = 0; - switch (PyTuple_GET_SIZE(args)) { - case 1: - if (!PyArg_ParseTuple(args, "O:addstr", &str)) { - goto exit; - } - break; - case 2: - if (!PyArg_ParseTuple(args, "OO&:addstr", &str, attr_converter, &attr)) { - goto exit; - } - group_right_1 = 1; - break; - case 3: - if (!PyArg_ParseTuple(args, "iiO:addstr", &y, &x, &str)) { - goto exit; - } - group_left_1 = 1; - break; - case 4: - if (!PyArg_ParseTuple(args, "iiOO&:addstr", &y, &x, &str, attr_converter, &attr)) { - goto exit; - } - group_left_1 = 1; - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_curses.window.addstr requires 1 to 4 arguments"); + Py_ssize_t offset = 0; + if (nargs < 1 || nargs > 4) { + PyErr_SetString(PyExc_TypeError, "_curses.window.addstr requires 1 to 4 arguments"); + goto exit; + } + if (nargs >= 3) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { + goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { goto exit; + } + offset += 2; + group_left_1 = 1; + } + str = args[offset]; + if (nargs == 2 || nargs == 4) { + if (!attr_converter(args[nargs - 1], &attr)) { + goto exit; + } + group_right_1 = 1; } return_value = _curses_window_addstr_impl((PyCursesWindowObject *)self, group_left_1, y, x, str, group_right_1, attr); @@ -353,7 +344,7 @@ PyDoc_STRVAR(_curses_window_addnstr__doc__, "current settings for the window object."); #define _CURSES_WINDOW_ADDNSTR_METHODDEF \ - {"addnstr", (PyCFunction)_curses_window_addnstr, METH_VARARGS, _curses_window_addnstr__doc__}, + {"addnstr", _PyCFunction_CAST(_curses_window_addnstr), METH_FASTCALL, _curses_window_addnstr__doc__}, static PyObject * _curses_window_addnstr_impl(PyCursesWindowObject *self, int group_left_1, @@ -361,7 +352,7 @@ _curses_window_addnstr_impl(PyCursesWindowObject *self, int group_left_1, int group_right_1, attr_t attr); static PyObject * -_curses_window_addnstr(PyObject *self, PyObject *args) +_curses_window_addnstr(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -372,34 +363,33 @@ _curses_window_addnstr(PyObject *self, PyObject *args) int group_right_1 = 0; attr_t attr = 0; - switch (PyTuple_GET_SIZE(args)) { - case 2: - if (!PyArg_ParseTuple(args, "Oi:addnstr", &str, &n)) { - goto exit; - } - break; - case 3: - if (!PyArg_ParseTuple(args, "OiO&:addnstr", &str, &n, attr_converter, &attr)) { - goto exit; - } - group_right_1 = 1; - break; - case 4: - if (!PyArg_ParseTuple(args, "iiOi:addnstr", &y, &x, &str, &n)) { - goto exit; - } - group_left_1 = 1; - break; - case 5: - if (!PyArg_ParseTuple(args, "iiOiO&:addnstr", &y, &x, &str, &n, attr_converter, &attr)) { - goto exit; - } - group_left_1 = 1; - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_curses.window.addnstr requires 2 to 5 arguments"); + Py_ssize_t offset = 0; + if (nargs < 2 || nargs > 5) { + PyErr_SetString(PyExc_TypeError, "_curses.window.addnstr requires 2 to 5 arguments"); + goto exit; + } + if (nargs >= 4) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { + goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { goto exit; + } + offset += 2; + group_left_1 = 1; + } + str = args[offset]; + n = PyLong_AsInt(args[offset + 1]); + if (n == -1 && PyErr_Occurred()) { + goto exit; + } + if (nargs == 3 || nargs == 5) { + if (!attr_converter(args[nargs - 1], &attr)) { + goto exit; + } + group_right_1 = 1; } return_value = _curses_window_addnstr_impl((PyCursesWindowObject *)self, group_left_1, y, x, str, n, group_right_1, attr); @@ -417,35 +407,30 @@ PyDoc_STRVAR(_curses_window_bkgd__doc__, " Background attributes."); #define _CURSES_WINDOW_BKGD_METHODDEF \ - {"bkgd", (PyCFunction)_curses_window_bkgd, METH_VARARGS, _curses_window_bkgd__doc__}, + {"bkgd", _PyCFunction_CAST(_curses_window_bkgd), METH_FASTCALL, _curses_window_bkgd__doc__}, static PyObject * _curses_window_bkgd_impl(PyCursesWindowObject *self, PyObject *ch, int group_right_1, attr_t attr); static PyObject * -_curses_window_bkgd(PyObject *self, PyObject *args) +_curses_window_bkgd(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyObject *ch; int group_right_1 = 0; attr_t attr = 0; - switch (PyTuple_GET_SIZE(args)) { - case 1: - if (!PyArg_ParseTuple(args, "O:bkgd", &ch)) { - goto exit; - } - break; - case 2: - if (!PyArg_ParseTuple(args, "OO&:bkgd", &ch, attr_converter, &attr)) { - goto exit; - } - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_curses.window.bkgd requires 1 to 2 arguments"); + if (nargs < 1 || nargs > 2) { + PyErr_SetString(PyExc_TypeError, "_curses.window.bkgd requires 1 to 2 arguments"); + goto exit; + } + ch = args[0]; + if (nargs >= 2) { + if (!attr_converter(args[1], &attr)) { goto exit; + } + group_right_1 = 1; } return_value = _curses_window_bkgd_impl((PyCursesWindowObject *)self, ch, group_right_1, attr); @@ -720,35 +705,30 @@ PyDoc_STRVAR(_curses_window_bkgdset__doc__, " Background attributes."); #define _CURSES_WINDOW_BKGDSET_METHODDEF \ - {"bkgdset", (PyCFunction)_curses_window_bkgdset, METH_VARARGS, _curses_window_bkgdset__doc__}, + {"bkgdset", _PyCFunction_CAST(_curses_window_bkgdset), METH_FASTCALL, _curses_window_bkgdset__doc__}, static PyObject * _curses_window_bkgdset_impl(PyCursesWindowObject *self, PyObject *ch, int group_right_1, attr_t attr); static PyObject * -_curses_window_bkgdset(PyObject *self, PyObject *args) +_curses_window_bkgdset(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyObject *ch; int group_right_1 = 0; attr_t attr = 0; - switch (PyTuple_GET_SIZE(args)) { - case 1: - if (!PyArg_ParseTuple(args, "O:bkgdset", &ch)) { - goto exit; - } - break; - case 2: - if (!PyArg_ParseTuple(args, "OO&:bkgdset", &ch, attr_converter, &attr)) { - goto exit; - } - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_curses.window.bkgdset requires 1 to 2 arguments"); + if (nargs < 1 || nargs > 2) { + PyErr_SetString(PyExc_TypeError, "_curses.window.bkgdset requires 1 to 2 arguments"); + goto exit; + } + ch = args[0]; + if (nargs >= 2) { + if (!attr_converter(args[1], &attr)) { goto exit; + } + group_right_1 = 1; } return_value = _curses_window_bkgdset_impl((PyCursesWindowObject *)self, ch, group_right_1, attr); @@ -865,33 +845,33 @@ PyDoc_STRVAR(_curses_window_box__doc__, "function."); #define _CURSES_WINDOW_BOX_METHODDEF \ - {"box", (PyCFunction)_curses_window_box, METH_VARARGS, _curses_window_box__doc__}, + {"box", _PyCFunction_CAST(_curses_window_box), METH_FASTCALL, _curses_window_box__doc__}, static PyObject * _curses_window_box_impl(PyCursesWindowObject *self, int group_right_1, PyObject *verch, PyObject *horch); static PyObject * -_curses_window_box(PyObject *self, PyObject *args) +_curses_window_box(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_right_1 = 0; PyObject *verch = _PyLong_GetZero(); PyObject *horch = _PyLong_GetZero(); - switch (PyTuple_GET_SIZE(args)) { + switch (nargs) { case 0: - break; case 2: - if (!PyArg_ParseTuple(args, "OO:box", &verch, &horch)) { - goto exit; - } - group_right_1 = 1; break; default: PyErr_SetString(PyExc_TypeError, "_curses.window.box requires 0 to 2 arguments"); goto exit; } + if (nargs >= 2) { + verch = args[0]; + horch = args[1]; + group_right_1 = 1; + } return_value = _curses_window_box_impl((PyCursesWindowObject *)self, group_right_1, verch, horch); exit: @@ -921,14 +901,14 @@ PyDoc_STRVAR(_curses_window_chgat__doc__, "contents will be redisplayed by the next window refresh."); #define _CURSES_WINDOW_CHGAT_METHODDEF \ - {"chgat", (PyCFunction)_curses_window_chgat, METH_VARARGS, _curses_window_chgat__doc__}, + {"chgat", _PyCFunction_CAST(_curses_window_chgat), METH_FASTCALL, _curses_window_chgat__doc__}, static PyObject * _curses_window_chgat_impl(PyCursesWindowObject *self, int group_left_1, int y, int x, int group_left_2, int n, attr_t attr); static PyObject * -_curses_window_chgat(PyObject *self, PyObject *args) +_curses_window_chgat(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -938,34 +918,30 @@ _curses_window_chgat(PyObject *self, PyObject *args) int n = -1; attr_t attr; - switch (PyTuple_GET_SIZE(args)) { - case 1: - if (!PyArg_ParseTuple(args, "O&:chgat", attr_converter, &attr)) { - goto exit; - } - break; - case 2: - if (!PyArg_ParseTuple(args, "iO&:chgat", &n, attr_converter, &attr)) { - goto exit; - } - group_left_2 = 1; - break; - case 3: - if (!PyArg_ParseTuple(args, "iiO&:chgat", &y, &x, attr_converter, &attr)) { - goto exit; - } - group_left_1 = 1; - break; - case 4: - if (!PyArg_ParseTuple(args, "iiiO&:chgat", &y, &x, &n, attr_converter, &attr)) { - goto exit; - } - group_left_1 = 1; - group_left_2 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_curses.window.chgat requires 1 to 4 arguments"); + if (nargs < 1 || nargs > 4) { + PyErr_SetString(PyExc_TypeError, "_curses.window.chgat requires 1 to 4 arguments"); + goto exit; + } + if (nargs >= 3) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { + goto exit; + } + group_left_1 = 1; + } + if (nargs == 2 || nargs == 4) { + n = PyLong_AsInt(args[nargs - 2]); + if (n == -1 && PyErr_Occurred()) { + goto exit; + } + group_left_2 = 1; + } + if (!attr_converter(args[nargs - 1], &attr)) { + goto exit; } return_value = _curses_window_chgat_impl((PyCursesWindowObject *)self, group_left_1, y, x, group_left_2, n, attr); @@ -988,33 +964,39 @@ PyDoc_STRVAR(_curses_window_delch__doc__, "position left."); #define _CURSES_WINDOW_DELCH_METHODDEF \ - {"delch", (PyCFunction)_curses_window_delch, METH_VARARGS, _curses_window_delch__doc__}, + {"delch", _PyCFunction_CAST(_curses_window_delch), METH_FASTCALL, _curses_window_delch__doc__}, static PyObject * _curses_window_delch_impl(PyCursesWindowObject *self, int group_right_1, int y, int x); static PyObject * -_curses_window_delch(PyObject *self, PyObject *args) +_curses_window_delch(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_right_1 = 0; int y = 0; int x = 0; - switch (PyTuple_GET_SIZE(args)) { + switch (nargs) { case 0: - break; case 2: - if (!PyArg_ParseTuple(args, "ii:delch", &y, &x)) { - goto exit; - } - group_right_1 = 1; break; default: PyErr_SetString(PyExc_TypeError, "_curses.window.delch requires 0 to 2 arguments"); goto exit; } + if (nargs >= 2) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { + goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { + goto exit; + } + group_right_1 = 1; + } return_value = _curses_window_delch_impl((PyCursesWindowObject *)self, group_right_1, y, x); exit: @@ -1039,14 +1021,14 @@ PyDoc_STRVAR(_curses_window_derwin__doc__, "relative to the entire screen."); #define _CURSES_WINDOW_DERWIN_METHODDEF \ - {"derwin", (PyCFunction)_curses_window_derwin, METH_VARARGS, _curses_window_derwin__doc__}, + {"derwin", _PyCFunction_CAST(_curses_window_derwin), METH_FASTCALL, _curses_window_derwin__doc__}, static PyObject * _curses_window_derwin_impl(PyCursesWindowObject *self, int group_left_1, int nlines, int ncols, int begin_y, int begin_x); static PyObject * -_curses_window_derwin(PyObject *self, PyObject *args) +_curses_window_derwin(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -1055,22 +1037,33 @@ _curses_window_derwin(PyObject *self, PyObject *args) int begin_y; int begin_x; - switch (PyTuple_GET_SIZE(args)) { + switch (nargs) { case 2: - if (!PyArg_ParseTuple(args, "ii:derwin", &begin_y, &begin_x)) { - goto exit; - } - break; case 4: - if (!PyArg_ParseTuple(args, "iiii:derwin", &nlines, &ncols, &begin_y, &begin_x)) { - goto exit; - } - group_left_1 = 1; break; default: PyErr_SetString(PyExc_TypeError, "_curses.window.derwin requires 2 to 4 arguments"); goto exit; } + if (nargs >= 4) { + nlines = PyLong_AsInt(args[0]); + if (nlines == -1 && PyErr_Occurred()) { + goto exit; + } + ncols = PyLong_AsInt(args[1]); + if (ncols == -1 && PyErr_Occurred()) { + goto exit; + } + group_left_1 = 1; + } + begin_y = PyLong_AsInt(args[nargs - 2]); + if (begin_y == -1 && PyErr_Occurred()) { + goto exit; + } + begin_x = PyLong_AsInt(args[nargs - 1]); + if (begin_x == -1 && PyErr_Occurred()) { + goto exit; + } return_value = _curses_window_derwin_impl((PyCursesWindowObject *)self, group_left_1, nlines, ncols, begin_y, begin_x); exit: @@ -1109,35 +1102,30 @@ PyDoc_STRVAR(_curses_window_echochar__doc__, " Attributes for the character."); #define _CURSES_WINDOW_ECHOCHAR_METHODDEF \ - {"echochar", (PyCFunction)_curses_window_echochar, METH_VARARGS, _curses_window_echochar__doc__}, + {"echochar", _PyCFunction_CAST(_curses_window_echochar), METH_FASTCALL, _curses_window_echochar__doc__}, static PyObject * _curses_window_echochar_impl(PyCursesWindowObject *self, PyObject *ch, int group_right_1, attr_t attr); static PyObject * -_curses_window_echochar(PyObject *self, PyObject *args) +_curses_window_echochar(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyObject *ch; int group_right_1 = 0; attr_t attr = 0; - switch (PyTuple_GET_SIZE(args)) { - case 1: - if (!PyArg_ParseTuple(args, "O:echochar", &ch)) { - goto exit; - } - break; - case 2: - if (!PyArg_ParseTuple(args, "OO&:echochar", &ch, attr_converter, &attr)) { - goto exit; - } - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_curses.window.echochar requires 1 to 2 arguments"); + if (nargs < 1 || nargs > 2) { + PyErr_SetString(PyExc_TypeError, "_curses.window.echochar requires 1 to 2 arguments"); + goto exit; + } + ch = args[0]; + if (nargs >= 2) { + if (!attr_converter(args[1], &attr)) { goto exit; + } + group_right_1 = 1; } return_value = _curses_window_echochar_impl((PyCursesWindowObject *)self, ch, group_right_1, attr); @@ -1278,33 +1266,39 @@ PyDoc_STRVAR(_curses_window_in_wch__doc__, "attributes and color pair."); #define _CURSES_WINDOW_IN_WCH_METHODDEF \ - {"in_wch", (PyCFunction)_curses_window_in_wch, METH_VARARGS, _curses_window_in_wch__doc__}, + {"in_wch", _PyCFunction_CAST(_curses_window_in_wch), METH_FASTCALL, _curses_window_in_wch__doc__}, static PyObject * _curses_window_in_wch_impl(PyCursesWindowObject *self, int group_right_1, int y, int x); static PyObject * -_curses_window_in_wch(PyObject *self, PyObject *args) +_curses_window_in_wch(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_right_1 = 0; int y = 0; int x = 0; - switch (PyTuple_GET_SIZE(args)) { + switch (nargs) { case 0: - break; case 2: - if (!PyArg_ParseTuple(args, "ii:in_wch", &y, &x)) { - goto exit; - } - group_right_1 = 1; break; default: PyErr_SetString(PyExc_TypeError, "_curses.window.in_wch requires 0 to 2 arguments"); goto exit; } + if (nargs >= 2) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { + goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { + goto exit; + } + group_right_1 = 1; + } return_value = _curses_window_in_wch_impl((PyCursesWindowObject *)self, group_right_1, y, x); exit: @@ -1344,33 +1338,39 @@ PyDoc_STRVAR(_curses_window_getch__doc__, "waits until a key is pressed."); #define _CURSES_WINDOW_GETCH_METHODDEF \ - {"getch", (PyCFunction)_curses_window_getch, METH_VARARGS, _curses_window_getch__doc__}, + {"getch", _PyCFunction_CAST(_curses_window_getch), METH_FASTCALL, _curses_window_getch__doc__}, static PyObject * _curses_window_getch_impl(PyCursesWindowObject *self, int group_right_1, int y, int x); static PyObject * -_curses_window_getch(PyObject *self, PyObject *args) +_curses_window_getch(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_right_1 = 0; int y = 0; int x = 0; - switch (PyTuple_GET_SIZE(args)) { + switch (nargs) { case 0: - break; case 2: - if (!PyArg_ParseTuple(args, "ii:getch", &y, &x)) { - goto exit; - } - group_right_1 = 1; break; default: PyErr_SetString(PyExc_TypeError, "_curses.window.getch requires 0 to 2 arguments"); goto exit; } + if (nargs >= 2) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { + goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { + goto exit; + } + group_right_1 = 1; + } return_value = _curses_window_getch_impl((PyCursesWindowObject *)self, group_right_1, y, x); exit: @@ -1392,33 +1392,39 @@ PyDoc_STRVAR(_curses_window_getkey__doc__, "if there is no input."); #define _CURSES_WINDOW_GETKEY_METHODDEF \ - {"getkey", (PyCFunction)_curses_window_getkey, METH_VARARGS, _curses_window_getkey__doc__}, + {"getkey", _PyCFunction_CAST(_curses_window_getkey), METH_FASTCALL, _curses_window_getkey__doc__}, static PyObject * _curses_window_getkey_impl(PyCursesWindowObject *self, int group_right_1, int y, int x); static PyObject * -_curses_window_getkey(PyObject *self, PyObject *args) +_curses_window_getkey(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_right_1 = 0; int y = 0; int x = 0; - switch (PyTuple_GET_SIZE(args)) { + switch (nargs) { case 0: - break; case 2: - if (!PyArg_ParseTuple(args, "ii:getkey", &y, &x)) { - goto exit; - } - group_right_1 = 1; break; default: PyErr_SetString(PyExc_TypeError, "_curses.window.getkey requires 0 to 2 arguments"); goto exit; } + if (nargs >= 2) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { + goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { + goto exit; + } + group_right_1 = 1; + } return_value = _curses_window_getkey_impl((PyCursesWindowObject *)self, group_right_1, y, x); exit: @@ -1438,33 +1444,39 @@ PyDoc_STRVAR(_curses_window_get_wch__doc__, "keypad keys, and other special keys."); #define _CURSES_WINDOW_GET_WCH_METHODDEF \ - {"get_wch", (PyCFunction)_curses_window_get_wch, METH_VARARGS, _curses_window_get_wch__doc__}, + {"get_wch", _PyCFunction_CAST(_curses_window_get_wch), METH_FASTCALL, _curses_window_get_wch__doc__}, static PyObject * _curses_window_get_wch_impl(PyCursesWindowObject *self, int group_right_1, int y, int x); static PyObject * -_curses_window_get_wch(PyObject *self, PyObject *args) +_curses_window_get_wch(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_right_1 = 0; int y = 0; int x = 0; - switch (PyTuple_GET_SIZE(args)) { + switch (nargs) { case 0: - break; case 2: - if (!PyArg_ParseTuple(args, "ii:get_wch", &y, &x)) { - goto exit; - } - group_right_1 = 1; break; default: PyErr_SetString(PyExc_TypeError, "_curses.window.get_wch requires 0 to 2 arguments"); goto exit; } + if (nargs >= 2) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { + goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { + goto exit; + } + group_right_1 = 1; + } return_value = _curses_window_get_wch_impl((PyCursesWindowObject *)self, group_right_1, y, x); exit: @@ -1483,14 +1495,14 @@ PyDoc_STRVAR(_curses_window_getstr__doc__, " Maximal number of characters."); #define _CURSES_WINDOW_GETSTR_METHODDEF \ - {"getstr", (PyCFunction)_curses_window_getstr, METH_VARARGS, _curses_window_getstr__doc__}, + {"getstr", _PyCFunction_CAST(_curses_window_getstr), METH_FASTCALL, _curses_window_getstr__doc__}, static PyObject * _curses_window_getstr_impl(PyCursesWindowObject *self, int group_left_1, int y, int x, unsigned int n); static PyObject * -_curses_window_getstr(PyObject *self, PyObject *args) +_curses_window_getstr(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -1498,24 +1510,30 @@ _curses_window_getstr(PyObject *self, PyObject *args) int x = 0; unsigned int n = 2047; - switch (PyTuple_GET_SIZE(args)) { - case 0: - case 1: - if (!PyArg_ParseTuple(args, "|O&:getstr", _PyLong_UnsignedInt_Converter, &n)) { - goto exit; - } - break; - case 2: - case 3: - if (!PyArg_ParseTuple(args, "ii|O&:getstr", &y, &x, _PyLong_UnsignedInt_Converter, &n)) { - goto exit; - } - group_left_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_curses.window.getstr requires 0 to 3 arguments"); + Py_ssize_t offset = 0; + if (nargs > 3) { + PyErr_SetString(PyExc_TypeError, "_curses.window.getstr requires 0 to 3 arguments"); + goto exit; + } + if (nargs >= 2) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { + goto exit; + } + offset += 2; + group_left_1 = 1; + } + if (nargs <= offset) { + goto skip_optional; + } + if (!_PyLong_UnsignedInt_Converter(args[offset], &n)) { + goto exit; } +skip_optional: return_value = _curses_window_getstr_impl((PyCursesWindowObject *)self, group_left_1, y, x, n); exit: @@ -1538,7 +1556,7 @@ PyDoc_STRVAR(_curses_window_hline__doc__, " Attributes for the characters."); #define _CURSES_WINDOW_HLINE_METHODDEF \ - {"hline", (PyCFunction)_curses_window_hline, METH_VARARGS, _curses_window_hline__doc__}, + {"hline", _PyCFunction_CAST(_curses_window_hline), METH_FASTCALL, _curses_window_hline__doc__}, static PyObject * _curses_window_hline_impl(PyCursesWindowObject *self, int group_left_1, @@ -1546,7 +1564,7 @@ _curses_window_hline_impl(PyCursesWindowObject *self, int group_left_1, int group_right_1, attr_t attr); static PyObject * -_curses_window_hline(PyObject *self, PyObject *args) +_curses_window_hline(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -1557,34 +1575,33 @@ _curses_window_hline(PyObject *self, PyObject *args) int group_right_1 = 0; attr_t attr = 0; - switch (PyTuple_GET_SIZE(args)) { - case 2: - if (!PyArg_ParseTuple(args, "Oi:hline", &ch, &n)) { - goto exit; - } - break; - case 3: - if (!PyArg_ParseTuple(args, "OiO&:hline", &ch, &n, attr_converter, &attr)) { - goto exit; - } - group_right_1 = 1; - break; - case 4: - if (!PyArg_ParseTuple(args, "iiOi:hline", &y, &x, &ch, &n)) { - goto exit; - } - group_left_1 = 1; - break; - case 5: - if (!PyArg_ParseTuple(args, "iiOiO&:hline", &y, &x, &ch, &n, attr_converter, &attr)) { - goto exit; - } - group_left_1 = 1; - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_curses.window.hline requires 2 to 5 arguments"); + Py_ssize_t offset = 0; + if (nargs < 2 || nargs > 5) { + PyErr_SetString(PyExc_TypeError, "_curses.window.hline requires 2 to 5 arguments"); + goto exit; + } + if (nargs >= 4) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { + goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { + goto exit; + } + offset += 2; + group_left_1 = 1; + } + ch = args[offset]; + n = PyLong_AsInt(args[offset + 1]); + if (n == -1 && PyErr_Occurred()) { + goto exit; + } + if (nargs == 3 || nargs == 5) { + if (!attr_converter(args[nargs - 1], &attr)) { goto exit; + } + group_right_1 = 1; } return_value = _curses_window_hline_impl((PyCursesWindowObject *)self, group_left_1, y, x, ch, n, group_right_1, attr); @@ -1609,7 +1626,7 @@ PyDoc_STRVAR(_curses_window_insch__doc__, "right, with the rightmost characters on the line being lost."); #define _CURSES_WINDOW_INSCH_METHODDEF \ - {"insch", (PyCFunction)_curses_window_insch, METH_VARARGS, _curses_window_insch__doc__}, + {"insch", _PyCFunction_CAST(_curses_window_insch), METH_FASTCALL, _curses_window_insch__doc__}, static PyObject * _curses_window_insch_impl(PyCursesWindowObject *self, int group_left_1, @@ -1617,7 +1634,7 @@ _curses_window_insch_impl(PyCursesWindowObject *self, int group_left_1, attr_t attr); static PyObject * -_curses_window_insch(PyObject *self, PyObject *args) +_curses_window_insch(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -1627,34 +1644,29 @@ _curses_window_insch(PyObject *self, PyObject *args) int group_right_1 = 0; attr_t attr = 0; - switch (PyTuple_GET_SIZE(args)) { - case 1: - if (!PyArg_ParseTuple(args, "O:insch", &ch)) { - goto exit; - } - break; - case 2: - if (!PyArg_ParseTuple(args, "OO&:insch", &ch, attr_converter, &attr)) { - goto exit; - } - group_right_1 = 1; - break; - case 3: - if (!PyArg_ParseTuple(args, "iiO:insch", &y, &x, &ch)) { - goto exit; - } - group_left_1 = 1; - break; - case 4: - if (!PyArg_ParseTuple(args, "iiOO&:insch", &y, &x, &ch, attr_converter, &attr)) { - goto exit; - } - group_left_1 = 1; - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_curses.window.insch requires 1 to 4 arguments"); + Py_ssize_t offset = 0; + if (nargs < 1 || nargs > 4) { + PyErr_SetString(PyExc_TypeError, "_curses.window.insch requires 1 to 4 arguments"); + goto exit; + } + if (nargs >= 3) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { + goto exit; + } + offset += 2; + group_left_1 = 1; + } + ch = args[offset]; + if (nargs == 2 || nargs == 4) { + if (!attr_converter(args[nargs - 1], &attr)) { + goto exit; + } + group_right_1 = 1; } return_value = _curses_window_insch_impl((PyCursesWindowObject *)self, group_left_1, y, x, ch, group_right_1, attr); @@ -1675,33 +1687,39 @@ PyDoc_STRVAR(_curses_window_inch__doc__, "attributes."); #define _CURSES_WINDOW_INCH_METHODDEF \ - {"inch", (PyCFunction)_curses_window_inch, METH_VARARGS, _curses_window_inch__doc__}, + {"inch", _PyCFunction_CAST(_curses_window_inch), METH_FASTCALL, _curses_window_inch__doc__}, static PyObject * _curses_window_inch_impl(PyCursesWindowObject *self, int group_right_1, int y, int x); static PyObject * -_curses_window_inch(PyObject *self, PyObject *args) +_curses_window_inch(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_right_1 = 0; int y = 0; int x = 0; - switch (PyTuple_GET_SIZE(args)) { + switch (nargs) { case 0: - break; case 2: - if (!PyArg_ParseTuple(args, "ii:inch", &y, &x)) { - goto exit; - } - group_right_1 = 1; break; default: PyErr_SetString(PyExc_TypeError, "_curses.window.inch requires 0 to 2 arguments"); goto exit; } + if (nargs >= 2) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { + goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { + goto exit; + } + group_right_1 = 1; + } return_value = _curses_window_inch_impl((PyCursesWindowObject *)self, group_right_1, y, x); exit: @@ -1727,14 +1745,14 @@ PyDoc_STRVAR(_curses_window_instr__doc__, "the trailing NUL)."); #define _CURSES_WINDOW_INSTR_METHODDEF \ - {"instr", (PyCFunction)_curses_window_instr, METH_VARARGS, _curses_window_instr__doc__}, + {"instr", _PyCFunction_CAST(_curses_window_instr), METH_FASTCALL, _curses_window_instr__doc__}, static PyObject * _curses_window_instr_impl(PyCursesWindowObject *self, int group_left_1, int y, int x, unsigned int n); static PyObject * -_curses_window_instr(PyObject *self, PyObject *args) +_curses_window_instr(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -1742,24 +1760,30 @@ _curses_window_instr(PyObject *self, PyObject *args) int x = 0; unsigned int n = 2047; - switch (PyTuple_GET_SIZE(args)) { - case 0: - case 1: - if (!PyArg_ParseTuple(args, "|O&:instr", _PyLong_UnsignedInt_Converter, &n)) { - goto exit; - } - break; - case 2: - case 3: - if (!PyArg_ParseTuple(args, "ii|O&:instr", &y, &x, _PyLong_UnsignedInt_Converter, &n)) { - goto exit; - } - group_left_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_curses.window.instr requires 0 to 3 arguments"); + Py_ssize_t offset = 0; + if (nargs > 3) { + PyErr_SetString(PyExc_TypeError, "_curses.window.instr requires 0 to 3 arguments"); + goto exit; + } + if (nargs >= 2) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { + goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { goto exit; + } + offset += 2; + group_left_1 = 1; } + if (nargs <= offset) { + goto skip_optional; + } + if (!_PyLong_UnsignedInt_Converter(args[offset], &n)) { + goto exit; + } +skip_optional: return_value = _curses_window_instr_impl((PyCursesWindowObject *)self, group_left_1, y, x, n); exit: @@ -1780,39 +1804,45 @@ PyDoc_STRVAR(_curses_window_get_wstr__doc__, "This is the wide-character variant of getstr(); it returns a str."); #define _CURSES_WINDOW_GET_WSTR_METHODDEF \ - {"get_wstr", (PyCFunction)_curses_window_get_wstr, METH_VARARGS, _curses_window_get_wstr__doc__}, + {"get_wstr", _PyCFunction_CAST(_curses_window_get_wstr), METH_FASTCALL, _curses_window_get_wstr__doc__}, static PyObject * _curses_window_get_wstr_impl(PyCursesWindowObject *self, int group_left_1, int y, int x, unsigned int n); static PyObject * -_curses_window_get_wstr(PyObject *self, PyObject *args) +_curses_window_get_wstr(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; int y = 0; - int x = 0; - unsigned int n = 2047; - - switch (PyTuple_GET_SIZE(args)) { - case 0: - case 1: - if (!PyArg_ParseTuple(args, "|O&:get_wstr", _PyLong_UnsignedInt_Converter, &n)) { - goto exit; - } - break; - case 2: - case 3: - if (!PyArg_ParseTuple(args, "ii|O&:get_wstr", &y, &x, _PyLong_UnsignedInt_Converter, &n)) { - goto exit; - } - group_left_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_curses.window.get_wstr requires 0 to 3 arguments"); + int x = 0; + unsigned int n = 2047; + + Py_ssize_t offset = 0; + if (nargs > 3) { + PyErr_SetString(PyExc_TypeError, "_curses.window.get_wstr requires 0 to 3 arguments"); + goto exit; + } + if (nargs >= 2) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { + goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { goto exit; + } + offset += 2; + group_left_1 = 1; } + if (nargs <= offset) { + goto skip_optional; + } + if (!_PyLong_UnsignedInt_Converter(args[offset], &n)) { + goto exit; + } +skip_optional: return_value = _curses_window_get_wstr_impl((PyCursesWindowObject *)self, group_left_1, y, x, n); exit: @@ -1833,14 +1863,14 @@ PyDoc_STRVAR(_curses_window_in_wstr__doc__, "This is the wide-character variant of instr(); it returns a str."); #define _CURSES_WINDOW_IN_WSTR_METHODDEF \ - {"in_wstr", (PyCFunction)_curses_window_in_wstr, METH_VARARGS, _curses_window_in_wstr__doc__}, + {"in_wstr", _PyCFunction_CAST(_curses_window_in_wstr), METH_FASTCALL, _curses_window_in_wstr__doc__}, static PyObject * _curses_window_in_wstr_impl(PyCursesWindowObject *self, int group_left_1, int y, int x, unsigned int n); static PyObject * -_curses_window_in_wstr(PyObject *self, PyObject *args) +_curses_window_in_wstr(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -1848,24 +1878,30 @@ _curses_window_in_wstr(PyObject *self, PyObject *args) int x = 0; unsigned int n = 2047; - switch (PyTuple_GET_SIZE(args)) { - case 0: - case 1: - if (!PyArg_ParseTuple(args, "|O&:in_wstr", _PyLong_UnsignedInt_Converter, &n)) { - goto exit; - } - break; - case 2: - case 3: - if (!PyArg_ParseTuple(args, "ii|O&:in_wstr", &y, &x, _PyLong_UnsignedInt_Converter, &n)) { - goto exit; - } - group_left_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_curses.window.in_wstr requires 0 to 3 arguments"); + Py_ssize_t offset = 0; + if (nargs > 3) { + PyErr_SetString(PyExc_TypeError, "_curses.window.in_wstr requires 0 to 3 arguments"); + goto exit; + } + if (nargs >= 2) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { + goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { goto exit; + } + offset += 2; + group_left_1 = 1; + } + if (nargs <= offset) { + goto skip_optional; + } + if (!_PyLong_UnsignedInt_Converter(args[offset], &n)) { + goto exit; } +skip_optional: return_value = _curses_window_in_wstr_impl((PyCursesWindowObject *)self, group_left_1, y, x, n); exit: @@ -1888,14 +1924,14 @@ PyDoc_STRVAR(_curses_window_in_wchstr__doc__, "complexstr."); #define _CURSES_WINDOW_IN_WCHSTR_METHODDEF \ - {"in_wchstr", (PyCFunction)_curses_window_in_wchstr, METH_VARARGS, _curses_window_in_wchstr__doc__}, + {"in_wchstr", _PyCFunction_CAST(_curses_window_in_wchstr), METH_FASTCALL, _curses_window_in_wchstr__doc__}, static PyObject * _curses_window_in_wchstr_impl(PyCursesWindowObject *self, int group_left_1, int y, int x, unsigned int n); static PyObject * -_curses_window_in_wchstr(PyObject *self, PyObject *args) +_curses_window_in_wchstr(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -1903,24 +1939,30 @@ _curses_window_in_wchstr(PyObject *self, PyObject *args) int x = 0; unsigned int n = 2047; - switch (PyTuple_GET_SIZE(args)) { - case 0: - case 1: - if (!PyArg_ParseTuple(args, "|O&:in_wchstr", _PyLong_UnsignedInt_Converter, &n)) { - goto exit; - } - break; - case 2: - case 3: - if (!PyArg_ParseTuple(args, "ii|O&:in_wchstr", &y, &x, _PyLong_UnsignedInt_Converter, &n)) { - goto exit; - } - group_left_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_curses.window.in_wchstr requires 0 to 3 arguments"); + Py_ssize_t offset = 0; + if (nargs > 3) { + PyErr_SetString(PyExc_TypeError, "_curses.window.in_wchstr requires 0 to 3 arguments"); + goto exit; + } + if (nargs >= 2) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { + goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { goto exit; + } + offset += 2; + group_left_1 = 1; } + if (nargs <= offset) { + goto skip_optional; + } + if (!_PyLong_UnsignedInt_Converter(args[offset], &n)) { + goto exit; + } +skip_optional: return_value = _curses_window_in_wchstr_impl((PyCursesWindowObject *)self, group_left_1, y, x, n); exit: @@ -1947,7 +1989,7 @@ PyDoc_STRVAR(_curses_window_insstr__doc__, "moving to y, x, if specified)."); #define _CURSES_WINDOW_INSSTR_METHODDEF \ - {"insstr", (PyCFunction)_curses_window_insstr, METH_VARARGS, _curses_window_insstr__doc__}, + {"insstr", _PyCFunction_CAST(_curses_window_insstr), METH_FASTCALL, _curses_window_insstr__doc__}, static PyObject * _curses_window_insstr_impl(PyCursesWindowObject *self, int group_left_1, @@ -1955,7 +1997,7 @@ _curses_window_insstr_impl(PyCursesWindowObject *self, int group_left_1, attr_t attr); static PyObject * -_curses_window_insstr(PyObject *self, PyObject *args) +_curses_window_insstr(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -1965,34 +2007,29 @@ _curses_window_insstr(PyObject *self, PyObject *args) int group_right_1 = 0; attr_t attr = 0; - switch (PyTuple_GET_SIZE(args)) { - case 1: - if (!PyArg_ParseTuple(args, "O:insstr", &str)) { - goto exit; - } - break; - case 2: - if (!PyArg_ParseTuple(args, "OO&:insstr", &str, attr_converter, &attr)) { - goto exit; - } - group_right_1 = 1; - break; - case 3: - if (!PyArg_ParseTuple(args, "iiO:insstr", &y, &x, &str)) { - goto exit; - } - group_left_1 = 1; - break; - case 4: - if (!PyArg_ParseTuple(args, "iiOO&:insstr", &y, &x, &str, attr_converter, &attr)) { - goto exit; - } - group_left_1 = 1; - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_curses.window.insstr requires 1 to 4 arguments"); + Py_ssize_t offset = 0; + if (nargs < 1 || nargs > 4) { + PyErr_SetString(PyExc_TypeError, "_curses.window.insstr requires 1 to 4 arguments"); + goto exit; + } + if (nargs >= 3) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { + goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { + goto exit; + } + offset += 2; + group_left_1 = 1; + } + str = args[offset]; + if (nargs == 2 || nargs == 4) { + if (!attr_converter(args[nargs - 1], &attr)) { goto exit; + } + group_right_1 = 1; } return_value = _curses_window_insstr_impl((PyCursesWindowObject *)self, group_left_1, y, x, str, group_right_1, attr); @@ -2023,7 +2060,7 @@ PyDoc_STRVAR(_curses_window_insnstr__doc__, "does not change (after moving to y, x, if specified)."); #define _CURSES_WINDOW_INSNSTR_METHODDEF \ - {"insnstr", (PyCFunction)_curses_window_insnstr, METH_VARARGS, _curses_window_insnstr__doc__}, + {"insnstr", _PyCFunction_CAST(_curses_window_insnstr), METH_FASTCALL, _curses_window_insnstr__doc__}, static PyObject * _curses_window_insnstr_impl(PyCursesWindowObject *self, int group_left_1, @@ -2031,7 +2068,7 @@ _curses_window_insnstr_impl(PyCursesWindowObject *self, int group_left_1, int group_right_1, attr_t attr); static PyObject * -_curses_window_insnstr(PyObject *self, PyObject *args) +_curses_window_insnstr(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -2042,34 +2079,33 @@ _curses_window_insnstr(PyObject *self, PyObject *args) int group_right_1 = 0; attr_t attr = 0; - switch (PyTuple_GET_SIZE(args)) { - case 2: - if (!PyArg_ParseTuple(args, "Oi:insnstr", &str, &n)) { - goto exit; - } - break; - case 3: - if (!PyArg_ParseTuple(args, "OiO&:insnstr", &str, &n, attr_converter, &attr)) { - goto exit; - } - group_right_1 = 1; - break; - case 4: - if (!PyArg_ParseTuple(args, "iiOi:insnstr", &y, &x, &str, &n)) { - goto exit; - } - group_left_1 = 1; - break; - case 5: - if (!PyArg_ParseTuple(args, "iiOiO&:insnstr", &y, &x, &str, &n, attr_converter, &attr)) { - goto exit; - } - group_left_1 = 1; - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_curses.window.insnstr requires 2 to 5 arguments"); + Py_ssize_t offset = 0; + if (nargs < 2 || nargs > 5) { + PyErr_SetString(PyExc_TypeError, "_curses.window.insnstr requires 2 to 5 arguments"); + goto exit; + } + if (nargs >= 4) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { + goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { goto exit; + } + offset += 2; + group_left_1 = 1; + } + str = args[offset]; + n = PyLong_AsInt(args[offset + 1]); + if (n == -1 && PyErr_Occurred()) { + goto exit; + } + if (nargs == 3 || nargs == 5) { + if (!attr_converter(args[nargs - 1], &attr)) { + goto exit; + } + group_right_1 = 1; } return_value = _curses_window_insnstr_impl((PyCursesWindowObject *)self, group_left_1, y, x, str, n, group_right_1, attr); @@ -2122,7 +2158,7 @@ PyDoc_STRVAR(_curses_window_noutrefresh__doc__, "screen. To accomplish that, call doupdate()."); #define _CURSES_WINDOW_NOUTREFRESH_METHODDEF \ - {"noutrefresh", (PyCFunction)_curses_window_noutrefresh, METH_VARARGS, _curses_window_noutrefresh__doc__}, + {"noutrefresh", _PyCFunction_CAST(_curses_window_noutrefresh), METH_FASTCALL, _curses_window_noutrefresh__doc__}, static PyObject * _curses_window_noutrefresh_impl(PyCursesWindowObject *self, @@ -2131,7 +2167,7 @@ _curses_window_noutrefresh_impl(PyCursesWindowObject *self, int smaxcol); static PyObject * -_curses_window_noutrefresh(PyObject *self, PyObject *args) +_curses_window_noutrefresh(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_right_1 = 0; @@ -2142,19 +2178,41 @@ _curses_window_noutrefresh(PyObject *self, PyObject *args) int smaxrow = 0; int smaxcol = 0; - switch (PyTuple_GET_SIZE(args)) { + switch (nargs) { case 0: - break; case 6: - if (!PyArg_ParseTuple(args, "iiiiii:noutrefresh", &pminrow, &pmincol, &sminrow, &smincol, &smaxrow, &smaxcol)) { - goto exit; - } - group_right_1 = 1; break; default: PyErr_SetString(PyExc_TypeError, "_curses.window.noutrefresh requires 0 to 6 arguments"); goto exit; } + if (nargs >= 6) { + pminrow = PyLong_AsInt(args[0]); + if (pminrow == -1 && PyErr_Occurred()) { + goto exit; + } + pmincol = PyLong_AsInt(args[1]); + if (pmincol == -1 && PyErr_Occurred()) { + goto exit; + } + sminrow = PyLong_AsInt(args[2]); + if (sminrow == -1 && PyErr_Occurred()) { + goto exit; + } + smincol = PyLong_AsInt(args[3]); + if (smincol == -1 && PyErr_Occurred()) { + goto exit; + } + smaxrow = PyLong_AsInt(args[4]); + if (smaxrow == -1 && PyErr_Occurred()) { + goto exit; + } + smaxcol = PyLong_AsInt(args[5]); + if (smaxcol == -1 && PyErr_Occurred()) { + goto exit; + } + group_right_1 = 1; + } return_value = _curses_window_noutrefresh_impl((PyCursesWindowObject *)self, group_right_1, pminrow, pmincol, sminrow, smincol, smaxrow, smaxcol); exit: @@ -2204,7 +2262,7 @@ PyDoc_STRVAR(_curses_window_overlay__doc__, "a rectangle in the destination window."); #define _CURSES_WINDOW_OVERLAY_METHODDEF \ - {"overlay", (PyCFunction)_curses_window_overlay, METH_VARARGS, _curses_window_overlay__doc__}, + {"overlay", _PyCFunction_CAST(_curses_window_overlay), METH_FASTCALL, _curses_window_overlay__doc__}, static PyObject * _curses_window_overlay_impl(PyCursesWindowObject *self, @@ -2213,7 +2271,7 @@ _curses_window_overlay_impl(PyCursesWindowObject *self, int dmincol, int dmaxrow, int dmaxcol); static PyObject * -_curses_window_overlay(PyObject *self, PyObject *args) +_curses_window_overlay(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyCursesWindowObject *destwin; @@ -2225,22 +2283,46 @@ _curses_window_overlay(PyObject *self, PyObject *args) int dmaxrow = 0; int dmaxcol = 0; - switch (PyTuple_GET_SIZE(args)) { + switch (nargs) { case 1: - if (!PyArg_ParseTuple(args, "O!:overlay", clinic_state()->window_type, &destwin)) { - goto exit; - } - break; case 7: - if (!PyArg_ParseTuple(args, "O!iiiiii:overlay", clinic_state()->window_type, &destwin, &sminrow, &smincol, &dminrow, &dmincol, &dmaxrow, &dmaxcol)) { - goto exit; - } - group_right_1 = 1; break; default: PyErr_SetString(PyExc_TypeError, "_curses.window.overlay requires 1 to 7 arguments"); goto exit; } + if (!PyObject_TypeCheck(args[0], clinic_state()->window_type)) { + _PyArg_BadArgument("overlay", "argument 1", (clinic_state()->window_type)->tp_name, args[0]); + goto exit; + } + destwin = (PyCursesWindowObject *)args[0]; + if (nargs >= 7) { + sminrow = PyLong_AsInt(args[1]); + if (sminrow == -1 && PyErr_Occurred()) { + goto exit; + } + smincol = PyLong_AsInt(args[2]); + if (smincol == -1 && PyErr_Occurred()) { + goto exit; + } + dminrow = PyLong_AsInt(args[3]); + if (dminrow == -1 && PyErr_Occurred()) { + goto exit; + } + dmincol = PyLong_AsInt(args[4]); + if (dmincol == -1 && PyErr_Occurred()) { + goto exit; + } + dmaxrow = PyLong_AsInt(args[5]); + if (dmaxrow == -1 && PyErr_Occurred()) { + goto exit; + } + dmaxcol = PyLong_AsInt(args[6]); + if (dmaxcol == -1 && PyErr_Occurred()) { + goto exit; + } + group_right_1 = 1; + } return_value = _curses_window_overlay_impl((PyCursesWindowObject *)self, destwin, group_right_1, sminrow, smincol, dminrow, dmincol, dmaxrow, dmaxcol); exit: @@ -2263,7 +2345,7 @@ PyDoc_STRVAR(_curses_window_overwrite__doc__, "a rectangle in the destination window."); #define _CURSES_WINDOW_OVERWRITE_METHODDEF \ - {"overwrite", (PyCFunction)_curses_window_overwrite, METH_VARARGS, _curses_window_overwrite__doc__}, + {"overwrite", _PyCFunction_CAST(_curses_window_overwrite), METH_FASTCALL, _curses_window_overwrite__doc__}, static PyObject * _curses_window_overwrite_impl(PyCursesWindowObject *self, @@ -2273,7 +2355,7 @@ _curses_window_overwrite_impl(PyCursesWindowObject *self, int dmaxcol); static PyObject * -_curses_window_overwrite(PyObject *self, PyObject *args) +_curses_window_overwrite(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyCursesWindowObject *destwin; @@ -2285,22 +2367,46 @@ _curses_window_overwrite(PyObject *self, PyObject *args) int dmaxrow = 0; int dmaxcol = 0; - switch (PyTuple_GET_SIZE(args)) { + switch (nargs) { case 1: - if (!PyArg_ParseTuple(args, "O!:overwrite", clinic_state()->window_type, &destwin)) { - goto exit; - } - break; case 7: - if (!PyArg_ParseTuple(args, "O!iiiiii:overwrite", clinic_state()->window_type, &destwin, &sminrow, &smincol, &dminrow, &dmincol, &dmaxrow, &dmaxcol)) { - goto exit; - } - group_right_1 = 1; break; default: PyErr_SetString(PyExc_TypeError, "_curses.window.overwrite requires 1 to 7 arguments"); goto exit; } + if (!PyObject_TypeCheck(args[0], clinic_state()->window_type)) { + _PyArg_BadArgument("overwrite", "argument 1", (clinic_state()->window_type)->tp_name, args[0]); + goto exit; + } + destwin = (PyCursesWindowObject *)args[0]; + if (nargs >= 7) { + sminrow = PyLong_AsInt(args[1]); + if (sminrow == -1 && PyErr_Occurred()) { + goto exit; + } + smincol = PyLong_AsInt(args[2]); + if (smincol == -1 && PyErr_Occurred()) { + goto exit; + } + dminrow = PyLong_AsInt(args[3]); + if (dminrow == -1 && PyErr_Occurred()) { + goto exit; + } + dmincol = PyLong_AsInt(args[4]); + if (dmincol == -1 && PyErr_Occurred()) { + goto exit; + } + dmaxrow = PyLong_AsInt(args[5]); + if (dmaxrow == -1 && PyErr_Occurred()) { + goto exit; + } + dmaxcol = PyLong_AsInt(args[6]); + if (dmaxcol == -1 && PyErr_Occurred()) { + goto exit; + } + group_right_1 = 1; + } return_value = _curses_window_overwrite_impl((PyCursesWindowObject *)self, destwin, group_right_1, sminrow, smincol, dminrow, dmincol, dmaxrow, dmaxcol); exit: @@ -2392,7 +2498,7 @@ PyDoc_STRVAR(_curses_window_refresh__doc__, "pmincol, sminrow, or smincol are treated as if they were zero."); #define _CURSES_WINDOW_REFRESH_METHODDEF \ - {"refresh", (PyCFunction)_curses_window_refresh, METH_VARARGS, _curses_window_refresh__doc__}, + {"refresh", _PyCFunction_CAST(_curses_window_refresh), METH_FASTCALL, _curses_window_refresh__doc__}, static PyObject * _curses_window_refresh_impl(PyCursesWindowObject *self, int group_right_1, @@ -2400,7 +2506,7 @@ _curses_window_refresh_impl(PyCursesWindowObject *self, int group_right_1, int smincol, int smaxrow, int smaxcol); static PyObject * -_curses_window_refresh(PyObject *self, PyObject *args) +_curses_window_refresh(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_right_1 = 0; @@ -2411,19 +2517,41 @@ _curses_window_refresh(PyObject *self, PyObject *args) int smaxrow = 0; int smaxcol = 0; - switch (PyTuple_GET_SIZE(args)) { + switch (nargs) { case 0: - break; case 6: - if (!PyArg_ParseTuple(args, "iiiiii:refresh", &pminrow, &pmincol, &sminrow, &smincol, &smaxrow, &smaxcol)) { - goto exit; - } - group_right_1 = 1; break; default: PyErr_SetString(PyExc_TypeError, "_curses.window.refresh requires 0 to 6 arguments"); goto exit; } + if (nargs >= 6) { + pminrow = PyLong_AsInt(args[0]); + if (pminrow == -1 && PyErr_Occurred()) { + goto exit; + } + pmincol = PyLong_AsInt(args[1]); + if (pmincol == -1 && PyErr_Occurred()) { + goto exit; + } + sminrow = PyLong_AsInt(args[2]); + if (sminrow == -1 && PyErr_Occurred()) { + goto exit; + } + smincol = PyLong_AsInt(args[3]); + if (smincol == -1 && PyErr_Occurred()) { + goto exit; + } + smaxrow = PyLong_AsInt(args[4]); + if (smaxrow == -1 && PyErr_Occurred()) { + goto exit; + } + smaxcol = PyLong_AsInt(args[5]); + if (smaxcol == -1 && PyErr_Occurred()) { + goto exit; + } + group_right_1 = 1; + } return_value = _curses_window_refresh_impl((PyCursesWindowObject *)self, group_right_1, pminrow, pmincol, sminrow, smincol, smaxrow, smaxcol); exit: @@ -2491,14 +2619,14 @@ PyDoc_STRVAR(_curses_window_subwin__doc__, "to the lower right corner of the window."); #define _CURSES_WINDOW_SUBWIN_METHODDEF \ - {"subwin", (PyCFunction)_curses_window_subwin, METH_VARARGS, _curses_window_subwin__doc__}, + {"subwin", _PyCFunction_CAST(_curses_window_subwin), METH_FASTCALL, _curses_window_subwin__doc__}, static PyObject * _curses_window_subwin_impl(PyCursesWindowObject *self, int group_left_1, int nlines, int ncols, int begin_y, int begin_x); static PyObject * -_curses_window_subwin(PyObject *self, PyObject *args) +_curses_window_subwin(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -2507,22 +2635,33 @@ _curses_window_subwin(PyObject *self, PyObject *args) int begin_y; int begin_x; - switch (PyTuple_GET_SIZE(args)) { + switch (nargs) { case 2: - if (!PyArg_ParseTuple(args, "ii:subwin", &begin_y, &begin_x)) { - goto exit; - } - break; case 4: - if (!PyArg_ParseTuple(args, "iiii:subwin", &nlines, &ncols, &begin_y, &begin_x)) { - goto exit; - } - group_left_1 = 1; break; default: PyErr_SetString(PyExc_TypeError, "_curses.window.subwin requires 2 to 4 arguments"); goto exit; } + if (nargs >= 4) { + nlines = PyLong_AsInt(args[0]); + if (nlines == -1 && PyErr_Occurred()) { + goto exit; + } + ncols = PyLong_AsInt(args[1]); + if (ncols == -1 && PyErr_Occurred()) { + goto exit; + } + group_left_1 = 1; + } + begin_y = PyLong_AsInt(args[nargs - 2]); + if (begin_y == -1 && PyErr_Occurred()) { + goto exit; + } + begin_x = PyLong_AsInt(args[nargs - 1]); + if (begin_x == -1 && PyErr_Occurred()) { + goto exit; + } return_value = _curses_window_subwin_impl((PyCursesWindowObject *)self, group_left_1, nlines, ncols, begin_y, begin_x); exit: @@ -2540,31 +2679,29 @@ PyDoc_STRVAR(_curses_window_scroll__doc__, "negative."); #define _CURSES_WINDOW_SCROLL_METHODDEF \ - {"scroll", (PyCFunction)_curses_window_scroll, METH_VARARGS, _curses_window_scroll__doc__}, + {"scroll", _PyCFunction_CAST(_curses_window_scroll), METH_FASTCALL, _curses_window_scroll__doc__}, static PyObject * _curses_window_scroll_impl(PyCursesWindowObject *self, int group_right_1, int lines); static PyObject * -_curses_window_scroll(PyObject *self, PyObject *args) +_curses_window_scroll(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_right_1 = 0; int lines = 1; - switch (PyTuple_GET_SIZE(args)) { - case 0: - break; - case 1: - if (!PyArg_ParseTuple(args, "i:scroll", &lines)) { - goto exit; - } - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_curses.window.scroll requires 0 to 1 arguments"); + if (nargs > 1) { + PyErr_SetString(PyExc_TypeError, "_curses.window.scroll requires 0 to 1 arguments"); + goto exit; + } + if (nargs >= 1) { + lines = PyLong_AsInt(args[0]); + if (lines == -1 && PyErr_Occurred()) { goto exit; + } + group_right_1 = 1; } return_value = _curses_window_scroll_impl((PyCursesWindowObject *)self, group_right_1, lines); @@ -2581,14 +2718,14 @@ PyDoc_STRVAR(_curses_window_touchline__doc__, "(changed=False)."); #define _CURSES_WINDOW_TOUCHLINE_METHODDEF \ - {"touchline", (PyCFunction)_curses_window_touchline, METH_VARARGS, _curses_window_touchline__doc__}, + {"touchline", _PyCFunction_CAST(_curses_window_touchline), METH_FASTCALL, _curses_window_touchline__doc__}, static PyObject * _curses_window_touchline_impl(PyCursesWindowObject *self, int start, int count, int group_right_1, int changed); static PyObject * -_curses_window_touchline(PyObject *self, PyObject *args) +_curses_window_touchline(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int start; @@ -2596,21 +2733,24 @@ _curses_window_touchline(PyObject *self, PyObject *args) int group_right_1 = 0; int changed = 1; - switch (PyTuple_GET_SIZE(args)) { - case 2: - if (!PyArg_ParseTuple(args, "ii:touchline", &start, &count)) { - goto exit; - } - break; - case 3: - if (!PyArg_ParseTuple(args, "iip:touchline", &start, &count, &changed)) { - goto exit; - } - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_curses.window.touchline requires 2 to 3 arguments"); + if (nargs < 2 || nargs > 3) { + PyErr_SetString(PyExc_TypeError, "_curses.window.touchline requires 2 to 3 arguments"); + goto exit; + } + start = PyLong_AsInt(args[0]); + if (start == -1 && PyErr_Occurred()) { + goto exit; + } + count = PyLong_AsInt(args[1]); + if (count == -1 && PyErr_Occurred()) { + goto exit; + } + if (nargs >= 3) { + changed = PyObject_IsTrue(args[2]); + if (changed < 0) { goto exit; + } + group_right_1 = 1; } return_value = _curses_window_touchline_impl((PyCursesWindowObject *)self, start, count, group_right_1, changed); @@ -2634,7 +2774,7 @@ PyDoc_STRVAR(_curses_window_vline__doc__, " Attributes for the character."); #define _CURSES_WINDOW_VLINE_METHODDEF \ - {"vline", (PyCFunction)_curses_window_vline, METH_VARARGS, _curses_window_vline__doc__}, + {"vline", _PyCFunction_CAST(_curses_window_vline), METH_FASTCALL, _curses_window_vline__doc__}, static PyObject * _curses_window_vline_impl(PyCursesWindowObject *self, int group_left_1, @@ -2642,7 +2782,7 @@ _curses_window_vline_impl(PyCursesWindowObject *self, int group_left_1, int group_right_1, attr_t attr); static PyObject * -_curses_window_vline(PyObject *self, PyObject *args) +_curses_window_vline(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -2653,34 +2793,33 @@ _curses_window_vline(PyObject *self, PyObject *args) int group_right_1 = 0; attr_t attr = 0; - switch (PyTuple_GET_SIZE(args)) { - case 2: - if (!PyArg_ParseTuple(args, "Oi:vline", &ch, &n)) { - goto exit; - } - break; - case 3: - if (!PyArg_ParseTuple(args, "OiO&:vline", &ch, &n, attr_converter, &attr)) { - goto exit; - } - group_right_1 = 1; - break; - case 4: - if (!PyArg_ParseTuple(args, "iiOi:vline", &y, &x, &ch, &n)) { - goto exit; - } - group_left_1 = 1; - break; - case 5: - if (!PyArg_ParseTuple(args, "iiOiO&:vline", &y, &x, &ch, &n, attr_converter, &attr)) { - goto exit; - } - group_left_1 = 1; - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_curses.window.vline requires 2 to 5 arguments"); + Py_ssize_t offset = 0; + if (nargs < 2 || nargs > 5) { + PyErr_SetString(PyExc_TypeError, "_curses.window.vline requires 2 to 5 arguments"); + goto exit; + } + if (nargs >= 4) { + y = PyLong_AsInt(args[0]); + if (y == -1 && PyErr_Occurred()) { + goto exit; + } + x = PyLong_AsInt(args[1]); + if (x == -1 && PyErr_Occurred()) { goto exit; + } + offset += 2; + group_left_1 = 1; + } + ch = args[offset]; + n = PyLong_AsInt(args[offset + 1]); + if (n == -1 && PyErr_Occurred()) { + goto exit; + } + if (nargs == 3 || nargs == 5) { + if (!attr_converter(args[nargs - 1], &attr)) { + goto exit; + } + group_right_1 = 1; } return_value = _curses_window_vline_impl((PyCursesWindowObject *)self, group_left_1, y, x, ch, n, group_right_1, attr); @@ -4807,14 +4946,14 @@ PyDoc_STRVAR(_curses_newwin__doc__, "lower right corner of the screen."); #define _CURSES_NEWWIN_METHODDEF \ - {"newwin", (PyCFunction)_curses_newwin, METH_VARARGS, _curses_newwin__doc__}, + {"newwin", _PyCFunction_CAST(_curses_newwin), METH_FASTCALL, _curses_newwin__doc__}, static PyObject * _curses_newwin_impl(PyObject *module, int nlines, int ncols, int group_right_1, int begin_y, int begin_x); static PyObject * -_curses_newwin(PyObject *module, PyObject *args) +_curses_newwin(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int nlines; @@ -4823,22 +4962,33 @@ _curses_newwin(PyObject *module, PyObject *args) int begin_y = 0; int begin_x = 0; - switch (PyTuple_GET_SIZE(args)) { + switch (nargs) { case 2: - if (!PyArg_ParseTuple(args, "ii:newwin", &nlines, &ncols)) { - goto exit; - } - break; case 4: - if (!PyArg_ParseTuple(args, "iiii:newwin", &nlines, &ncols, &begin_y, &begin_x)) { - goto exit; - } - group_right_1 = 1; break; default: PyErr_SetString(PyExc_TypeError, "_curses.newwin requires 2 to 4 arguments"); goto exit; } + nlines = PyLong_AsInt(args[0]); + if (nlines == -1 && PyErr_Occurred()) { + goto exit; + } + ncols = PyLong_AsInt(args[1]); + if (ncols == -1 && PyErr_Occurred()) { + goto exit; + } + if (nargs >= 4) { + begin_y = PyLong_AsInt(args[2]); + if (begin_y == -1 && PyErr_Occurred()) { + goto exit; + } + begin_x = PyLong_AsInt(args[3]); + if (begin_x == -1 && PyErr_Occurred()) { + goto exit; + } + group_right_1 = 1; + } return_value = _curses_newwin_impl(module, nlines, ncols, group_right_1, begin_y, begin_x); exit: @@ -6585,4 +6735,4 @@ _curses_has_extended_color_support(PyObject *module, PyObject *Py_UNUSED(ignored #ifndef _CURSES_ASSUME_DEFAULT_COLORS_METHODDEF #define _CURSES_ASSUME_DEFAULT_COLORS_METHODDEF #endif /* !defined(_CURSES_ASSUME_DEFAULT_COLORS_METHODDEF) */ -/*[clinic end generated code: output=680f621e7c1f101b input=a9049054013a1b77]*/ +/*[clinic end generated code: output=e23b642a86fd7f59 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_ssl.c.h b/Modules/clinic/_ssl.c.h index e337ed2390a1fc4..0ba747e4fe489ea 100644 --- a/Modules/clinic/_ssl.c.h +++ b/Modules/clinic/_ssl.c.h @@ -6,6 +6,7 @@ preserve # include "pycore_gc.h" // PyGC_Head # include "pycore_runtime.h" // _Py_ID() #endif +#include "pycore_abstract.h" // _PyNumber_Index() #include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION() #include "pycore_long.h" // _PyLong_Size_t_Converter() #include "pycore_modsupport.h" // _PyArg_CheckPositional() @@ -690,35 +691,42 @@ PyDoc_STRVAR(_ssl__SSLSocket_read__doc__, "Read up to size bytes from the SSL socket."); #define _SSL__SSLSOCKET_READ_METHODDEF \ - {"read", (PyCFunction)_ssl__SSLSocket_read, METH_VARARGS, _ssl__SSLSocket_read__doc__}, + {"read", _PyCFunction_CAST(_ssl__SSLSocket_read), METH_FASTCALL, _ssl__SSLSocket_read__doc__}, static PyObject * _ssl__SSLSocket_read_impl(PySSLSocket *self, Py_ssize_t len, int group_right_1, Py_buffer *buffer); static PyObject * -_ssl__SSLSocket_read(PyObject *self, PyObject *args) +_ssl__SSLSocket_read(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; Py_ssize_t len; int group_right_1 = 0; Py_buffer buffer = {NULL, NULL}; - switch (PyTuple_GET_SIZE(args)) { - case 1: - if (!PyArg_ParseTuple(args, "n:read", &len)) { - goto exit; - } - break; - case 2: - if (!PyArg_ParseTuple(args, "nw*:read", &len, &buffer)) { - goto exit; - } - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "_ssl._SSLSocket.read requires 1 to 2 arguments"); + if (nargs < 1 || nargs > 2) { + PyErr_SetString(PyExc_TypeError, "_ssl._SSLSocket.read requires 1 to 2 arguments"); + goto exit; + } + { + Py_ssize_t ival = -1; + PyObject *iobj = _PyNumber_Index(args[0]); + if (iobj != NULL) { + ival = PyLong_AsSsize_t(iobj); + Py_DECREF(iobj); + } + if (ival == -1 && PyErr_Occurred()) { goto exit; + } + len = ival; + } + if (nargs >= 2) { + if (PyObject_GetBuffer(args[1], &buffer, PyBUF_WRITABLE) < 0) { + _PyArg_BadArgument("read", "argument 2", "read-write bytes-like object", args[1]); + goto exit; + } + group_right_1 = 1; } Py_BEGIN_CRITICAL_SECTION(self); return_value = _ssl__SSLSocket_read_impl((PySSLSocket *)self, len, group_right_1, &buffer); @@ -3326,4 +3334,4 @@ _ssl_enum_crls(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObje #ifndef _SSL_ENUM_CRLS_METHODDEF #define _SSL_ENUM_CRLS_METHODDEF #endif /* !defined(_SSL_ENUM_CRLS_METHODDEF) */ -/*[clinic end generated code: output=aef2e74b706c6106 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=6643d091f34595ae input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_testclinic.c.h b/Modules/clinic/_testclinic.c.h index 12bf0639b66427d..088e7d103504ead 100644 --- a/Modules/clinic/_testclinic.c.h +++ b/Modules/clinic/_testclinic.c.h @@ -3481,30 +3481,25 @@ PyDoc_STRVAR(only_group__doc__, "only_group([a])"); #define ONLY_GROUP_METHODDEF \ - {"only_group", (PyCFunction)only_group, METH_VARARGS, only_group__doc__}, + {"only_group", _PyCFunction_CAST(only_group), METH_FASTCALL, only_group__doc__}, static PyObject * only_group_impl(PyObject *module, int group_right_1, PyObject *a); static PyObject * -only_group(PyObject *module, PyObject *args) +only_group(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_right_1 = 0; PyObject *a = NULL; - switch (PyTuple_GET_SIZE(args)) { - case 0: - break; - case 1: - if (!PyArg_ParseTuple(args, "O:only_group", &a)) { - goto exit; - } - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "only_group requires 0 to 1 arguments"); - goto exit; + if (nargs > 1) { + PyErr_SetString(PyExc_TypeError, "only_group requires 0 to 1 arguments"); + goto exit; + } + if (nargs >= 1) { + a = args[0]; + group_right_1 = 1; } return_value = only_group_impl(module, group_right_1, a); @@ -3516,14 +3511,14 @@ PyDoc_STRVAR(group_and_opt__doc__, "group_and_opt([a, b,] c=None)"); #define GROUP_AND_OPT_METHODDEF \ - {"group_and_opt", (PyCFunction)group_and_opt, METH_VARARGS, group_and_opt__doc__}, + {"group_and_opt", _PyCFunction_CAST(group_and_opt), METH_FASTCALL, group_and_opt__doc__}, static PyObject * group_and_opt_impl(PyObject *module, int group_left_1, PyObject *a, PyObject *b, PyObject *c); static PyObject * -group_and_opt(PyObject *module, PyObject *args) +group_and_opt(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -3531,24 +3526,22 @@ group_and_opt(PyObject *module, PyObject *args) PyObject *b = NULL; PyObject *c = Py_None; - switch (PyTuple_GET_SIZE(args)) { - case 0: - case 1: - if (!PyArg_ParseTuple(args, "|O:group_and_opt", &c)) { - goto exit; - } - break; - case 2: - case 3: - if (!PyArg_ParseTuple(args, "OO|O:group_and_opt", &a, &b, &c)) { - goto exit; - } - group_left_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "group_and_opt requires 0 to 3 arguments"); - goto exit; + Py_ssize_t offset = 0; + if (nargs > 3) { + PyErr_SetString(PyExc_TypeError, "group_and_opt requires 0 to 3 arguments"); + goto exit; + } + if (nargs >= 2) { + a = args[0]; + b = args[1]; + offset += 2; + group_left_1 = 1; + } + if (nargs <= offset) { + goto skip_optional; } + c = args[offset]; +skip_optional: return_value = group_and_opt_impl(module, group_left_1, a, b, c); exit: @@ -3559,7 +3552,7 @@ PyDoc_STRVAR(two_groups_on_left__doc__, "two_groups_on_left([a, b,] [c,] d)"); #define TWO_GROUPS_ON_LEFT_METHODDEF \ - {"two_groups_on_left", (PyCFunction)two_groups_on_left, METH_VARARGS, two_groups_on_left__doc__}, + {"two_groups_on_left", _PyCFunction_CAST(two_groups_on_left), METH_FASTCALL, two_groups_on_left__doc__}, static PyObject * two_groups_on_left_impl(PyObject *module, int group_left_1, PyObject *a, @@ -3567,7 +3560,7 @@ two_groups_on_left_impl(PyObject *module, int group_left_1, PyObject *a, PyObject *d); static PyObject * -two_groups_on_left(PyObject *module, PyObject *args) +two_groups_on_left(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -3577,35 +3570,20 @@ two_groups_on_left(PyObject *module, PyObject *args) PyObject *c = NULL; PyObject *d; - switch (PyTuple_GET_SIZE(args)) { - case 1: - if (!PyArg_ParseTuple(args, "O:two_groups_on_left", &d)) { - goto exit; - } - break; - case 2: - if (!PyArg_ParseTuple(args, "OO:two_groups_on_left", &c, &d)) { - goto exit; - } - group_left_2 = 1; - break; - case 3: - if (!PyArg_ParseTuple(args, "OOO:two_groups_on_left", &a, &b, &d)) { - goto exit; - } - group_left_1 = 1; - break; - case 4: - if (!PyArg_ParseTuple(args, "OOOO:two_groups_on_left", &a, &b, &c, &d)) { - goto exit; - } - group_left_1 = 1; - group_left_2 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "two_groups_on_left requires 1 to 4 arguments"); - goto exit; + if (nargs < 1 || nargs > 4) { + PyErr_SetString(PyExc_TypeError, "two_groups_on_left requires 1 to 4 arguments"); + goto exit; + } + if (nargs >= 3) { + a = args[0]; + b = args[1]; + group_left_1 = 1; + } + if (nargs == 2 || nargs == 4) { + c = args[nargs - 2]; + group_left_2 = 1; } + d = args[nargs - 1]; return_value = two_groups_on_left_impl(module, group_left_1, a, b, group_left_2, c, d); exit: @@ -3616,7 +3594,7 @@ PyDoc_STRVAR(two_groups_on_right__doc__, "two_groups_on_right(a, [b,] [c, d])"); #define TWO_GROUPS_ON_RIGHT_METHODDEF \ - {"two_groups_on_right", (PyCFunction)two_groups_on_right, METH_VARARGS, two_groups_on_right__doc__}, + {"two_groups_on_right", _PyCFunction_CAST(two_groups_on_right), METH_FASTCALL, two_groups_on_right__doc__}, static PyObject * two_groups_on_right_impl(PyObject *module, PyObject *a, int group_right_1, @@ -3624,7 +3602,7 @@ two_groups_on_right_impl(PyObject *module, PyObject *a, int group_right_1, PyObject *d); static PyObject * -two_groups_on_right(PyObject *module, PyObject *args) +two_groups_on_right(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyObject *a; @@ -3634,34 +3612,19 @@ two_groups_on_right(PyObject *module, PyObject *args) PyObject *c = NULL; PyObject *d = NULL; - switch (PyTuple_GET_SIZE(args)) { - case 1: - if (!PyArg_ParseTuple(args, "O:two_groups_on_right", &a)) { - goto exit; - } - break; - case 2: - if (!PyArg_ParseTuple(args, "OO:two_groups_on_right", &a, &b)) { - goto exit; - } - group_right_1 = 1; - break; - case 3: - if (!PyArg_ParseTuple(args, "OOO:two_groups_on_right", &a, &c, &d)) { - goto exit; - } - group_right_2 = 1; - break; - case 4: - if (!PyArg_ParseTuple(args, "OOOO:two_groups_on_right", &a, &b, &c, &d)) { - goto exit; - } - group_right_1 = 1; - group_right_2 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "two_groups_on_right requires 1 to 4 arguments"); - goto exit; + if (nargs < 1 || nargs > 4) { + PyErr_SetString(PyExc_TypeError, "two_groups_on_right requires 1 to 4 arguments"); + goto exit; + } + a = args[0]; + if (nargs == 2 || nargs == 4) { + b = args[1]; + group_right_1 = 1; + } + if (nargs >= 3) { + c = args[nargs - 2]; + d = args[nargs - 1]; + group_right_2 = 1; } return_value = two_groups_on_right_impl(module, a, group_right_1, b, group_right_2, c, d); @@ -3673,14 +3636,14 @@ PyDoc_STRVAR(group_and_two_opt__doc__, "group_and_two_opt([a, b, c,] d=None, e=None)"); #define GROUP_AND_TWO_OPT_METHODDEF \ - {"group_and_two_opt", (PyCFunction)group_and_two_opt, METH_VARARGS, group_and_two_opt__doc__}, + {"group_and_two_opt", _PyCFunction_CAST(group_and_two_opt), METH_FASTCALL, group_and_two_opt__doc__}, static PyObject * group_and_two_opt_impl(PyObject *module, int group_left_1, PyObject *a, PyObject *b, PyObject *c, PyObject *d, PyObject *e); static PyObject * -group_and_two_opt(PyObject *module, PyObject *args) +group_and_two_opt(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -3690,26 +3653,27 @@ group_and_two_opt(PyObject *module, PyObject *args) PyObject *d = Py_None; PyObject *e = Py_None; - switch (PyTuple_GET_SIZE(args)) { - case 0: - case 1: - case 2: - if (!PyArg_ParseTuple(args, "|OO:group_and_two_opt", &d, &e)) { - goto exit; - } - break; - case 3: - case 4: - case 5: - if (!PyArg_ParseTuple(args, "OOO|OO:group_and_two_opt", &a, &b, &c, &d, &e)) { - goto exit; - } - group_left_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "group_and_two_opt requires 0 to 5 arguments"); - goto exit; + Py_ssize_t offset = 0; + if (nargs > 5) { + PyErr_SetString(PyExc_TypeError, "group_and_two_opt requires 0 to 5 arguments"); + goto exit; + } + if (nargs >= 3) { + a = args[0]; + b = args[1]; + c = args[2]; + offset += 3; + group_left_1 = 1; + } + if (nargs <= offset) { + goto skip_optional; } + d = args[offset]; + if (nargs <= offset + 1) { + goto skip_optional; + } + e = args[offset + 1]; +skip_optional: return_value = group_and_two_opt_impl(module, group_left_1, a, b, c, d, e); exit: @@ -4839,4 +4803,4 @@ _testclinic_TestClass_posonly_poskw_varpos_array_no_fastcall(PyObject *type, PyO exit: return return_value; } -/*[clinic end generated code: output=15e6c430697bd384 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=10c3b999199d7bbb input=a9049054013a1b77]*/ diff --git a/Modules/clinic/gcmodule.c.h b/Modules/clinic/gcmodule.c.h index aa743c8f40a565f..0ec615c61cbb2f6 100644 --- a/Modules/clinic/gcmodule.c.h +++ b/Modules/clinic/gcmodule.c.h @@ -224,14 +224,14 @@ PyDoc_STRVAR(gc_set_threshold__doc__, "Setting \'threshold0\' to zero disables collection."); #define GC_SET_THRESHOLD_METHODDEF \ - {"set_threshold", (PyCFunction)gc_set_threshold, METH_VARARGS, gc_set_threshold__doc__}, + {"set_threshold", _PyCFunction_CAST(gc_set_threshold), METH_FASTCALL, gc_set_threshold__doc__}, static PyObject * gc_set_threshold_impl(PyObject *module, int threshold0, int group_right_1, int threshold1, int group_right_2, int threshold2); static PyObject * -gc_set_threshold(PyObject *module, PyObject *args) +gc_set_threshold(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int threshold0; @@ -240,28 +240,27 @@ gc_set_threshold(PyObject *module, PyObject *args) int group_right_2 = 0; int threshold2 = 0; - switch (PyTuple_GET_SIZE(args)) { - case 1: - if (!PyArg_ParseTuple(args, "i:set_threshold", &threshold0)) { - goto exit; - } - break; - case 2: - if (!PyArg_ParseTuple(args, "ii:set_threshold", &threshold0, &threshold1)) { - goto exit; - } - group_right_1 = 1; - break; - case 3: - if (!PyArg_ParseTuple(args, "iii:set_threshold", &threshold0, &threshold1, &threshold2)) { - goto exit; - } - group_right_1 = 1; - group_right_2 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "gc.set_threshold requires 1 to 3 arguments"); + if (nargs < 1 || nargs > 3) { + PyErr_SetString(PyExc_TypeError, "gc.set_threshold requires 1 to 3 arguments"); + goto exit; + } + threshold0 = PyLong_AsInt(args[0]); + if (threshold0 == -1 && PyErr_Occurred()) { + goto exit; + } + if (nargs >= 2) { + threshold1 = PyLong_AsInt(args[1]); + if (threshold1 == -1 && PyErr_Occurred()) { + goto exit; + } + group_right_1 = 1; + } + if (nargs >= 3) { + threshold2 = PyLong_AsInt(args[2]); + if (threshold2 == -1 && PyErr_Occurred()) { goto exit; + } + group_right_2 = 1; } return_value = gc_set_threshold_impl(module, threshold0, group_right_1, threshold1, group_right_2, threshold2); @@ -584,4 +583,4 @@ gc_get_freeze_count(PyObject *module, PyObject *Py_UNUSED(ignored)) exit: return return_value; } -/*[clinic end generated code: output=756c0e7719b76971 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=d0cb000f41ffe433 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/syslogmodule.c.h b/Modules/clinic/syslogmodule.c.h index f9034982f3b2c7f..1603d8ba9ff1c29 100644 --- a/Modules/clinic/syslogmodule.c.h +++ b/Modules/clinic/syslogmodule.c.h @@ -105,35 +105,43 @@ PyDoc_STRVAR(syslog_syslog__doc__, "Send the string message to the system logger."); #define SYSLOG_SYSLOG_METHODDEF \ - {"syslog", (PyCFunction)syslog_syslog, METH_VARARGS, syslog_syslog__doc__}, + {"syslog", _PyCFunction_CAST(syslog_syslog), METH_FASTCALL, syslog_syslog__doc__}, static PyObject * syslog_syslog_impl(PyObject *module, int group_left_1, int priority, const char *message); static PyObject * -syslog_syslog(PyObject *module, PyObject *args) +syslog_syslog(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int group_left_1 = 0; int priority = LOG_INFO; const char *message; - switch (PyTuple_GET_SIZE(args)) { - case 1: - if (!PyArg_ParseTuple(args, "s:syslog", &message)) { - goto exit; - } - break; - case 2: - if (!PyArg_ParseTuple(args, "is:syslog", &priority, &message)) { - goto exit; - } - group_left_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "syslog.syslog requires 1 to 2 arguments"); + if (nargs < 1 || nargs > 2) { + PyErr_SetString(PyExc_TypeError, "syslog.syslog requires 1 to 2 arguments"); + goto exit; + } + if (nargs >= 2) { + priority = PyLong_AsInt(args[0]); + if (priority == -1 && PyErr_Occurred()) { goto exit; + } + group_left_1 = 1; + } + if (!PyUnicode_Check(args[nargs - 1])) { + _PyArg_BadArgument("syslog", "argument", "str", args[nargs - 1]); + goto exit; + } + Py_ssize_t message_length; + message = PyUnicode_AsUTF8AndSize(args[nargs - 1], &message_length); + if (message == NULL) { + goto exit; + } + if (strlen(message) != (size_t)message_length) { + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; } Py_BEGIN_CRITICAL_SECTION(module); return_value = syslog_syslog_impl(module, group_left_1, priority, message); @@ -265,4 +273,4 @@ syslog_LOG_UPTO(PyObject *module, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=f92ac9948fa6131e input=a9049054013a1b77]*/ +/*[clinic end generated code: output=ab818466dcdbbe59 input=a9049054013a1b77]*/ diff --git a/Tools/clinic/libclinic/clanguage.py b/Tools/clinic/libclinic/clanguage.py index 1581a19a4fd78ab..0f21df9da837a24 100644 --- a/Tools/clinic/libclinic/clanguage.py +++ b/Tools/clinic/libclinic/clanguage.py @@ -1,18 +1,17 @@ from __future__ import annotations import itertools import textwrap -from typing import TYPE_CHECKING, Literal, Final +from typing import TYPE_CHECKING, Final from operator import attrgetter from collections.abc import Iterable import libclinic.cpp -from libclinic import ( - unspecified, fail, Sentinels, VersionTuple) -from libclinic.codegen import CRenderData, TemplateDict, CodeGen +from libclinic import unspecified, fail, VersionTuple +from libclinic.codegen import CRenderData, CodeGen from libclinic.language import Language from libclinic.function import ( - Module, Class, Function, Parameter, ParamTuple, - permute_optional_groups, + Module, Class, Function, Parameter, + group_to_variable_name, GETTER, SETTER, METHOD_INIT) from libclinic.converters import self_converter from libclinic.parse_args import ParseArgsCodeGen @@ -20,20 +19,6 @@ from libclinic.app import Clinic -def count_required(subset: ParamTuple) -> int: - """Return the number of arguments which cannot be omitted. - - A parameter in an optional group is passed together with its group, - so only trailing parameters with a default value can be omitted. - """ - count = len(subset) - for p in reversed(subset): - if p.group or not p.is_optional(): - break - count -= 1 - return count - - def c_id(name: str) -> str: if len(name) == 1 and ord(name) < 256: if name.isalnum(): @@ -260,145 +245,6 @@ def output_templates( args = ParseArgsCodeGen(f, codegen) return args.parse_args(self) - @staticmethod - def group_to_variable_name(group: int) -> str: - adjective = "left_" if group < 0 else "right_" - return "group_" + adjective + str(abs(group)) - - def render_option_group_parsing( - self, - f: Function, - template_dict: TemplateDict, - limited_capi: bool, - ) -> None: - # positional only, grouped, optional arguments! - # can be optional on the left or right. - # here's an example: - # - # [ [ [ A1 A2 ] B1 B2 B3 ] C1 C2 ] D1 D2 D3 [ E1 E2 E3 [ F1 F2 F3 ] ] - # - # Here group D are required, and all other groups are optional. - # (Group D's "group" is actually None.) - # We can figure out which sets of arguments we have based on - # how many arguments are in the tuple. - # - # Note that you need to count up on both sides. For example, - # you could have groups C+D, or C+D+E, or C+D+E+F. - # - # What if the number of arguments leads us to an ambiguous result? - # Clinic prefers groups on the left. So in the above example, - # five arguments would map to B+C, not C+D. - # - # A nested group can only be omitted together with the group - # containing it, but groups on the same level, like G and H in - # - # [ G1 G2 ] [ H1 ] I1 I2 - # - # can be omitted independently of each other. - - out = [] - parameters = list(f.parameters.values()) - if isinstance(parameters[0].converter, self_converter): - del parameters[0] - - # Groups are collected into chains of nested groups. A group which - # is not nested in the preceding one starts a new chain. - group: list[Parameter] | None = None - left: list[list[list[Parameter]]] = [] - right: list[list[list[Parameter]]] = [] - required: list[Parameter] = [] - last: int | Literal[Sentinels.unspecified] = unspecified - last_depth = 0 - - for p in parameters: - group_id = p.group - if group_id != last: - last = group_id - group = [] - if group_id == 0: - group = required - else: - chains = left if group_id < 0 else right - nested = ((p.group_depth < last_depth) if group_id < 0 - else (p.group_depth > last_depth)) - if chains and nested: - chains[-1].append(group) - else: - chains.append([group]) - last_depth = p.group_depth - assert group is not None - group.append(p) - - # Map the number of arguments to the subset which accepts it. - subsets: dict[int, ParamTuple] = {} - for subset in permute_optional_groups(left, required, right): - for count in range(count_required(subset), len(subset) + 1): - if count in subsets: - fail(f"Function {f.full_name!r} has an ambiguous group " - f"configuration: a call with {count} argument(s) " - f"can be parsed in more than one way.") - subsets[count] = subset - - if limited_capi: - nargs = 'PyTuple_Size(args)' - else: - nargs = 'PyTuple_GET_SIZE(args)' - out.append(f"switch ({nargs}) {{\n") - for count, subset in sorted(subsets.items()): - if count < len(subset): - # The omitted parameters are parsed by the following case. - out.append(f" case {count}:\n") - continue - - if count == 0: - out.append(""" case 0: - break; -""") - continue - - # A set would eliminate duplicates too, but the iteration - # order of small negative integers depends on the platform. - group_ids = dict.fromkeys(p.group for p in subset) - d: dict[str, str | int] = {} - d['count'] = count - d['name'] = f.name - format_units = [p.converter.format_unit for p in subset] - n_required = count_required(subset) - if n_required < count: - format_units.insert(n_required, '|') - d['format_units'] = "".join(format_units) - - parse_arguments: list[str] = [] - for p in subset: - p.converter.parse_argument(parse_arguments) - d['parse_arguments'] = ", ".join(parse_arguments) - - group_ids.pop(0, None) - lines = "\n".join([ - self.group_to_variable_name(g) + " = 1;" - for g in group_ids - ]) - - s = """\ - case {count}: - if (!PyArg_ParseTuple(args, "{format_units}:{name}", {parse_arguments})) {{ - goto exit; - }} - {group_booleans} - break; -""" - s = libclinic.linear_format(s, group_booleans=lines) - s = s.format_map(d) - out.append(s) - - out.append(" default:\n") - s = ' PyErr_SetString(PyExc_TypeError, "{} requires {} to {} arguments");\n' - out.append(s.format(f.full_name, min(subsets), max(subsets))) - out.append(' goto exit;\n') - out.append("}") - - template_dict['option_group_parsing'] = libclinic.format_escape("".join(out)) - def render_function( self, clinic: Clinic, @@ -451,7 +297,7 @@ def render_function( if last_group != group: last_group = group if group: - group_name = self.group_to_variable_name(group) + group_name = group_to_variable_name(group) data.impl_arguments.append(group_name) data.declarations.append("int " + group_name + " = 0;") data.impl_parameters.append("int " + group_name) @@ -534,16 +380,9 @@ def render_function( template_dict['unpack_min'] = str(unpack_min) template_dict['unpack_max'] = str(unpack_max) - if has_option_groups: - self.render_option_group_parsing(f, template_dict, - limited_capi=codegen.limited_capi) - # buffers, not destination for name, destination in clinic.destination_buffers.items(): template = templates[name] - if has_option_groups: - template = libclinic.linear_format(template, - option_group_parsing=template_dict['option_group_parsing']) template = libclinic.linear_format(template, declarations=template_dict['declarations'], return_conversion=template_dict['return_conversion'], diff --git a/Tools/clinic/libclinic/function.py b/Tools/clinic/libclinic/function.py index 325633eb010608f..81494e7881d7734 100644 --- a/Tools/clinic/libclinic/function.py +++ b/Tools/clinic/libclinic/function.py @@ -270,6 +270,25 @@ def render_docstring(self) -> str: ParamTuple = tuple["Parameter", ...] +def group_to_variable_name(group: int) -> str: + adjective = "left_" if group < 0 else "right_" + return "group_" + adjective + str(abs(group)) + + +def count_required(subset: ParamTuple) -> int: + """Return the number of arguments which cannot be omitted. + + A parameter in an optional group is passed together with its group, + so only trailing parameters with a default value can be omitted. + """ + count = len(subset) + for p in reversed(subset): + if p.group or not p.is_optional(): + break + count -= 1 + return count + + def permute_left_option_groups( l: Sequence[Iterable[Parameter]] ) -> Iterator[ParamTuple]: diff --git a/Tools/clinic/libclinic/parse_args.py b/Tools/clinic/libclinic/parse_args.py index 2ad1e94ea2b4c79..524bbdbab5372ed 100644 --- a/Tools/clinic/libclinic/parse_args.py +++ b/Tools/clinic/libclinic/parse_args.py @@ -1,10 +1,11 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Final +from typing import TYPE_CHECKING, Final, Literal import libclinic -from libclinic import fail, warn +from libclinic import fail, warn, unspecified, Sentinels from libclinic.function import ( - Function, Parameter, + Function, Parameter, ParamTuple, + count_required, group_to_variable_name, permute_optional_groups, GETTER, SETTER, METHOD_NEW) from libclinic.converter import CConverter from libclinic.converters import ( @@ -462,15 +463,314 @@ def parse_one_arg(self) -> None: parser_code = libclinic.normalize_snippet(parsearg, indent=4) self.parser_body(parser_code) + def option_group_subsets(self) -> dict[int, ParamTuple]: + # positional only, grouped, optional arguments! + # can be optional on the left or right. + # here's an example: + # + # [ [ [ A1 A2 ] B1 B2 B3 ] C1 C2 ] D1 D2 D3 [ E1 E2 E3 [ F1 F2 F3 ] ] + # + # Here group D are required, and all other groups are optional. + # (Group D's "group" is actually None.) + # We can figure out which sets of arguments we have based on + # how many arguments are in the tuple. + # + # Note that you need to count up on both sides. For example, + # you could have groups C+D, or C+D+E, or C+D+E+F. + # + # What if the number of arguments leads us to an ambiguous result? + # Clinic prefers groups on the left. So in the above example, + # five arguments would map to B+C, not C+D. + # + # A nested group can only be omitted together with the group + # containing it, but groups on the same level, like G and H in + # + # [ G1 G2 ] [ H1 ] I1 I2 + # + # can be omitted independently of each other. + + # Groups are collected into chains of nested groups. A group which + # is not nested in the preceding one starts a new chain. + group: list[Parameter] | None = None + left: list[list[list[Parameter]]] = [] + right: list[list[list[Parameter]]] = [] + required: list[Parameter] = [] + last: int | Literal[Sentinels.unspecified] = unspecified + last_depth = 0 + + for p in self.parameters: + group_id = p.group + if group_id != last: + last = group_id + group = [] + if group_id == 0: + group = required + else: + chains = left if group_id < 0 else right + nested = ((p.group_depth < last_depth) if group_id < 0 + else (p.group_depth > last_depth)) + if chains and nested: + chains[-1].append(group) + else: + chains.append([group]) + last_depth = p.group_depth + assert group is not None + group.append(p) + + # Map the number of arguments to the subset which accepts it. + subsets: dict[int, ParamTuple] = {} + for subset in permute_optional_groups(left, required, right): + for count in range(count_required(subset), len(subset) + 1): + if count in subsets: + fail(f"Function {self.func.full_name!r} has an ambiguous " + f"group configuration: a call with {count} " + f"argument(s) can be parsed in more than one way.") + subsets[count] = subset + return subsets + def parse_option_groups(self) -> None: # positional parameters with option groups - # (we have to generate lots of PyArg_ParseTuple calls - # in a big switch statement) + # (which groups are passed is determined by the number of arguments) + + nargs, argname_fmt = self.select_positional_convention() + # With the stack convention "nargs" is already a parameter. + size_expr = None if self.fastcall else nargs + + subsets = self.option_group_subsets() + parser_code = self.render_option_groups(subsets, argname_fmt, size_expr) + if parser_code is None: + # The code of some converter cannot be inlined, so the + # arguments of every combination of groups are parsed at once. + parser_code = self.render_option_groups_parse_tuple(subsets) + self.parser_body(*parser_code) - self.flags = "METH_VARARGS" - self.parser_prototype = PARSER_PROTOTYPE_VARARGS - parser_code = ' {option_group_parsing}' - self.parser_body(parser_code) + def render_option_groups( + self, + subsets: dict[int, ParamTuple], + argname_fmt: str, + size_expr: str | None, + ) -> list[str] | None: + """Return the code which parses the arguments of all groups. + + Every parameter is parsed once, in a block guarded by the number of + arguments. Return None if the code of some converter cannot be + inlined. + """ + # Split the parameters into the groups, in the order in which + # they are passed. + groups: list[tuple[int, list[Parameter]]] = [] + for p in self.parameters: + if not groups or groups[-1][0] != p.group: + groups.append((p.group, [])) + groups[-1][1].append(p) + + indices, shifting = self.render_option_group_indices(subsets, groups) + + parser_code = [] + if size_expr is not None: + parser_code.append(libclinic.normalize_snippet( + f"Py_ssize_t nargs = {size_expr};", indent=4)) + if shifting: + parser_code.append(libclinic.normalize_snippet( + "Py_ssize_t offset = 0;", indent=4)) + parser_code.append(self.render_option_group_check(subsets)) + + has_optional = False + for group_id, params in groups: + body = [] + for p in params: + index_expr = indices[p.name] + if index_expr.isdigit(): + displayname = p.get_displayname(int(index_expr) + 1) + else: + # The position of the argument differs between the calls. + displayname = p.get_displayname(0) + parsearg = p.converter.parse_arg(argname_fmt % index_expr, + displayname, + limited_capi=self.limited_capi) + if parsearg is None: + return None + if not group_id and (has_optional or p.is_optional()): + # Such parameter is omitted on its own, and nothing + # can follow it, so the rest is simply skipped. + has_optional = True + body.append(libclinic.normalize_snippet(""" + if (nargs <= %s) {{ + goto skip_optional; + }} + """, indent=4) % index_expr) + body.append(libclinic.normalize_snippet(parsearg, indent=4)) + + if not group_id: + parser_code.extend(body) + continue + + if group_id in shifting: + # The arguments of this group shift the following ones. + body.append(libclinic.normalize_snippet( + f"offset += {len(params)};", indent=4)) + body.append(libclinic.normalize_snippet( + f"{group_to_variable_name(group_id)} = 1;", indent=4)) + condition = self.render_option_group_condition(subsets, group_id) + parser_code.append(libclinic.normalize_snippet( + f"if ({condition}) {{{{", indent=4)) + parser_code.extend(libclinic.normalize_snippet(line, indent=8) + for line in body) + parser_code.append(libclinic.normalize_snippet("}}", indent=4)) + + if has_optional: + parser_code.append("skip_optional:") + return parser_code + + @staticmethod + def render_option_group_indices( + subsets: dict[int, ParamTuple], + groups: list[tuple[int, list[Parameter]]], + ) -> tuple[dict[str, str], set[int]]: + """Return the index of the argument of every parameter, as C code, + and the groups which have to add their size to "offset". + + A group which is not passed shifts the following arguments. Their + index can still be fixed if it is counted from the end; otherwise it + is counted at run time, in "offset". + """ + forward: dict[str, set[int]] = {} + backward: dict[str, set[int]] = {} + for count, subset in subsets.items(): + for i, p in enumerate(subset[:count]): + forward.setdefault(p.name, set()).add(i) + backward.setdefault(p.name, set()).add(count - i) + # A parameter with a default value can be omitted on its own, so + # its index from the end is not fixed. + for group_id, params in groups: + if not group_id: + for p in params: + if p.is_optional(): + backward.pop(p.name) + + def counted_at_run_time(p: Parameter) -> bool: + return (len(forward[p.name]) != 1 + and len(backward.get(p.name, ())) != 1) + + # A group adds its size to "offset" if it shifts an argument + # which is counted at run time. + shifting: set[int] = set() + seen: list[int] = [] + for group_id, params in groups: + if any(counted_at_run_time(p) for p in params): + shifting.update(g for g in seen if g) + seen.append(group_id) + + indices = {} + # The number of the parameters before the current one, and how many + # of them are counted in "offset". + pos = 0 + in_offset = 0 + for group_id, params in groups: + for i, p in enumerate(params): + if not counted_at_run_time(p): + if len(forward[p.name]) == 1: + indices[p.name] = str(min(forward[p.name])) + else: + indices[p.name] = f"nargs - {min(backward[p.name])}" + else: + index = pos + i - in_offset + indices[p.name] = ("offset" if index == 0 + else f"offset + {index}") + pos += len(params) + if group_id in shifting: + in_offset += len(params) + return indices, shifting + + @staticmethod + def render_option_group_condition( + subsets: dict[int, ParamTuple], + group_id: int, + ) -> str: + """Return the condition on which the group is passed.""" + counts = sorted(count for count, subset in subsets.items() + if any(p.group == group_id for p in subset)) + if counts == list(range(counts[0], max(subsets) + 1)): + return f"nargs >= {counts[0]}" + return " || ".join(f"nargs == {count}" for count in counts) + + def render_option_group_check( + self, + subsets: dict[int, ParamTuple], + ) -> str: + """Return the code which rejects an unsupported number of arguments.""" + error = ('PyErr_SetString(PyExc_TypeError, "%s requires %d to %d ' + 'arguments");' % (self.func.full_name, min(subsets), + max(subsets))) + counts = sorted(subsets) + if counts == list(range(counts[0], counts[-1] + 1)): + tests = [f"nargs > {counts[-1]}"] + if counts[0]: + tests.insert(0, f"nargs < {counts[0]}") + lines = [ + f"if ({' || '.join(tests)}) {{{{", + f" {error}", + " goto exit;", + "}}", + ] + else: + # Some numbers of arguments in between are not supported. + lines = ["switch (nargs) {{"] + lines += [f" case {count}:" for count in counts] + lines += [ + " break;", + " default:", + f" {error}", + " goto exit;", + "}}", + ] + return libclinic.normalize_snippet("\n".join(lines), indent=4) + + def render_option_groups_parse_tuple( + self, + subsets: dict[int, ParamTuple], + ) -> list[str]: + """Return the code which parses the arguments of every group at once.""" + parse_call = self.render_parse_all_arguments() + # The convention can have changed, so ask for it again. + size_expr, _ = self.select_positional_convention() + parser_code = [libclinic.normalize_snippet(f"switch ({size_expr}) {{{{", + indent=4)] + for count, subset in sorted(subsets.items()): + parser_code.append(f" case {count}:") + if count != len(subset): + # The omitted parameters are parsed by the following case. + continue + if count: + format_units = [p.converter.format_unit for p in subset] + n_required = count_required(subset) + if n_required < count: + format_units.insert(n_required, '|') + parse_arguments: list[str] = [] + for p in subset: + p.converter.parse_argument(parse_arguments) + parser_code.append(libclinic.normalize_snippet(""" + if (!%s"%s:%s", %s)) {{ + goto exit; + }} + """, indent=12) % (parse_call, "".join(format_units), + self.func.name, + ", ".join(parse_arguments))) + # A set would eliminate duplicates too, but the iteration + # order of small negative integers depends on the platform. + group_ids = dict.fromkeys(p.group for p in subset) + group_ids.pop(0, None) + for group_id in group_ids: + parser_code.append( + f" {group_to_variable_name(group_id)} = 1;") + parser_code.append(" break;") + parser_code.append(" default:") + parser_code.append( + ' PyErr_SetString(PyExc_TypeError, "%s requires %d to %d arguments");' + % (self.func.full_name, min(subsets), max(subsets))) + parser_code.append(" goto exit;") + parser_code.append(" }}") + return parser_code def _parse_vararg(self) -> str: assert self.varpos is not None @@ -488,27 +788,45 @@ def _parse_kwarg(self) -> str: assert isinstance(c, libclinic.converters.VarKeywordCConverter) return c.parse_var_keyword() - def parse_pos_only(self) -> None: - if self.fastcall: - # positional-only, but no option groups - # we only need one call to _PyArg_ParseStack + def select_positional_convention(self) -> tuple[str, str]: + """Select the calling convention of a positional-only function. + Set the method flags and the prototype, and return the expression of + the number of arguments and the format of an argument expression. + """ + if self.fastcall: self.flags = "METH_FASTCALL" self.parser_prototype = PARSER_PROTOTYPE_FASTCALL - nargs = 'nargs' - argname_fmt = 'args[%d]' - else: - # positional-only, but no option groups - # we only need one call to PyArg_ParseTuple + return 'nargs', 'args[%s]' - self.flags = "METH_VARARGS" - self.parser_prototype = PARSER_PROTOTYPE_VARARGS - if self.limited_capi: - nargs = 'PyTuple_Size(args)' - argname_fmt = 'PyTuple_GetItem(args, %d)' - else: - nargs = 'PyTuple_GET_SIZE(args)' - argname_fmt = 'PyTuple_GET_ITEM(args, %d)' + self.flags = "METH_VARARGS" + self.parser_prototype = PARSER_PROTOTYPE_VARARGS + if self.limited_capi: + return 'PyTuple_Size(args)', 'PyTuple_GetItem(args, %s)' + return 'PyTuple_GET_SIZE(args)', 'PyTuple_GET_ITEM(args, %s)' + + def render_parse_all_arguments(self) -> str: + """Return the beginning of the call which parses all arguments. + + Fall back to the tuple convention if the stack one cannot be used. + """ + for p in self.parameters: + p.converter.use_converter() + if self.limited_capi: + # _PyArg_ParseStack() is not part of the limited C API. + self.fastcall = False + if self.fastcall: + self.codegen.add_include('pycore_modsupport.h', + '_PyArg_ParseStack()') + return '_PyArg_ParseStack(args, nargs, ' + self.flags = "METH_VARARGS" + self.parser_prototype = PARSER_PROTOTYPE_VARARGS + return 'PyArg_ParseTuple(args, ' + + def parse_pos_only(self) -> None: + # positional-only, but no option groups: we only need one call + # to _PyArg_ParseStack or PyArg_ParseTuple + nargs, argname_fmt = self.select_positional_convention() parser_code = [] max_args = NO_VARARG if self.varpos else self.max_pos @@ -586,29 +904,13 @@ def parse_pos_only(self) -> None: elif self.var_keyword: parser_code.append(libclinic.normalize_snippet(self._parse_kwarg(), indent=4)) else: - for parameter in self.parameters: - parameter.converter.use_converter() - - if self.limited_capi: - self.fastcall = False - if self.fastcall: - self.codegen.add_include('pycore_modsupport.h', - '_PyArg_ParseStack()') - parser_code = [libclinic.normalize_snippet(""" - if (!_PyArg_ParseStack(args, nargs, "{format_units}:{name}", - {parse_arguments})) {{ - goto exit; - }} - """, indent=4)] - else: - self.flags = "METH_VARARGS" - self.parser_prototype = PARSER_PROTOTYPE_VARARGS - parser_code = [libclinic.normalize_snippet(""" - if (!PyArg_ParseTuple(args, "{format_units}:{name}", - {parse_arguments})) {{ - goto exit; - }} - """, indent=4)] + parse_call = self.render_parse_all_arguments() + parser_code = [libclinic.normalize_snippet(""" + if (!%s"{format_units}:{name}", + {parse_arguments})) {{ + goto exit; + }} + """, indent=4) % parse_call] self.parser_body(*parser_code) def parse_var_keyword(self) -> None: