From 964535a13a45cc962a2e35bfaba0fb3867917fd6 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 27 Sep 2026 18:56:45 +0300 Subject: [PATCH 1/5] gh-155496: Use Argument Clinic for the getpath module (GH-158132) This also fixes a use after free in isxfile() on Windows: the path was freed before being passed to CompareStringOrdinal(). --- Modules/clinic/getpath.c.h | 380 +++++++++++++++++++++++++++++++++++++ Modules/getpath.c | 313 +++++++++++++++++------------- 2 files changed, 556 insertions(+), 137 deletions(-) create mode 100644 Modules/clinic/getpath.c.h diff --git a/Modules/clinic/getpath.c.h b/Modules/clinic/getpath.c.h new file mode 100644 index 00000000000000..54ab0240e4482c --- /dev/null +++ b/Modules/clinic/getpath.c.h @@ -0,0 +1,380 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +#include "pycore_modsupport.h" // _PyArg_BadArgument() + +PyDoc_STRVAR(getpath_abspath__doc__, +"abspath($module, path, /)\n" +"--\n" +"\n" +"Return the absolute path."); + +#define GETPATH_ABSPATH_METHODDEF \ + {"abspath", (PyCFunction)getpath_abspath, METH_O, getpath_abspath__doc__}, + +static PyObject * +getpath_abspath_impl(PyObject *module, const wchar_t *path); + +static PyObject * +getpath_abspath(PyObject *module, PyObject *arg) +{ + PyObject *return_value = NULL; + const wchar_t *path = NULL; + + if (!PyUnicode_Check(arg)) { + _PyArg_BadArgument("abspath", "argument", "str", arg); + goto exit; + } + path = PyUnicode_AsWideCharString(arg, NULL); + if (path == NULL) { + goto exit; + } + return_value = getpath_abspath_impl(module, path); + +exit: + /* Cleanup for path */ + PyMem_Free((void *)path); + + return return_value; +} + +PyDoc_STRVAR(getpath_basename__doc__, +"basename($module, path, /)\n" +"--\n" +"\n" +"Return the final component of the path."); + +#define GETPATH_BASENAME_METHODDEF \ + {"basename", (PyCFunction)getpath_basename, METH_O, getpath_basename__doc__}, + +static PyObject * +getpath_basename_impl(PyObject *module, PyObject *path); + +static PyObject * +getpath_basename(PyObject *module, PyObject *arg) +{ + PyObject *return_value = NULL; + PyObject *path; + + if (!PyUnicode_Check(arg)) { + _PyArg_BadArgument("basename", "argument", "str", arg); + goto exit; + } + path = arg; + return_value = getpath_basename_impl(module, path); + +exit: + return return_value; +} + +PyDoc_STRVAR(getpath_dirname__doc__, +"dirname($module, path, /)\n" +"--\n" +"\n" +"Return the directory component of the path."); + +#define GETPATH_DIRNAME_METHODDEF \ + {"dirname", (PyCFunction)getpath_dirname, METH_O, getpath_dirname__doc__}, + +static PyObject * +getpath_dirname_impl(PyObject *module, PyObject *path); + +static PyObject * +getpath_dirname(PyObject *module, PyObject *arg) +{ + PyObject *return_value = NULL; + PyObject *path; + + if (!PyUnicode_Check(arg)) { + _PyArg_BadArgument("dirname", "argument", "str", arg); + goto exit; + } + path = arg; + return_value = getpath_dirname_impl(module, path); + +exit: + return return_value; +} + +PyDoc_STRVAR(getpath_isabs__doc__, +"isabs($module, path, /)\n" +"--\n" +"\n" +"Return True if the path is absolute."); + +#define GETPATH_ISABS_METHODDEF \ + {"isabs", (PyCFunction)getpath_isabs, METH_O, getpath_isabs__doc__}, + +static int +getpath_isabs_impl(PyObject *module, const wchar_t *path); + +static PyObject * +getpath_isabs(PyObject *module, PyObject *arg) +{ + PyObject *return_value = NULL; + const wchar_t *path = NULL; + int _return_value; + + if (!PyUnicode_Check(arg)) { + _PyArg_BadArgument("isabs", "argument", "str", arg); + goto exit; + } + path = PyUnicode_AsWideCharString(arg, NULL); + if (path == NULL) { + goto exit; + } + _return_value = getpath_isabs_impl(module, path); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyBool_FromLong((long)_return_value); + +exit: + /* Cleanup for path */ + PyMem_Free((void *)path); + + return return_value; +} + +PyDoc_STRVAR(getpath_hassuffix__doc__, +"hassuffix($module, path, suffix, /)\n" +"--\n" +"\n" +"Return True if the path ends with the suffix, ignoring the case."); + +#define GETPATH_HASSUFFIX_METHODDEF \ + {"hassuffix", _PyCFunction_CAST(getpath_hassuffix), METH_FASTCALL, getpath_hassuffix__doc__}, + +static int +getpath_hassuffix_impl(PyObject *module, PyObject *pathobj, + PyObject *suffixobj); + +static PyObject * +getpath_hassuffix(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *pathobj; + PyObject *suffixobj; + int _return_value; + + if (!_PyArg_CheckPositional("hassuffix", nargs, 2, 2)) { + goto exit; + } + if (!PyUnicode_Check(args[0])) { + _PyArg_BadArgument("hassuffix", "argument 1", "str", args[0]); + goto exit; + } + pathobj = args[0]; + if (!PyUnicode_Check(args[1])) { + _PyArg_BadArgument("hassuffix", "argument 2", "str", args[1]); + goto exit; + } + suffixobj = args[1]; + _return_value = getpath_hassuffix_impl(module, pathobj, suffixobj); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyBool_FromLong((long)_return_value); + +exit: + return return_value; +} + +PyDoc_STRVAR(getpath_isdir__doc__, +"isdir($module, path, /)\n" +"--\n" +"\n" +"Return True if the path is a directory."); + +#define GETPATH_ISDIR_METHODDEF \ + {"isdir", (PyCFunction)getpath_isdir, METH_O, getpath_isdir__doc__}, + +static int +getpath_isdir_impl(PyObject *module, const wchar_t *path); + +static PyObject * +getpath_isdir(PyObject *module, PyObject *arg) +{ + PyObject *return_value = NULL; + const wchar_t *path = NULL; + int _return_value; + + if (!PyUnicode_Check(arg)) { + _PyArg_BadArgument("isdir", "argument", "str", arg); + goto exit; + } + path = PyUnicode_AsWideCharString(arg, NULL); + if (path == NULL) { + goto exit; + } + _return_value = getpath_isdir_impl(module, path); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyBool_FromLong((long)_return_value); + +exit: + /* Cleanup for path */ + PyMem_Free((void *)path); + + return return_value; +} + +PyDoc_STRVAR(getpath_isfile__doc__, +"isfile($module, path, /)\n" +"--\n" +"\n" +"Return True if the path is a regular file."); + +#define GETPATH_ISFILE_METHODDEF \ + {"isfile", (PyCFunction)getpath_isfile, METH_O, getpath_isfile__doc__}, + +static int +getpath_isfile_impl(PyObject *module, PyObject *pathobj); + +static PyObject * +getpath_isfile(PyObject *module, PyObject *arg) +{ + PyObject *return_value = NULL; + PyObject *pathobj; + int _return_value; + + if (!PyUnicode_Check(arg)) { + _PyArg_BadArgument("isfile", "argument", "str", arg); + goto exit; + } + pathobj = arg; + _return_value = getpath_isfile_impl(module, pathobj); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyBool_FromLong((long)_return_value); + +exit: + return return_value; +} + +PyDoc_STRVAR(getpath_isxfile__doc__, +"isxfile($module, path, /)\n" +"--\n" +"\n" +"Return True if the path is an executable file."); + +#define GETPATH_ISXFILE_METHODDEF \ + {"isxfile", (PyCFunction)getpath_isxfile, METH_O, getpath_isxfile__doc__}, + +static int +getpath_isxfile_impl(PyObject *module, PyObject *pathobj); + +static PyObject * +getpath_isxfile(PyObject *module, PyObject *arg) +{ + PyObject *return_value = NULL; + PyObject *pathobj; + int _return_value; + + if (!PyUnicode_Check(arg)) { + _PyArg_BadArgument("isxfile", "argument", "str", arg); + goto exit; + } + pathobj = arg; + _return_value = getpath_isxfile_impl(module, pathobj); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyBool_FromLong((long)_return_value); + +exit: + return return_value; +} + +PyDoc_STRVAR(getpath_joinpath__doc__, +"joinpath($module, /, *args)\n" +"--\n" +"\n" +"Join the path components."); + +#define GETPATH_JOINPATH_METHODDEF \ + {"joinpath", _PyCFunction_CAST(getpath_joinpath), METH_FASTCALL, getpath_joinpath__doc__}, + +static PyObject * +getpath_joinpath_impl(PyObject *module, PyObject *args); + +static PyObject * +getpath_joinpath(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *__clinic_args = NULL; + + __clinic_args = PyTuple_FromArray(args, nargs); + if (__clinic_args == NULL) { + goto exit; + } + return_value = getpath_joinpath_impl(module, __clinic_args); + +exit: + /* Cleanup for args */ + Py_XDECREF(__clinic_args); + + return return_value; +} + +PyDoc_STRVAR(getpath_readlines__doc__, +"readlines($module, path, /)\n" +"--\n" +"\n" +"Return the lines of the file."); + +#define GETPATH_READLINES_METHODDEF \ + {"readlines", (PyCFunction)getpath_readlines, METH_O, getpath_readlines__doc__}, + +static PyObject * +getpath_readlines_impl(PyObject *module, PyObject *pathobj); + +static PyObject * +getpath_readlines(PyObject *module, PyObject *arg) +{ + PyObject *return_value = NULL; + PyObject *pathobj; + + if (!PyUnicode_Check(arg)) { + _PyArg_BadArgument("readlines", "argument", "str", arg); + goto exit; + } + pathobj = arg; + return_value = getpath_readlines_impl(module, pathobj); + +exit: + return return_value; +} + +PyDoc_STRVAR(getpath_realpath__doc__, +"realpath($module, path, /)\n" +"--\n" +"\n" +"Resolve a symlinked file."); + +#define GETPATH_REALPATH_METHODDEF \ + {"realpath", (PyCFunction)getpath_realpath, METH_O, getpath_realpath__doc__}, + +static PyObject * +getpath_realpath_impl(PyObject *module, PyObject *pathobj); + +static PyObject * +getpath_realpath(PyObject *module, PyObject *arg) +{ + PyObject *return_value = NULL; + PyObject *pathobj; + + if (!PyUnicode_Check(arg)) { + _PyArg_BadArgument("realpath", "argument", "str", arg); + goto exit; + } + pathobj = arg; + return_value = getpath_realpath_impl(module, pathobj); + +exit: + return return_value; +} +/*[clinic end generated code: output=74266cdd2d87e28d input=a9049054013a1b77]*/ diff --git a/Modules/getpath.c b/Modules/getpath.c index ed41536acbcc81..48047de0c12af2 100644 --- a/Modules/getpath.c +++ b/Modules/getpath.c @@ -58,40 +58,52 @@ #endif +/*[clinic input] +module getpath +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=b425aa3ea7292100]*/ + +#include "clinic/getpath.c.h" + /* HELPER FUNCTIONS for getpath.py */ +/*[clinic input] +getpath.abspath + + path: Py_UNICODE + / + +Return the absolute path. +[clinic start generated code]*/ + static PyObject * -getpath_abspath(PyObject *Py_UNUSED(self), PyObject *args) +getpath_abspath_impl(PyObject *module, const wchar_t *path) +/*[clinic end generated code: output=5009336e32e75b9b input=0fd554ce535744f2]*/ { - PyObject *r = NULL; - PyObject *pathobj; - wchar_t *path; - if (!PyArg_ParseTuple(args, "U", &pathobj)) { + wchar_t *abs; + if (_Py_abspath(_Py_normpath((wchar_t *)path, -1), &abs) < 0 || abs == NULL) { + PyErr_SetString(PyExc_OSError, "failed to make path absolute"); return NULL; } - Py_ssize_t len; - path = PyUnicode_AsWideCharString(pathobj, &len); - if (path) { - wchar_t *abs; - if (_Py_abspath((const wchar_t *)_Py_normpath(path, -1), &abs) == 0 && abs) { - r = PyUnicode_FromWideChar(abs, -1); - PyMem_RawFree((void *)abs); - } else { - PyErr_SetString(PyExc_OSError, "failed to make path absolute"); - } - PyMem_Free((void *)path); - } + PyObject *r = PyUnicode_FromWideChar(abs, -1); + PyMem_RawFree((void *)abs); return r; } +/*[clinic input] +getpath.basename + + path: unicode + / + +Return the final component of the path. +[clinic start generated code]*/ + static PyObject * -getpath_basename(PyObject *Py_UNUSED(self), PyObject *args) +getpath_basename_impl(PyObject *module, PyObject *path) +/*[clinic end generated code: output=d383d3b34842236e input=0de5b71fc78bbad8]*/ { - PyObject *path; - if (!PyArg_ParseTuple(args, "U", &path)) { - return NULL; - } Py_ssize_t end = PyUnicode_GET_LENGTH(path); Py_ssize_t pos = PyUnicode_FindChar(path, SEP, 0, end, -1); if (pos < 0) { @@ -101,13 +113,19 @@ getpath_basename(PyObject *Py_UNUSED(self), PyObject *args) } +/*[clinic input] +getpath.dirname + + path: unicode + / + +Return the directory component of the path. +[clinic start generated code]*/ + static PyObject * -getpath_dirname(PyObject *Py_UNUSED(self), PyObject *args) +getpath_dirname_impl(PyObject *module, PyObject *path) +/*[clinic end generated code: output=6887a025f5f6784c input=0c33269fe28957fb]*/ { - PyObject *path; - if (!PyArg_ParseTuple(args, "U", &path)) { - return NULL; - } Py_ssize_t end = PyUnicode_GET_LENGTH(path); Py_ssize_t pos = PyUnicode_FindChar(path, SEP, 0, end, -1); if (pos < 0) { @@ -117,51 +135,51 @@ getpath_dirname(PyObject *Py_UNUSED(self), PyObject *args) } -static PyObject * -getpath_isabs(PyObject *Py_UNUSED(self), PyObject *args) +/*[clinic input] +getpath.isabs -> bool + + path: Py_UNICODE + / + +Return True if the path is absolute. +[clinic start generated code]*/ + +static int +getpath_isabs_impl(PyObject *module, const wchar_t *path) +/*[clinic end generated code: output=4659b9e6f088c2ca input=04931a206cdd77f6]*/ { - PyObject *r = NULL; - PyObject *pathobj; - const wchar_t *path; - if (!PyArg_ParseTuple(args, "U", &pathobj)) { - return NULL; - } - path = PyUnicode_AsWideCharString(pathobj, NULL); - if (path) { - r = _Py_isabs(path) ? Py_True : Py_False; - PyMem_Free((void *)path); - } - return Py_XNewRef(r); + return _Py_isabs(path); } -static PyObject * -getpath_hassuffix(PyObject *Py_UNUSED(self), PyObject *args) +/*[clinic input] +getpath.hassuffix -> bool + + path as pathobj: unicode + suffix as suffixobj: unicode + / + +Return True if the path ends with the suffix, ignoring the case. +[clinic start generated code]*/ + +static int +getpath_hassuffix_impl(PyObject *module, PyObject *pathobj, + PyObject *suffixobj) +/*[clinic end generated code: output=c4cbd6f2f567f83c input=4b477740575b94d8]*/ { - PyObject *r = NULL; - PyObject *pathobj; - PyObject *suffixobj; - const wchar_t *path; - const wchar_t *suffix; - if (!PyArg_ParseTuple(args, "UU", &pathobj, &suffixobj)) { - return NULL; - } + int r = -1; Py_ssize_t len, suffixLen; - path = PyUnicode_AsWideCharString(pathobj, &len); + const wchar_t *path = PyUnicode_AsWideCharString(pathobj, &len); if (path) { - suffix = PyUnicode_AsWideCharString(suffixobj, &suffixLen); + const wchar_t *suffix = PyUnicode_AsWideCharString(suffixobj, + &suffixLen); if (suffix) { - if (suffixLen > len || + r = suffixLen <= len && #ifdef MS_WINDOWS - wcsicmp(&path[len - suffixLen], suffix) != 0 + wcsicmp(&path[len - suffixLen], suffix) == 0; #else - wcscmp(&path[len - suffixLen], suffix) != 0 + wcscmp(&path[len - suffixLen], suffix) == 0; #endif - ) { - r = Py_NewRef(Py_False); - } else { - r = Py_NewRef(Py_True); - } PyMem_Free((void *)suffix); } PyMem_Free((void *)path); @@ -170,105 +188,114 @@ getpath_hassuffix(PyObject *Py_UNUSED(self), PyObject *args) } -static PyObject * -getpath_isdir(PyObject *Py_UNUSED(self), PyObject *args) +/*[clinic input] +getpath.isdir -> bool + + path: Py_UNICODE + / + +Return True if the path is a directory. +[clinic start generated code]*/ + +static int +getpath_isdir_impl(PyObject *module, const wchar_t *path) +/*[clinic end generated code: output=467820dd83daa7a6 input=0ddd588cd5357a9a]*/ { - PyObject *r = NULL; - PyObject *pathobj; - const wchar_t *path; - if (!PyArg_ParseTuple(args, "U", &pathobj)) { - return NULL; - } - path = PyUnicode_AsWideCharString(pathobj, NULL); - if (path) { #ifdef MS_WINDOWS - DWORD attr = GetFileAttributesW(path); - r = (attr != INVALID_FILE_ATTRIBUTES) && - (attr & FILE_ATTRIBUTE_DIRECTORY) ? Py_True : Py_False; + DWORD attr = GetFileAttributesW(path); + return (attr != INVALID_FILE_ATTRIBUTES) + && (attr & FILE_ATTRIBUTE_DIRECTORY); #else - struct stat st; - r = (_Py_wstat(path, &st) == 0) && S_ISDIR(st.st_mode) ? Py_True : Py_False; + struct stat st; + return (_Py_wstat(path, &st) == 0) && S_ISDIR(st.st_mode); #endif - PyMem_Free((void *)path); - } - return Py_XNewRef(r); } -static PyObject * -getpath_isfile(PyObject *Py_UNUSED(self), PyObject *args) -{ - PyObject *pathobj; - if (!PyArg_ParseTuple(args, "U", &pathobj)) { - return NULL; - } +/*[clinic input] +getpath.isfile -> bool + + path as pathobj: unicode + / - int isfile; +Return True if the path is a regular file. +[clinic start generated code]*/ + +static int +getpath_isfile_impl(PyObject *module, PyObject *pathobj) +/*[clinic end generated code: output=197acb7a5434b9d1 input=ba1c2746ec8f2f47]*/ +{ #ifdef MS_WINDOWS wchar_t *path = PyUnicode_AsWideCharString(pathobj, NULL); if (path == NULL) { - return NULL; + return -1; } DWORD attr = GetFileAttributesW(path); PyMem_Free(path); - isfile = ((attr != INVALID_FILE_ATTRIBUTES) - && !(attr & FILE_ATTRIBUTE_DIRECTORY)); + return (attr != INVALID_FILE_ATTRIBUTES) + && !(attr & FILE_ATTRIBUTE_DIRECTORY); #else struct stat st; int res = _Py_stat(pathobj, &st); if (res == -2) { - return NULL; + return -1; } - isfile = ((res == 0) && S_ISREG(st.st_mode)); + return (res == 0) && S_ISREG(st.st_mode); #endif - return PyBool_FromLong(isfile); } -static PyObject * -getpath_isxfile(PyObject *Py_UNUSED(self), PyObject *args) -{ - PyObject *pathobj; - if (!PyArg_ParseTuple(args, "U", &pathobj)) { - return NULL; - } +/*[clinic input] +getpath.isxfile -> bool + + path as pathobj: unicode + / + +Return True if the path is an executable file. +[clinic start generated code]*/ - int isxfile; +static int +getpath_isxfile_impl(PyObject *module, PyObject *pathobj) +/*[clinic end generated code: output=2f0bc6708d945bc8 input=6d99faa90e262511]*/ +{ #ifdef MS_WINDOWS Py_ssize_t cchPath; wchar_t *path = PyUnicode_AsWideCharString(pathobj, &cchPath); if (path == NULL) { - return NULL; + return -1; } DWORD attr = GetFileAttributesW(path); + int isxfile = (attr != INVALID_FILE_ATTRIBUTES) && + !(attr & FILE_ATTRIBUTE_DIRECTORY) && + (cchPath >= 4) && + (CompareStringOrdinal(path + cchPath - 4, -1, L".exe", -1, 1 /* ignore case */) == CSTR_EQUAL); PyMem_Free(path); - isxfile = (attr != INVALID_FILE_ATTRIBUTES) && - !(attr & FILE_ATTRIBUTE_DIRECTORY) && - (cchPath >= 4) && - (CompareStringOrdinal(path + cchPath - 4, -1, L".exe", -1, 1 /* ignore case */) == CSTR_EQUAL); + return isxfile; #else struct stat st; int res = _Py_stat(pathobj, &st); if (res == -2) { - return NULL; + return -1; } - isxfile = ((res == 0) - && S_ISREG(st.st_mode) - && (st.st_mode & 0111)); + return (res == 0) && S_ISREG(st.st_mode) && (st.st_mode & 0111); #endif - return PyBool_FromLong(isxfile); } +/*[clinic input] +getpath.joinpath + + *args: tuple + +Join the path components. +[clinic start generated code]*/ + static PyObject * -getpath_joinpath(PyObject *Py_UNUSED(self), PyObject *args) +getpath_joinpath_impl(PyObject *module, PyObject *args) +/*[clinic end generated code: output=0044d429b32e5f5a input=5c67eeca4a6d1413]*/ { - if (!PyTuple_Check(args)) { - PyErr_SetString(PyExc_TypeError, "requires tuple of arguments"); - return NULL; - } Py_ssize_t n = PyTuple_GET_SIZE(args); if (n == 0) { return Py_GetConstant(Py_CONSTANT_EMPTY_STR); @@ -347,13 +374,19 @@ getpath_joinpath(PyObject *Py_UNUSED(self), PyObject *args) } +/*[clinic input] +getpath.readlines + + path as pathobj: unicode + / + +Return the lines of the file. +[clinic start generated code]*/ + static PyObject * -getpath_readlines(PyObject *Py_UNUSED(self), PyObject *args) +getpath_readlines_impl(PyObject *module, PyObject *pathobj) +/*[clinic end generated code: output=6a7c1a1d2bb23046 input=6f54150f72789b78]*/ { - PyObject *pathobj; - if (!PyArg_ParseTuple(args, "U", &pathobj)) { - return NULL; - } FILE *fp = Py_fopen(pathobj, "rb"); if (!fp) { return NULL; @@ -423,13 +456,19 @@ getpath_readlines(PyObject *Py_UNUSED(self), PyObject *args) } +/*[clinic input] +getpath.realpath + + path as pathobj: unicode + / + +Resolve a symlinked file. +[clinic start generated code]*/ + static PyObject * -getpath_realpath(PyObject *Py_UNUSED(self) , PyObject *args) +getpath_realpath_impl(PyObject *module, PyObject *pathobj) +/*[clinic end generated code: output=8559260e3786874e input=d3c5eee0ddd2c3e2]*/ { - PyObject *pathobj; - if (!PyArg_ParseTuple(args, "U", &pathobj)) { - return NULL; - } #if defined(HAVE_READLINK) /* This readlink calculation only resolves a symlinked file, and does not resolve any path segments. This is consistent with @@ -566,17 +605,17 @@ getpath_realpath(PyObject *Py_UNUSED(self) , PyObject *args) static PyMethodDef getpath_methods[] = { - {"abspath", getpath_abspath, METH_VARARGS, NULL}, - {"basename", getpath_basename, METH_VARARGS, NULL}, - {"dirname", getpath_dirname, METH_VARARGS, NULL}, - {"hassuffix", getpath_hassuffix, METH_VARARGS, NULL}, - {"isabs", getpath_isabs, METH_VARARGS, NULL}, - {"isdir", getpath_isdir, METH_VARARGS, NULL}, - {"isfile", getpath_isfile, METH_VARARGS, NULL}, - {"isxfile", getpath_isxfile, METH_VARARGS, NULL}, - {"joinpath", getpath_joinpath, METH_VARARGS, NULL}, - {"readlines", getpath_readlines, METH_VARARGS, NULL}, - {"realpath", getpath_realpath, METH_VARARGS, NULL}, + GETPATH_ABSPATH_METHODDEF + GETPATH_BASENAME_METHODDEF + GETPATH_DIRNAME_METHODDEF + GETPATH_HASSUFFIX_METHODDEF + GETPATH_ISABS_METHODDEF + GETPATH_ISDIR_METHODDEF + GETPATH_ISFILE_METHODDEF + GETPATH_ISXFILE_METHODDEF + GETPATH_JOINPATH_METHODDEF + GETPATH_READLINES_METHODDEF + GETPATH_REALPATH_METHODDEF {NULL, NULL, 0, NULL} }; From 93142c95c550e781bef5bec93100eca3c90be4f6 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 27 Sep 2026 18:58:30 +0300 Subject: [PATCH 2/5] gh-155496: Use Argument Clinic for more functions of the _csv module (GH-158133) --- Modules/_csv.c | 190 ++++++++++++++++++------------- Modules/clinic/_csv.c.h | 246 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 353 insertions(+), 83 deletions(-) diff --git a/Modules/_csv.c b/Modules/_csv.c index 6af66c3f09a03b..34548b94385693 100644 --- a/Modules/_csv.c +++ b/Modules/_csv.c @@ -21,10 +21,9 @@ module instead. /*[clinic input] module _csv +class _csv.Dialect "DialectObj *" "clinic_state()->dialect_type" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=385118b71aa43706]*/ - -#include "clinic/_csv.c.h" +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=042fcc14c7d541cc]*/ #define NOT_SET ((Py_UCS4)-1) #define EOL ((Py_UCS4)-2) @@ -125,6 +124,8 @@ typedef struct { bool nonascii_special; } DialectObj; +#include "clinic/_csv.c.h" + typedef struct { PyObject_HEAD @@ -631,43 +632,62 @@ dialect_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) /* Since dialect is now a heap type, it inherits pickling method for * protocol 0 and 1 from object, therefore it needs to be overridden */ -PyDoc_STRVAR(dialect_reduce_doc, "raises an exception to avoid pickling"); +/*[clinic input] +_csv.Dialect.__reduce__ + +Raise an exception to avoid pickling. +[clinic start generated code]*/ static PyObject * -Dialect_reduce(PyObject *self, PyObject *args) { +_csv_Dialect___reduce___impl(DialectObj *self) +/*[clinic end generated code: output=f728b34af509ed69 input=e46419b46279e480]*/ +{ PyErr_Format(PyExc_TypeError, "cannot pickle '%.100s' instances", _PyType_Name(Py_TYPE(self))); return NULL; } -PyDoc_STRVAR(dialect_replace_doc, -"__replace__($self, /, **changes)\n" -"--\n" -"\n" -"Return a copy of the dialect with the specified options replaced."); +/*[clinic input] +_csv.Dialect.__reduce_ex__ + + protocol: object + / + +Raise an exception to avoid pickling. +[clinic start generated code]*/ static PyObject * -Dialect_replace(PyObject *self, PyObject *args, PyObject *kwargs) +_csv_Dialect___reduce_ex___impl(DialectObj *self, PyObject *protocol) +/*[clinic end generated code: output=d45dec397da6575a input=c6ebd579e8959040]*/ +{ + return _csv_Dialect___reduce___impl(self); +} + +/*[clinic input] +_csv.Dialect.__replace__ + + **changes: dict + +Return a copy of the dialect with the specified options replaced. +[clinic start generated code]*/ + +static PyObject * +_csv_Dialect___replace___impl(DialectObj *self, PyObject *changes) +/*[clinic end generated code: output=8f692c2c63a61b50 input=154beb565fbabd4c]*/ { - if (PyTuple_GET_SIZE(args) != 0) { - PyErr_SetString(PyExc_TypeError, - "__replace__() takes no positional arguments"); - return NULL; - } PyObject *newargs = PyTuple_Pack(1, self); if (newargs == NULL) { return NULL; } - PyObject *result = dialect_new(Py_TYPE(self), newargs, kwargs); + PyObject *result = dialect_new(Py_TYPE(self), newargs, changes); Py_DECREF(newargs); return result; } static struct PyMethodDef dialect_methods[] = { - {"__reduce__", Dialect_reduce, METH_VARARGS, dialect_reduce_doc}, - {"__reduce_ex__", Dialect_reduce, METH_VARARGS, dialect_reduce_doc}, - {"__replace__", _PyCFunction_CAST(Dialect_replace), - METH_VARARGS | METH_KEYWORDS, dialect_replace_doc}, + _CSV_DIALECT___REDUCE___METHODDEF + _CSV_DIALECT___REDUCE_EX___METHODDEF + _CSV_DIALECT___REPLACE___METHODDEF {NULL, NULL} }; @@ -1162,10 +1182,31 @@ PyType_Spec Reader_Type_spec = { }; +/*[clinic input] +_csv.reader + + iterable: object + dialect: object(c_default='NULL') = 'excel' + / + **fmtparams: dict + +Return a reader object that will process lines from the given iterable. + +The "iterable" argument can be any object that returns a line +of input for each iteration, such as a file object or a list. The +optional "dialect" argument defines a CSV dialect. The function +also accepts optional keyword arguments which override settings +provided by the dialect. + +The returned object is an iterator. Each iteration returns a row +of the CSV file (which can span multiple input lines). +[clinic start generated code]*/ + static PyObject * -csv_reader(PyObject *module, PyObject *args, PyObject *keyword_args) +_csv_reader_impl(PyObject *module, PyObject *iterable, PyObject *dialect, + PyObject *fmtparams) +/*[clinic end generated code: output=c7033323f4e82fae input=330c6d58878e33b7]*/ { - PyObject * iterator, * dialect = NULL; _csvstate *module_state = get_csv_state(module); ReaderObj * self = PyObject_GC_New( ReaderObj, @@ -1186,17 +1227,13 @@ csv_reader(PyObject *module, PyObject *args, PyObject *keyword_args) return NULL; } - if (!PyArg_UnpackTuple(args, "reader", 1, 2, &iterator, &dialect)) { - Py_DECREF(self); - return NULL; - } - self->input_iter = PyObject_GetIter(iterator); + self->input_iter = PyObject_GetIter(iterable); if (self->input_iter == NULL) { Py_DECREF(self); return NULL; } self->dialect = (DialectObj *)_call_dialect(module_state, dialect, - keyword_args); + fmtparams); if (self->dialect == NULL) { Py_DECREF(self); return NULL; @@ -1624,10 +1661,27 @@ PyType_Spec Writer_Type_spec = { }; +/*[clinic input] +_csv.writer + + fileobj as output_file: object + dialect: object(c_default='NULL') = 'excel' + / + **fmtparams: dict + +Return a writer object writing user data to the given file object. + +The "fileobj" argument can be any object that supports the file API. +The optional "dialect" argument defines a CSV dialect. The function +also accepts optional keyword arguments which override settings +provided by the dialect. +[clinic start generated code]*/ + static PyObject * -csv_writer(PyObject *module, PyObject *args, PyObject *keyword_args) +_csv_writer_impl(PyObject *module, PyObject *output_file, PyObject *dialect, + PyObject *fmtparams) +/*[clinic end generated code: output=3f57919e03cca475 input=18d396d2aa8138f0]*/ { - PyObject * output_file, * dialect = NULL; _csvstate *module_state = get_csv_state(module); WriterObj * self = PyObject_GC_New(WriterObj, module_state->writer_type); @@ -1644,10 +1698,6 @@ csv_writer(PyObject *module, PyObject *args, PyObject *keyword_args) self->error_obj = Py_NewRef(module_state->error_obj); - if (!PyArg_UnpackTuple(args, "writer", 1, 2, &output_file, &dialect)) { - Py_DECREF(self); - return NULL; - } if (PyObject_GetOptionalAttr(output_file, module_state->str_write, &self->write) < 0) { @@ -1661,7 +1711,7 @@ csv_writer(PyObject *module, PyObject *args, PyObject *keyword_args) return NULL; } self->dialect = (DialectObj *)_call_dialect(module_state, dialect, - keyword_args); + fmtparams); if (self->dialect == NULL) { Py_DECREF(self); return NULL; @@ -1687,21 +1737,36 @@ _csv_list_dialects_impl(PyObject *module) return PyDict_Keys(get_csv_state(module)->dialects); } +/*[clinic input] +_csv.register_dialect + + name as name_obj: object + dialect as dialect_obj: object(c_default='NULL') = 'excel' + / + **fmtparams: dict + +Create a mapping from a string name to a CVS dialect. + +The optional "dialect" argument specifies the base dialect instance +or the name of the registered dialect. The function also accepts +optional keyword arguments which override settings provided by the +dialect. +[clinic start generated code]*/ + static PyObject * -csv_register_dialect(PyObject *module, PyObject *args, PyObject *kwargs) +_csv_register_dialect_impl(PyObject *module, PyObject *name_obj, + PyObject *dialect_obj, PyObject *fmtparams) +/*[clinic end generated code: output=b00b54de5b950472 input=64e9180e18d88a97]*/ { - PyObject *name_obj, *dialect_obj = NULL; _csvstate *module_state = get_csv_state(module); PyObject *dialect; - if (!PyArg_UnpackTuple(args, "register_dialect", 1, 2, &name_obj, &dialect_obj)) - return NULL; if (!PyUnicode_Check(name_obj)) { PyErr_SetString(PyExc_TypeError, "dialect name must be a string"); return NULL; } - dialect = _call_dialect(module_state, dialect_obj, kwargs); + dialect = _call_dialect(module_state, dialect_obj, fmtparams); if (dialect == NULL) return NULL; if (PyDict_SetItem(module_state->dialects, name_obj, dialect) < 0) { @@ -1800,47 +1865,10 @@ PyType_Spec error_spec = { PyDoc_STRVAR(csv_module_doc, "CSV parsing and writing.\n"); -PyDoc_STRVAR(csv_reader_doc, -"reader($module, iterable, /, dialect='excel', **fmtparams)\n" -"--\n\n" -"Return a reader object that will process lines from the given iterable.\n" -"\n" -"The \"iterable\" argument can be any object that returns a line\n" -"of input for each iteration, such as a file object or a list. The\n" -"optional \"dialect\" argument defines a CSV dialect. The function\n" -"also accepts optional keyword arguments which override settings\n" -"provided by the dialect.\n" -"\n" -"The returned object is an iterator. Each iteration returns a row\n" -"of the CSV file (which can span multiple input lines).\n"); - -PyDoc_STRVAR(csv_writer_doc, -"writer($module, fileobj, /, dialect='excel', **fmtparams)\n" -"--\n\n" -"Return a writer object that will write user data on the given file object.\n" -"\n" -"The \"fileobj\" argument can be any object that supports the file API.\n" -"The optional \"dialect\" argument defines a CSV dialect. The function\n" -"also accepts optional keyword arguments which override settings\n" -"provided by the dialect.\n"); - -PyDoc_STRVAR(csv_register_dialect_doc, -"register_dialect($module, name, /, dialect='excel', **fmtparams)\n" -"--\n\n" -"Create a mapping from a string name to a CVS dialect.\n" -"\n" -"The optional \"dialect\" argument specifies the base dialect instance\n" -"or the name of the registered dialect. The function also accepts\n" -"optional keyword arguments which override settings provided by the\n" -"dialect.\n"); - static struct PyMethodDef csv_methods[] = { - { "reader", _PyCFunction_CAST(csv_reader), - METH_VARARGS | METH_KEYWORDS, csv_reader_doc}, - { "writer", _PyCFunction_CAST(csv_writer), - METH_VARARGS | METH_KEYWORDS, csv_writer_doc}, - { "register_dialect", _PyCFunction_CAST(csv_register_dialect), - METH_VARARGS | METH_KEYWORDS, csv_register_dialect_doc}, + _CSV_READER_METHODDEF + _CSV_WRITER_METHODDEF + _CSV_REGISTER_DIALECT_METHODDEF _CSV_LIST_DIALECTS_METHODDEF _CSV_UNREGISTER_DIALECT_METHODDEF _CSV_GET_DIALECT_METHODDEF diff --git a/Modules/clinic/_csv.c.h b/Modules/clinic/_csv.c.h index b8dd8ac35fac59..b25f30893224cd 100644 --- a/Modules/clinic/_csv.c.h +++ b/Modules/clinic/_csv.c.h @@ -6,7 +6,196 @@ preserve # include "pycore_gc.h" // PyGC_Head # include "pycore_runtime.h" // _Py_ID() #endif -#include "pycore_modsupport.h" // _PyArg_UnpackKeywords() +#include "pycore_modsupport.h" // _PyArg_NoPositional() + +PyDoc_STRVAR(_csv_Dialect___reduce____doc__, +"__reduce__($self, /)\n" +"--\n" +"\n" +"Raise an exception to avoid pickling."); + +#define _CSV_DIALECT___REDUCE___METHODDEF \ + {"__reduce__", (PyCFunction)_csv_Dialect___reduce__, METH_NOARGS, _csv_Dialect___reduce____doc__}, + +static PyObject * +_csv_Dialect___reduce___impl(DialectObj *self); + +static PyObject * +_csv_Dialect___reduce__(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _csv_Dialect___reduce___impl((DialectObj *)self); +} + +PyDoc_STRVAR(_csv_Dialect___reduce_ex____doc__, +"__reduce_ex__($self, protocol, /)\n" +"--\n" +"\n" +"Raise an exception to avoid pickling."); + +#define _CSV_DIALECT___REDUCE_EX___METHODDEF \ + {"__reduce_ex__", (PyCFunction)_csv_Dialect___reduce_ex__, METH_O, _csv_Dialect___reduce_ex____doc__}, + +static PyObject * +_csv_Dialect___reduce_ex___impl(DialectObj *self, PyObject *protocol); + +static PyObject * +_csv_Dialect___reduce_ex__(PyObject *self, PyObject *protocol) +{ + PyObject *return_value = NULL; + + return_value = _csv_Dialect___reduce_ex___impl((DialectObj *)self, protocol); + + return return_value; +} + +PyDoc_STRVAR(_csv_Dialect___replace____doc__, +"__replace__($self, /, **changes)\n" +"--\n" +"\n" +"Return a copy of the dialect with the specified options replaced."); + +#define _CSV_DIALECT___REPLACE___METHODDEF \ + {"__replace__", _PyCFunction_CAST(_csv_Dialect___replace__), METH_VARARGS|METH_KEYWORDS, _csv_Dialect___replace____doc__}, + +static PyObject * +_csv_Dialect___replace___impl(DialectObj *self, PyObject *changes); + +static PyObject * +_csv_Dialect___replace__(PyObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + PyObject *changes = NULL; + + if (!_PyArg_NoPositional("__replace__", args)) { + goto exit; + } + if (kwargs == NULL) { + changes = PyDict_New(); + if (changes == NULL) { + goto exit; + } + } + else { + changes = Py_NewRef(kwargs); + } + return_value = _csv_Dialect___replace___impl((DialectObj *)self, changes); + +exit: + /* Cleanup for changes */ + Py_XDECREF(changes); + + return return_value; +} + +PyDoc_STRVAR(_csv_reader__doc__, +"reader($module, iterable, dialect=\'excel\', /, **fmtparams)\n" +"--\n" +"\n" +"Return a reader object that will process lines from the given iterable.\n" +"\n" +"The \"iterable\" argument can be any object that returns a line\n" +"of input for each iteration, such as a file object or a list. The\n" +"optional \"dialect\" argument defines a CSV dialect. The function\n" +"also accepts optional keyword arguments which override settings\n" +"provided by the dialect.\n" +"\n" +"The returned object is an iterator. Each iteration returns a row\n" +"of the CSV file (which can span multiple input lines)."); + +#define _CSV_READER_METHODDEF \ + {"reader", _PyCFunction_CAST(_csv_reader), METH_VARARGS|METH_KEYWORDS, _csv_reader__doc__}, + +static PyObject * +_csv_reader_impl(PyObject *module, PyObject *iterable, PyObject *dialect, + PyObject *fmtparams); + +static PyObject * +_csv_reader(PyObject *module, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + PyObject *iterable; + PyObject *dialect = NULL; + PyObject *fmtparams = NULL; + + if (!_PyArg_CheckPositional("reader", PyTuple_GET_SIZE(args), 1, 2)) { + goto exit; + } + iterable = PyTuple_GET_ITEM(args, 0); + if (PyTuple_GET_SIZE(args) < 2) { + goto skip_optional; + } + dialect = PyTuple_GET_ITEM(args, 1); +skip_optional: + if (kwargs == NULL) { + fmtparams = PyDict_New(); + if (fmtparams == NULL) { + goto exit; + } + } + else { + fmtparams = Py_NewRef(kwargs); + } + return_value = _csv_reader_impl(module, iterable, dialect, fmtparams); + +exit: + /* Cleanup for fmtparams */ + Py_XDECREF(fmtparams); + + return return_value; +} + +PyDoc_STRVAR(_csv_writer__doc__, +"writer($module, fileobj, dialect=\'excel\', /, **fmtparams)\n" +"--\n" +"\n" +"Return a writer object writing user data to the given file object.\n" +"\n" +"The \"fileobj\" argument can be any object that supports the file API.\n" +"The optional \"dialect\" argument defines a CSV dialect. The function\n" +"also accepts optional keyword arguments which override settings\n" +"provided by the dialect."); + +#define _CSV_WRITER_METHODDEF \ + {"writer", _PyCFunction_CAST(_csv_writer), METH_VARARGS|METH_KEYWORDS, _csv_writer__doc__}, + +static PyObject * +_csv_writer_impl(PyObject *module, PyObject *output_file, PyObject *dialect, + PyObject *fmtparams); + +static PyObject * +_csv_writer(PyObject *module, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + PyObject *output_file; + PyObject *dialect = NULL; + PyObject *fmtparams = NULL; + + if (!_PyArg_CheckPositional("writer", PyTuple_GET_SIZE(args), 1, 2)) { + goto exit; + } + output_file = PyTuple_GET_ITEM(args, 0); + if (PyTuple_GET_SIZE(args) < 2) { + goto skip_optional; + } + dialect = PyTuple_GET_ITEM(args, 1); +skip_optional: + if (kwargs == NULL) { + fmtparams = PyDict_New(); + if (fmtparams == NULL) { + goto exit; + } + } + else { + fmtparams = Py_NewRef(kwargs); + } + return_value = _csv_writer_impl(module, output_file, dialect, fmtparams); + +exit: + /* Cleanup for fmtparams */ + Py_XDECREF(fmtparams); + + return return_value; +} PyDoc_STRVAR(_csv_list_dialects__doc__, "list_dialects($module, /)\n" @@ -26,6 +215,59 @@ _csv_list_dialects(PyObject *module, PyObject *Py_UNUSED(ignored)) return _csv_list_dialects_impl(module); } +PyDoc_STRVAR(_csv_register_dialect__doc__, +"register_dialect($module, name, dialect=\'excel\', /, **fmtparams)\n" +"--\n" +"\n" +"Create a mapping from a string name to a CVS dialect.\n" +"\n" +"The optional \"dialect\" argument specifies the base dialect instance\n" +"or the name of the registered dialect. The function also accepts\n" +"optional keyword arguments which override settings provided by the\n" +"dialect."); + +#define _CSV_REGISTER_DIALECT_METHODDEF \ + {"register_dialect", _PyCFunction_CAST(_csv_register_dialect), METH_VARARGS|METH_KEYWORDS, _csv_register_dialect__doc__}, + +static PyObject * +_csv_register_dialect_impl(PyObject *module, PyObject *name_obj, + PyObject *dialect_obj, PyObject *fmtparams); + +static PyObject * +_csv_register_dialect(PyObject *module, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + PyObject *name_obj; + PyObject *dialect_obj = NULL; + PyObject *fmtparams = NULL; + + if (!_PyArg_CheckPositional("register_dialect", PyTuple_GET_SIZE(args), 1, 2)) { + goto exit; + } + name_obj = PyTuple_GET_ITEM(args, 0); + if (PyTuple_GET_SIZE(args) < 2) { + goto skip_optional; + } + dialect_obj = PyTuple_GET_ITEM(args, 1); +skip_optional: + if (kwargs == NULL) { + fmtparams = PyDict_New(); + if (fmtparams == NULL) { + goto exit; + } + } + else { + fmtparams = Py_NewRef(kwargs); + } + return_value = _csv_register_dialect_impl(module, name_obj, dialect_obj, fmtparams); + +exit: + /* Cleanup for fmtparams */ + Py_XDECREF(fmtparams); + + return return_value; +} + PyDoc_STRVAR(_csv_unregister_dialect__doc__, "unregister_dialect($module, /, name)\n" "--\n" @@ -207,4 +449,4 @@ _csv_field_size_limit(PyObject *module, PyObject *const *args, Py_ssize_t nargs, exit: return return_value; } -/*[clinic end generated code: output=ed77cb69fad9f3b4 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=1a90b8a8ed82497d input=a9049054013a1b77]*/ From dc590064bdfe45a937cab40a1fd34a25352e8c77 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 27 Sep 2026 19:00:22 +0300 Subject: [PATCH 3/5] gh-155496: Use Argument Clinic for more functions and methods (GH-158134) Convert to Argument Clinic: * builtins dir() and vars() * property.__set_name__() * memoryview.__exit__() * structseq __replace__() * types.SimpleNamespace.__replace__() * re.Match.group() * sys.getsizeof() and sys.set_asyncgen_hooks() * atexit.register() * os.scandir() iterator __exit__() * _dbm, _gdbm and _decimal context manager __exit__() * _functools lru_cache __copy__() and __deepcopy__() * _elementtree.SubElement() * _interpreters.new_config() * _tkinter call() and wantobjects() * zoneinfo.ZoneInfo.__init_subclass__() * internal hamt and stdprinter methods --- .../pycore_global_objects_fini_generated.h | 2 + Include/internal/pycore_global_strings.h | 2 + .../internal/pycore_runtime_init_generated.h | 2 + .../internal/pycore_unicodeobject_generated.h | 2 + Lib/test/test_inspect/test_inspect.py | 16 +- Lib/test/test_property.py | 2 +- Modules/_dbmmodule.c | 22 ++- Modules/_decimal/_decimal.c | 22 ++- Modules/_decimal/clinic/_decimal.c.h | 30 +++- Modules/_elementtree.c | 40 +++-- Modules/_functoolsmodule.c | 25 +++- Modules/_gdbmmodule.c | 21 ++- Modules/_interpretersmodule.c | 45 +++--- Modules/_sre/clinic/sre.c.h | 31 +++- Modules/_sre/sre.c | 40 ++--- Modules/_tkinter.c | 36 +++-- Modules/_zoneinfo.c | 18 ++- Modules/atexitmodule.c | 61 ++++---- Modules/clinic/_dbmmodule.c.h | 31 +++- Modules/clinic/_elementtree.c.h | 63 +++++++- Modules/clinic/_functoolsmodule.c.h | 29 +++- Modules/clinic/_gdbmmodule.c.h | 31 +++- Modules/clinic/_interpretersmodule.c.h | 68 ++++++++- Modules/clinic/_tkinter.c.h | 67 ++++++++- Modules/clinic/_zoneinfo.c.h | 42 +++++- Modules/clinic/atexitmodule.c.h | 61 ++++++++ Modules/clinic/posixmodule.c.h | 29 +++- Modules/posixmodule.c | 20 ++- Objects/clinic/descrobject.c.h | 33 ++++- Objects/clinic/fileobject.c.h | 35 +++++ Objects/clinic/memoryobject.c.h | 30 +++- Objects/clinic/namespaceobject.c.h | 45 ++++++ Objects/clinic/structseq.c.h | 41 +++++- Objects/descrobject.c | 35 ++--- Objects/fileobject.c | 27 +++- Objects/memoryobject.c | 22 ++- Objects/namespaceobject.c | 34 +++-- Objects/structseq.c | 65 ++++---- Python/bltinmodule.c | 69 +++++---- Python/clinic/bltinmodule.c.h | 80 +++++++++- Python/clinic/hamt.c.h | 70 +++++++++ Python/clinic/sysmodule.c.h | 139 +++++++++++++++++- Python/hamt.c | 56 ++++--- Python/sysmodule.c | 59 ++++---- 44 files changed, 1363 insertions(+), 335 deletions(-) create mode 100644 Modules/clinic/atexitmodule.c.h create mode 100644 Objects/clinic/fileobject.c.h create mode 100644 Objects/clinic/namespaceobject.c.h create mode 100644 Python/clinic/hamt.c.h diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index ce3d004374338e..bcbfcdd9eaaec5 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -488,7 +488,9 @@ _PyStaticObjects_CheckAll(PyInterpreterState *interp) { _PyStaticObject_CheckUnicodeSingleton((PyObject *)&_Py_ID(filter), "filter", 6); _PyStaticObject_CheckUnicodeSingleton((PyObject *)&_Py_ID(filters), "filters", 7); _PyStaticObject_CheckUnicodeSingleton((PyObject *)&_Py_ID(final), "final", 5); + _PyStaticObject_CheckUnicodeSingleton((PyObject *)&_Py_ID(finalizer), "finalizer", 9); _PyStaticObject_CheckUnicodeSingleton((PyObject *)&_Py_ID(find_class), "find_class", 10); + _PyStaticObject_CheckUnicodeSingleton((PyObject *)&_Py_ID(firstiter), "firstiter", 9); _PyStaticObject_CheckUnicodeSingleton((PyObject *)&_Py_ID(fix_imports), "fix_imports", 11); _PyStaticObject_CheckUnicodeSingleton((PyObject *)&_Py_ID(flags), "flags", 5); _PyStaticObject_CheckUnicodeSingleton((PyObject *)&_Py_ID(flush), "flush", 5); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index a293f0528b91ae..2e5020578ad69b 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -500,7 +500,9 @@ struct _Py_global_strings { STRUCT_FOR_ID(filter) STRUCT_FOR_ID(filters) STRUCT_FOR_ID(final) + STRUCT_FOR_ID(finalizer) STRUCT_FOR_ID(find_class) + STRUCT_FOR_ID(firstiter) STRUCT_FOR_ID(fix_imports) STRUCT_FOR_ID(flags) STRUCT_FOR_ID(flush) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index fa90d6b9582499..c95b2d4f95a50d 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -1775,7 +1775,9 @@ extern "C" { INIT_ID(filter), \ INIT_ID(filters), \ INIT_ID(final), \ + INIT_ID(finalizer), \ INIT_ID(find_class), \ + INIT_ID(firstiter), \ INIT_ID(fix_imports), \ INIT_ID(flags), \ INIT_ID(flush), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index aafe24e288e172..795515260daecb 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -455,7 +455,9 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { offsetof(struct _Py_global_strings, identifiers._py_filter._ascii.ob_base), offsetof(struct _Py_global_strings, identifiers._py_filters._ascii.ob_base), offsetof(struct _Py_global_strings, identifiers._py_final._ascii.ob_base), + offsetof(struct _Py_global_strings, identifiers._py_finalizer._ascii.ob_base), offsetof(struct _Py_global_strings, identifiers._py_find_class._ascii.ob_base), + offsetof(struct _Py_global_strings, identifiers._py_firstiter._ascii.ob_base), offsetof(struct _Py_global_strings, identifiers._py_fix_imports._ascii.ob_base), offsetof(struct _Py_global_strings, identifiers._py_flags._ascii.ob_base), offsetof(struct _Py_global_strings, identifiers._py_flush._ascii.ob_base), diff --git a/Lib/test/test_inspect/test_inspect.py b/Lib/test/test_inspect/test_inspect.py index d3760ac3c266a8..38c7a9bde823d9 100644 --- a/Lib/test/test_inspect/test_inspect.py +++ b/Lib/test/test_inspect/test_inspect.py @@ -6170,11 +6170,10 @@ def test_builtins_have_signatures(self): no_signature = {'type', 'super', 'bytearray', 'bytes', 'dict', 'frozendict', 'int', 'str'} # These need PEP 457 groups - needs_groups = {"range", "slice", "dir", "getattr", - "next", "vars"} + needs_groups = {"range", "slice", "getattr", "next"} no_signature |= needs_groups # These have unrepresentable parameter default values of NULL - unsupported_signature = {"aiter", "iter"} + unsupported_signature = {"aiter", "iter", "dir", "vars"} # These need *args support in Argument Clinic needs_varargs = {"min", "max", "__build_class__"} no_signature |= needs_varargs @@ -6207,10 +6206,12 @@ def test_types_module_has_signatures(self): methods_no_signature=methods_no_signature) def test_sys_module_has_signatures(self): - no_signature = {'getsizeof', 'set_asyncgen_hooks'} - no_signature |= {name for name in ['getobjects'] - if hasattr(sys, name)} - self._test_module_has_signatures(sys, no_signature) + no_signature = {name for name in ['getobjects'] + if hasattr(sys, name)} + # The C default is NULL and None has other meaning + unsupported_signature = {'getsizeof', 'set_asyncgen_hooks'} + self._test_module_has_signatures(sys, no_signature, + unsupported_signature) def test_abc_module_has_signatures(self): import abc @@ -6313,7 +6314,6 @@ def test_pwd_module_has_signatures(self): def test_re_module_has_signatures(self): import re methods_no_signature = { - 'Match': {'group'}, 'Pattern': {'match'}, # It is now an alias for prefixmatch } self._test_module_has_signatures(re, diff --git a/Lib/test/test_property.py b/Lib/test/test_property.py index 26aefdbf0421dd..3c02330f09a081 100644 --- a/Lib/test/test_property.py +++ b/Lib/test/test_property.py @@ -260,7 +260,7 @@ def test_property_set_name_incorrect_args(self): for i in (0, 1, 3): with self.assertRaisesRegex( TypeError, - fr'^__set_name__\(\) takes 2 positional arguments but {i} were given$' + fr'^__set_name__ expected 2 arguments?, got {i}$' ): p.__set_name__(*([0] * i)) diff --git a/Modules/_dbmmodule.c b/Modules/_dbmmodule.c index a9f4f27d9eb742..0a5192546982d4 100644 --- a/Modules/_dbmmodule.c +++ b/Modules/_dbmmodule.c @@ -513,15 +513,21 @@ dbm__enter__(PyObject *self, PyObject *Py_UNUSED(dummy)) return Py_NewRef(self); } +/*[clinic input] +@critical_section +_dbm.dbm.__exit__ + + *exc_info: array + +Close the database. +[clinic start generated code]*/ + static PyObject * -dbm__exit__(PyObject *self, PyObject *Py_UNUSED(args)) +_dbm_dbm___exit___impl(dbmobject *self, PyObject * const *exc_info, + Py_ssize_t exc_info_length) +/*[clinic end generated code: output=f9549bf513b3285d input=340d8190b6fb0f15]*/ { - PyObject *result; - dbmobject *dp = dbmobject_CAST(self); - Py_BEGIN_CRITICAL_SECTION(self); - result = _dbm_dbm_close_impl(dp); - Py_END_CRITICAL_SECTION(); - return result; + return _dbm_dbm_close_impl(self); } static PyMethodDef dbm_methods[] = { @@ -531,7 +537,7 @@ static PyMethodDef dbm_methods[] = { _DBM_DBM_SETDEFAULT_METHODDEF _DBM_DBM_CLEAR_METHODDEF {"__enter__", dbm__enter__, METH_NOARGS, NULL}, - {"__exit__", dbm__exit__, METH_VARARGS, NULL}, + _DBM_DBM___EXIT___METHODDEF {NULL, NULL} /* sentinel */ }; diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index ada9b02d690717..20e4f5bea88464 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -57,7 +57,6 @@ #define _PY_DEC_ROUND_GUARD (MPD_ROUND_GUARD-1) #endif -#include "clinic/_decimal.c.h" #define MPD_SPEC_VERSION "1.70" // Highest version of the spec this complies with // See https://speleotrove.com/decimal/decarith.html @@ -66,8 +65,9 @@ module _decimal class _decimal.Decimal "PyObject *" "&dec_spec" class _decimal.Context "PyObject *" "&context_spec" +class _decimal.ContextManager "PyDecContextManagerObject *" "&ctxmanager_spec" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=a6a6c0bdf4e576ef]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=52b8c97cabc5bf05]*/ struct PyDecContextObject; struct DecCondMap; @@ -234,6 +234,8 @@ typedef struct { PyObject *global; } PyDecContextManagerObject; +#include "clinic/_decimal.c.h" + #define _PyDecContextManagerObject_CAST(op) ((PyDecContextManagerObject *)(op)) #undef MPD @@ -2209,11 +2211,21 @@ ctxmanager_set_local(PyObject *op, PyObject *Py_UNUSED(dummy)) return Py_NewRef(self->local); } +/*[clinic input] +_decimal.ContextManager.__exit__ + + *exc_info: array + +Restore the global context. +[clinic start generated code]*/ + static PyObject * -ctxmanager_restore_global(PyObject *op, PyObject *Py_UNUSED(args)) +_decimal_ContextManager___exit___impl(PyDecContextManagerObject *self, + PyObject * const *exc_info, + Py_ssize_t exc_info_length) +/*[clinic end generated code: output=744a645b0145842d input=a86ec9080e28dff3]*/ { PyObject *ret; - PyDecContextManagerObject *self = _PyDecContextManagerObject_CAST(op); ret = PyDec_SetCurrentContext(PyType_GetModule(Py_TYPE(self)), self->global); if (ret == NULL) { return NULL; @@ -2226,7 +2238,7 @@ ctxmanager_restore_global(PyObject *op, PyObject *Py_UNUSED(args)) static PyMethodDef ctxmanager_methods[] = { {"__enter__", ctxmanager_set_local, METH_NOARGS, NULL}, - {"__exit__", ctxmanager_restore_global, METH_VARARGS, NULL}, + _DECIMAL_CONTEXTMANAGER___EXIT___METHODDEF {NULL, NULL} }; diff --git a/Modules/_decimal/clinic/_decimal.c.h b/Modules/_decimal/clinic/_decimal.c.h index 8ad883d8a2d14d..aa78fd6887a06f 100644 --- a/Modules/_decimal/clinic/_decimal.c.h +++ b/Modules/_decimal/clinic/_decimal.c.h @@ -705,6 +705,34 @@ _decimal_localcontext(PyObject *module, PyObject *const *args, Py_ssize_t nargs, return return_value; } +PyDoc_STRVAR(_decimal_ContextManager___exit____doc__, +"__exit__($self, /, *exc_info)\n" +"--\n" +"\n" +"Restore the global context."); + +#define _DECIMAL_CONTEXTMANAGER___EXIT___METHODDEF \ + {"__exit__", _PyCFunction_CAST(_decimal_ContextManager___exit__), METH_FASTCALL, _decimal_ContextManager___exit____doc__}, + +static PyObject * +_decimal_ContextManager___exit___impl(PyDecContextManagerObject *self, + PyObject * const *exc_info, + Py_ssize_t exc_info_length); + +static PyObject * +_decimal_ContextManager___exit__(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject * const *exc_info; + Py_ssize_t exc_info_length; + + exc_info = args; + exc_info_length = nargs; + return_value = _decimal_ContextManager___exit___impl((PyDecContextManagerObject *)self, exc_info, exc_info_length); + + return return_value; +} + PyDoc_STRVAR(_decimal_Decimal_from_float__doc__, "from_float($type, f, /)\n" "--\n" @@ -7100,4 +7128,4 @@ _decimal_Context_same_quantum(PyObject *context, PyTypeObject *cls, PyObject *co #ifndef _DECIMAL_CONTEXT_APPLY_METHODDEF #define _DECIMAL_CONTEXT_APPLY_METHODDEF #endif /* !defined(_DECIMAL_CONTEXT_APPLY_METHODDEF) */ -/*[clinic end generated code: output=718b1f6c20412350 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=73c37ff551bca176 input=a9049054013a1b77]*/ diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c index 36115e61c2c215..50b7121b63ea85 100644 --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -612,33 +612,41 @@ element_get_tail(ElementObject* self) return Py_NewRef(res); } -static PyObject* -subelement(PyObject *self, PyObject *args, PyObject *kwds) +/*[clinic input] +_elementtree.SubElement + + parent: object(subclass_of='get_elementtree_state(module)->Element_Type') + tag: object + attrib: object(subclass_of='&PyDict_Type', c_default='NULL') = {} + / + **extra: dict + +Create a new subelement of the parent element. +[clinic start generated code]*/ + +static PyObject * +_elementtree_SubElement_impl(PyObject *module, PyObject *parent, + PyObject *tag, PyObject *attrib, + PyObject *extra) +/*[clinic end generated code: output=42e8a4ebc5db08aa input=8588fc68283cdaa0]*/ { PyObject* elem; - elementtreestate *st = get_elementtree_state(self); - ElementObject* parent; - PyObject* tag; - PyObject* attrib = NULL; - if (!PyArg_ParseTuple(args, "O!O|O!:SubElement", - st->Element_Type, &parent, &tag, - &PyDict_Type, &attrib)) { - return NULL; - } + elementtreestate *st = get_elementtree_state(module); + ElementObject* parent_elem = (ElementObject *)parent; if (attrib) { /* attrib passed as positional arg */ attrib = PyDict_Copy(attrib); if (!attrib) return NULL; - if (kwds != NULL && PyDict_Update(attrib, kwds) < 0) { + if (PyDict_Update(attrib, extra) < 0) { Py_DECREF(attrib); return NULL; } - } else if (kwds) { + } else if (PyDict_GET_SIZE(extra)) { /* have keyword args */ - attrib = get_attrib_from_keywords(kwds); + attrib = get_attrib_from_keywords(extra); if (!attrib) return NULL; } else { @@ -650,7 +658,7 @@ subelement(PyObject *self, PyObject *args, PyObject *kwds) if (elem == NULL) return NULL; - if (element_add_subelement(st, parent, elem) < 0) { + if (element_add_subelement(st, parent_elem, elem) < 0) { Py_DECREF(elem); return NULL; } @@ -4547,7 +4555,7 @@ static PyType_Spec xmlparser_spec = { /* python module interface */ static PyMethodDef _functions[] = { - {"SubElement", _PyCFunction_CAST(subelement), METH_VARARGS | METH_KEYWORDS}, + _ELEMENTTREE_SUBELEMENT_METHODDEF _ELEMENTTREE__SET_FACTORIES_METHODDEF {NULL, NULL} }; diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c index 1ab230218124a4..0ee6eeb9b00bc9 100644 --- a/Modules/_functoolsmodule.c +++ b/Modules/_functoolsmodule.c @@ -1817,14 +1817,31 @@ lru_cache_reduce(PyObject *self, PyObject *Py_UNUSED(dummy)) return PyObject_GetAttrString(self, "__qualname__"); } +/*[clinic input] +_functools._lru_cache_wrapper.__copy__ + +Return a copy of the wrapper, which is the wrapper itself. +[clinic start generated code]*/ + static PyObject * -lru_cache_copy(PyObject *self, PyObject *Py_UNUSED(args)) +_functools__lru_cache_wrapper___copy___impl(PyObject *self) +/*[clinic end generated code: output=d681851615d57391 input=41d000bde05efb2b]*/ { return Py_NewRef(self); } +/*[clinic input] +_functools._lru_cache_wrapper.__deepcopy__ + + memo: object + / + +Return a deep copy of the wrapper, which is the wrapper itself. +[clinic start generated code]*/ + static PyObject * -lru_cache_deepcopy(PyObject *self, PyObject *Py_UNUSED(args)) +_functools__lru_cache_wrapper___deepcopy__(PyObject *self, PyObject *memo) +/*[clinic end generated code: output=3445cd9d96273c9e input=84f706565f55ce46]*/ { return Py_NewRef(self); } @@ -1872,8 +1889,8 @@ static PyMethodDef lru_cache_methods[] = { _FUNCTOOLS__LRU_CACHE_WRAPPER_CACHE_INFO_METHODDEF _FUNCTOOLS__LRU_CACHE_WRAPPER_CACHE_CLEAR_METHODDEF {"__reduce__", lru_cache_reduce, METH_NOARGS}, - {"__copy__", lru_cache_copy, METH_VARARGS}, - {"__deepcopy__", lru_cache_deepcopy, METH_VARARGS}, + _FUNCTOOLS__LRU_CACHE_WRAPPER___COPY___METHODDEF + _FUNCTOOLS__LRU_CACHE_WRAPPER___DEEPCOPY___METHODDEF {NULL} }; diff --git a/Modules/_gdbmmodule.c b/Modules/_gdbmmodule.c index 20d482021656a5..47c02b72de2a76 100644 --- a/Modules/_gdbmmodule.c +++ b/Modules/_gdbmmodule.c @@ -687,14 +687,21 @@ gdbm__enter__(PyObject *self, PyObject *args) return Py_NewRef(self); } +/*[clinic input] +@critical_section +_gdbm.gdbm.__exit__ + + *exc_info: array + +Close the database. +[clinic start generated code]*/ + static PyObject * -gdbm__exit__(PyObject *self, PyObject *args) +_gdbm_gdbm___exit___impl(gdbmobject *self, PyObject * const *exc_info, + Py_ssize_t exc_info_length) +/*[clinic end generated code: output=4bb425e091228932 input=b22b90a00b22cf18]*/ { - PyObject *result; - Py_BEGIN_CRITICAL_SECTION(self); - result = _gdbm_gdbm_close_impl((gdbmobject *)self); - Py_END_CRITICAL_SECTION(); - return result; + return _gdbm_gdbm_close_impl(self); } static PyMethodDef gdbm_methods[] = { @@ -708,7 +715,7 @@ static PyMethodDef gdbm_methods[] = { _GDBM_GDBM_SETDEFAULT_METHODDEF _GDBM_GDBM_CLEAR_METHODDEF {"__enter__", gdbm__enter__, METH_NOARGS, NULL}, - {"__exit__", gdbm__exit__, METH_VARARGS, NULL}, + _GDBM_GDBM___EXIT___METHODDEF {NULL, NULL} /* sentinel */ }; diff --git a/Modules/_interpretersmodule.c b/Modules/_interpretersmodule.c index 15bfd35a80806c..6630d5f6fe2d33 100644 --- a/Modules/_interpretersmodule.c +++ b/Modules/_interpretersmodule.c @@ -802,23 +802,33 @@ get_summary(PyInterpreterState *interp) } -// Not converted to Argument Clinic because the function uses ``**kwargs``. +/*[clinic input] +_interpreters.new_config + + name: str(c_default="NULL") = 'isolated' + / + **overrides: dict + +Return a representation of a new PyInterpreterConfig. + +The name determines the initial values of the config. Supported named +configs are: default, isolated, legacy, and empty. + +Any keyword arguments are set on the corresponding config fields, +overriding the initial values. +[clinic start generated code]*/ + static PyObject * -interp_new_config(PyObject *self, PyObject *args, PyObject *kwds) +_interpreters_new_config_impl(PyObject *module, const char *name, + PyObject *overrides) +/*[clinic end generated code: output=90ca53e5c8f66e31 input=67a5a2832894a72b]*/ { - const char *name = NULL; - if (!PyArg_ParseTuple(args, "|s:" MODULE_NAME_STR ".new_config", &name)) - { - return NULL; - } - PyObject *overrides = kwds; - PyInterpreterConfig config; if (init_named_config(&config, name) < 0) { return NULL; } - if (overrides != NULL && PyDict_GET_SIZE(overrides) > 0) { + if (PyDict_GET_SIZE(overrides) > 0) { if (_PyInterpreterConfig_UpdateFromDict(&config, overrides) < 0) { return NULL; } @@ -834,18 +844,6 @@ interp_new_config(PyObject *self, PyObject *args, PyObject *kwds) return configobj; } -PyDoc_STRVAR(new_config_doc, -"new_config($module, name='isolated', /, **overrides)\n\ ---\n\ -\n\ -Return a representation of a new PyInterpreterConfig.\n\ -\n\ -The name determines the initial values of the config. Supported named\n\ -configs are: default, isolated, legacy, and empty.\n\ -\n\ -Any keyword arguments are set on the corresponding config fields,\n\ -overriding the initial values."); - /*[clinic input] _interpreters.create @@ -1558,8 +1556,7 @@ _interpreters_capture_exception_impl(PyObject *module, PyObject *exc_arg) static PyMethodDef module_functions[] = { - {"new_config", _PyCFunction_CAST(interp_new_config), - METH_VARARGS | METH_KEYWORDS, new_config_doc}, + _INTERPRETERS_NEW_CONFIG_METHODDEF _INTERPRETERS_CREATE_METHODDEF _INTERPRETERS_DESTROY_METHODDEF diff --git a/Modules/_sre/clinic/sre.c.h b/Modules/_sre/clinic/sre.c.h index b49bf4e058b69b..9e6c91d09f59a4 100644 --- a/Modules/_sre/clinic/sre.c.h +++ b/Modules/_sre/clinic/sre.c.h @@ -1247,6 +1247,35 @@ _sre_SRE_Match_expand(PyObject *self, PyObject *const *args, Py_ssize_t nargs, P return return_value; } +PyDoc_STRVAR(_sre_SRE_Match_group__doc__, +"group($self, /, *args)\n" +"--\n" +"\n" +"Return subgroup(s) of the match by indices or names.\n" +"\n" +"For 0 returns the entire match."); + +#define _SRE_SRE_MATCH_GROUP_METHODDEF \ + {"group", _PyCFunction_CAST(_sre_SRE_Match_group), METH_FASTCALL, _sre_SRE_Match_group__doc__}, + +static PyObject * +_sre_SRE_Match_group_impl(MatchObject *self, PyObject * const *args, + Py_ssize_t args_length); + +static PyObject * +_sre_SRE_Match_group(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject * const *__clinic_args; + Py_ssize_t args_length; + + __clinic_args = args; + args_length = nargs; + return_value = _sre_SRE_Match_group_impl((MatchObject *)self, __clinic_args, args_length); + + return return_value; +} + PyDoc_STRVAR(_sre_SRE_Match_groups__doc__, "groups($self, /, default=None)\n" "--\n" @@ -1568,4 +1597,4 @@ _sre_SRE_Scanner_search(PyObject *self, PyTypeObject *cls, PyObject *const *args #ifndef _SRE_SRE_PATTERN__FAIL_AFTER_METHODDEF #define _SRE_SRE_PATTERN__FAIL_AFTER_METHODDEF #endif /* !defined(_SRE_SRE_PATTERN__FAIL_AFTER_METHODDEF) */ -/*[clinic end generated code: output=0c867efb64e020aa input=a9049054013a1b77]*/ +/*[clinic end generated code: output=2e6c222a2eb0875e input=a9049054013a1b77]*/ diff --git a/Modules/_sre/sre.c b/Modules/_sre/sre.c index 031e972aeba031..47c2c4abc3ef24 100644 --- a/Modules/_sre/sre.c +++ b/Modules/_sre/sre.c @@ -2610,31 +2610,38 @@ _sre_SRE_Match_expand_impl(MatchObject *self, PyObject *template) return result; } -static PyObject* -match_group(PyObject *op, PyObject* args) +/*[clinic input] +_sre.SRE_Match.group + + *args: array + +Return subgroup(s) of the match by indices or names. + +For 0 returns the entire match. +[clinic start generated code]*/ + +static PyObject * +_sre_SRE_Match_group_impl(MatchObject *self, PyObject * const *args, + Py_ssize_t args_length) +/*[clinic end generated code: output=240cddd2cf62ee2a input=f6d9bfa0d01f3cda]*/ { - MatchObject *self = _MatchObject_CAST(op); PyObject* result; - Py_ssize_t i, size; - - size = PyTuple_GET_SIZE(args); + Py_ssize_t i; - switch (size) { + switch (args_length) { case 0: result = match_getslice(self, _PyLong_GetZero(), Py_None); break; case 1: - result = match_getslice(self, PyTuple_GET_ITEM(args, 0), Py_None); + result = match_getslice(self, args[0], Py_None); break; default: /* fetch multiple items */ - result = PyTuple_New(size); + result = PyTuple_New(args_length); if (!result) return NULL; - for (i = 0; i < size; i++) { - PyObject* item = match_getslice( - self, PyTuple_GET_ITEM(args, i), Py_None - ); + for (i = 0; i < args_length; i++) { + PyObject* item = match_getslice(self, args[i], Py_None); if (!item) { Py_DECREF(result); return NULL; @@ -2876,11 +2883,6 @@ PyDoc_STRVAR(match_doc, "The result of re.search(), re.prefixmatch(), and re.fullmatch().\n\ Match objects always have a boolean value of True."); -PyDoc_STRVAR(match_group_doc, -"group([group1, ...]) -> str or tuple.\n\ - Return subgroup(s) of the match by indices or names.\n\ - For 0 returns the entire match."); - static PyObject * match_lastindex_get(PyObject *op, void *Py_UNUSED(ignored)) { @@ -3436,7 +3438,7 @@ static PyType_Spec pattern_spec = { }; static PyMethodDef match_methods[] = { - {"group", match_group, METH_VARARGS, match_group_doc}, + _SRE_SRE_MATCH_GROUP_METHODDEF _SRE_SRE_MATCH_START_METHODDEF _SRE_SRE_MATCH_END_METHODDEF _SRE_SRE_MATCH_SPAN_METHODDEF diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 746c39e6d3f4a2..cff855d61cdbda 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -1690,14 +1690,21 @@ Tkapp_CallProc(Tcl_Event *evPtr, int flags) interpreter thread, so we ship the PyObject* args to the target thread, and perform processing there. */ +/*[clinic input] +_tkinter.tkapp.call + + *args: tuple + +[clinic start generated code]*/ + static PyObject * -Tkapp_Call(PyObject *selfptr, PyObject *args) +_tkinter_tkapp_call_impl(TkappObject *self, PyObject *args) +/*[clinic end generated code: output=2af3af48d1927065 input=60052dc395d80297]*/ { Tcl_Obj *objStore[ARGSZ]; Tcl_Obj **objv = NULL; Tcl_Size objc; PyObject *res = NULL; - TkappObject *self = TkappObject_CAST(selfptr); int flags = TCL_EVAL_DIRECT | TCL_EVAL_GLOBAL; /* If args is a single tuple, replace with contents of tuple */ @@ -3231,18 +3238,23 @@ _tkinter_tkapp_loadtk_impl(TkappObject *self) Py_RETURN_NONE; } +/*[clinic input] +_tkinter.tkapp.wantobjects + + value: int = -1 + / + +Return the current setting, or set it if the argument is not -1. +[clinic start generated code]*/ + static PyObject * -Tkapp_WantObjects(PyObject *op, PyObject *args) +_tkinter_tkapp_wantobjects_impl(TkappObject *self, int value) +/*[clinic end generated code: output=10ce2bffa4adb3a4 input=69a4045e2c202385]*/ { - TkappObject *self = TkappObject_CAST(op); - int wantobjects = -1; - if (!PyArg_ParseTuple(args, "|i:wantobjects", &wantobjects)) { - return NULL; - } - if (wantobjects == -1) { + if (value == -1) { return PyLong_FromLong(self->wantobjects); } - self->wantobjects = wantobjects; + self->wantobjects = value; Py_RETURN_NONE; } @@ -3580,10 +3592,10 @@ static PyType_Spec Tktt_Type_spec = { static PyMethodDef Tkapp_methods[] = { _TKINTER_TKAPP_WILLDISPATCH_METHODDEF - {"wantobjects", Tkapp_WantObjects, METH_VARARGS}, + _TKINTER_TKAPP_WANTOBJECTS_METHODDEF _TKINTER_TKAPP_SETTRACE_METHODDEF _TKINTER_TKAPP_GETTRACE_METHODDEF - {"call", Tkapp_Call, METH_VARARGS}, + _TKINTER_TKAPP_CALL_METHODDEF _TKINTER_TKAPP_EVAL_METHODDEF _TKINTER_TKAPP_EVALFILE_METHODDEF _TKINTER_TKAPP_RECORD_METHODDEF diff --git a/Modules/_zoneinfo.c b/Modules/_zoneinfo.c index 56ccabbea0ab48..46ab3499e00354 100644 --- a/Modules/_zoneinfo.c +++ b/Modules/_zoneinfo.c @@ -2619,9 +2619,21 @@ initialize_caches(zoneinfo_state *state) return 0; } +/*[clinic input] +@classmethod +zoneinfo.ZoneInfo.__init_subclass__ + + **kwargs: dict + +Function to initialize subclasses. +[clinic start generated code]*/ + static PyObject * -zoneinfo_init_subclass(PyObject *cls, PyObject *args, PyObject *kwargs) +zoneinfo_ZoneInfo___init_subclass___impl(PyTypeObject *type, + PyObject *kwargs) +/*[clinic end generated code: output=05b20743d42252f1 input=fd2e4b35d6ab1397]*/ { + PyObject *cls = (PyObject *)type; PyObject *weak_cache = new_weak_cache(); if (weak_cache == NULL) { return NULL; @@ -2651,9 +2663,7 @@ static PyMethodDef zoneinfo_methods[] = { {"__reduce__", zoneinfo_reduce, METH_NOARGS, PyDoc_STR("Function for serialization with the pickle protocol.")}, ZONEINFO_ZONEINFO__UNPICKLE_METHODDEF - {"__init_subclass__", _PyCFunction_CAST(zoneinfo_init_subclass), - METH_VARARGS | METH_KEYWORDS | METH_CLASS, - PyDoc_STR("Function to initialize subclasses.")}, + ZONEINFO_ZONEINFO___INIT_SUBCLASS___METHODDEF {NULL} /* Sentinel */ }; diff --git a/Modules/atexitmodule.c b/Modules/atexitmodule.c index 177b09d3dafbd9..b835fe670938cb 100644 --- a/Modules/atexitmodule.c +++ b/Modules/atexitmodule.c @@ -12,6 +12,13 @@ #include "pycore_interp.h" // PyInterpreterState.atexit #include "pycore_pystate.h" // _PyInterpreterState_GET +/*[clinic input] +module atexit +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=ac8fd67d15bf23fc]*/ + +#include "clinic/atexitmodule.c.h" + /* ===================================================================== */ /* Callback machinery. */ @@ -157,45 +164,34 @@ _PyAtExit_Call(PyInterpreterState *interp) /* Module methods. */ -PyDoc_STRVAR(atexit_register__doc__, -"register($module, func, /, *args, **kwargs)\n\ ---\n\ -\n\ -Register a function to be executed upon normal program termination\n\ -\n\ - func - function to be called at exit\n\ - args - optional arguments to pass to func\n\ - kwargs - optional keyword arguments to pass to func\n\ -\n\ - func is returned to facilitate usage as a decorator."); +/*[clinic input] +atexit.register + + func: object + / + *args: tuple + **kwargs: dict + +Register a function to be executed upon normal program termination + + func - function to be called at exit + args - optional arguments to pass to func + kwargs - optional keyword arguments to pass to func + + func is returned to facilitate usage as a decorator. +[clinic start generated code]*/ static PyObject * -atexit_register(PyObject *module, PyObject *args, PyObject *kwargs) +atexit_register_impl(PyObject *module, PyObject *func, PyObject *args, + PyObject *kwargs) +/*[clinic end generated code: output=c921286994bd8612 input=a682b5a343a82e4a]*/ { - if (PyTuple_GET_SIZE(args) == 0) { - PyErr_SetString(PyExc_TypeError, - "register() takes at least 1 argument (0 given)"); - return NULL; - } - - PyObject *func = PyTuple_GET_ITEM(args, 0); if (!PyCallable_Check(func)) { PyErr_SetString(PyExc_TypeError, "the first argument must be callable"); return NULL; } - PyObject *func_args = PyTuple_GetSlice(args, 1, PyTuple_GET_SIZE(args)); - if (func_args == NULL) { - return NULL; - } - PyObject *func_kwargs = kwargs; - - if (func_kwargs == NULL) - { - func_kwargs = Py_None; - } - PyObject *callback = PyTuple_Pack(3, func, func_args, func_kwargs); - Py_DECREF(func_args); + PyObject *callback = PyTuple_Pack(3, func, args, kwargs); if (callback == NULL) { return NULL; @@ -318,8 +314,7 @@ atexit_unregister(PyObject *module, PyObject *func) static PyMethodDef atexit_methods[] = { - {"register", _PyCFunction_CAST(atexit_register), METH_VARARGS|METH_KEYWORDS, - atexit_register__doc__}, + ATEXIT_REGISTER_METHODDEF {"_clear", atexit_clear, METH_NOARGS, atexit_clear__doc__}, {"unregister", atexit_unregister, METH_O, atexit_unregister__doc__}, {"_run_exitfuncs", atexit_run_exitfuncs, METH_NOARGS, diff --git a/Modules/clinic/_dbmmodule.c.h b/Modules/clinic/_dbmmodule.c.h index 6c979a4b0081df..ec6c1df4f32d9f 100644 --- a/Modules/clinic/_dbmmodule.c.h +++ b/Modules/clinic/_dbmmodule.c.h @@ -185,6 +185,35 @@ _dbm_dbm_clear(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssiz return return_value; } +PyDoc_STRVAR(_dbm_dbm___exit____doc__, +"__exit__($self, /, *exc_info)\n" +"--\n" +"\n" +"Close the database."); + +#define _DBM_DBM___EXIT___METHODDEF \ + {"__exit__", _PyCFunction_CAST(_dbm_dbm___exit__), METH_FASTCALL, _dbm_dbm___exit____doc__}, + +static PyObject * +_dbm_dbm___exit___impl(dbmobject *self, PyObject * const *exc_info, + Py_ssize_t exc_info_length); + +static PyObject * +_dbm_dbm___exit__(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject * const *exc_info; + Py_ssize_t exc_info_length; + + exc_info = args; + exc_info_length = nargs; + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _dbm_dbm___exit___impl((dbmobject *)self, exc_info, exc_info_length); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + PyDoc_STRVAR(dbmopen__doc__, "open($module, filename, flags=\'r\', mode=0o666, /)\n" "--\n" @@ -247,4 +276,4 @@ dbmopen(PyObject *module, PyObject *const *args, Py_ssize_t nargs) exit: return return_value; } -/*[clinic end generated code: output=677deecf525167a5 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=0a53988f7d8beec4 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_elementtree.c.h b/Modules/clinic/_elementtree.c.h index a39e738ec538b6..132f5c800b96ed 100644 --- a/Modules/clinic/_elementtree.c.h +++ b/Modules/clinic/_elementtree.c.h @@ -7,7 +7,66 @@ preserve # include "pycore_runtime.h" // _Py_SINGLETON() #endif #include "pycore_abstract.h" // _PyNumber_Index() -#include "pycore_modsupport.h" // _PyArg_UnpackKeywords() +#include "pycore_modsupport.h" // _PyArg_CheckPositional() + +PyDoc_STRVAR(_elementtree_SubElement__doc__, +"SubElement($module, parent, tag, attrib={}, /, **extra)\n" +"--\n" +"\n" +"Create a new subelement of the parent element."); + +#define _ELEMENTTREE_SUBELEMENT_METHODDEF \ + {"SubElement", _PyCFunction_CAST(_elementtree_SubElement), METH_VARARGS|METH_KEYWORDS, _elementtree_SubElement__doc__}, + +static PyObject * +_elementtree_SubElement_impl(PyObject *module, PyObject *parent, + PyObject *tag, PyObject *attrib, + PyObject *extra); + +static PyObject * +_elementtree_SubElement(PyObject *module, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + PyObject *parent; + PyObject *tag; + PyObject *attrib = NULL; + PyObject *extra = NULL; + + if (!_PyArg_CheckPositional("SubElement", PyTuple_GET_SIZE(args), 2, 3)) { + goto exit; + } + if (!PyObject_TypeCheck(PyTuple_GET_ITEM(args, 0), get_elementtree_state(module)->Element_Type)) { + _PyArg_BadArgument("SubElement", "argument 1", (get_elementtree_state(module)->Element_Type)->tp_name, PyTuple_GET_ITEM(args, 0)); + goto exit; + } + parent = PyTuple_GET_ITEM(args, 0); + tag = PyTuple_GET_ITEM(args, 1); + if (PyTuple_GET_SIZE(args) < 3) { + goto skip_optional; + } + if (!PyDict_Check(PyTuple_GET_ITEM(args, 2))) { + _PyArg_BadArgument("SubElement", "argument 3", "dict", PyTuple_GET_ITEM(args, 2)); + goto exit; + } + attrib = PyTuple_GET_ITEM(args, 2); +skip_optional: + if (kwargs == NULL) { + extra = PyDict_New(); + if (extra == NULL) { + goto exit; + } + } + else { + extra = Py_NewRef(kwargs); + } + return_value = _elementtree_SubElement_impl(module, parent, tag, attrib, extra); + +exit: + /* Cleanup for extra */ + Py_XDECREF(extra); + + return return_value; +} PyDoc_STRVAR(_elementtree_Element_append__doc__, "append($self, subelement, /)\n" @@ -1479,4 +1538,4 @@ _elementtree_XMLParser__setevents(PyObject *self, PyObject *const *args, Py_ssiz exit: return return_value; } -/*[clinic end generated code: output=e2e9cf288c4400f6 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=7a0ff4b8cc3838c1 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_functoolsmodule.c.h b/Modules/clinic/_functoolsmodule.c.h index 5f350c864f057b..b09653fe5d4ef8 100644 --- a/Modules/clinic/_functoolsmodule.c.h +++ b/Modules/clinic/_functoolsmodule.c.h @@ -193,4 +193,31 @@ _functools__lru_cache_wrapper_cache_clear(PyObject *self, PyObject *Py_UNUSED(ig return return_value; } -/*[clinic end generated code: output=6d8fdaeba4b520fa input=a9049054013a1b77]*/ + +PyDoc_STRVAR(_functools__lru_cache_wrapper___copy____doc__, +"__copy__($self, /)\n" +"--\n" +"\n" +"Return a copy of the wrapper, which is the wrapper itself."); + +#define _FUNCTOOLS__LRU_CACHE_WRAPPER___COPY___METHODDEF \ + {"__copy__", (PyCFunction)_functools__lru_cache_wrapper___copy__, METH_NOARGS, _functools__lru_cache_wrapper___copy____doc__}, + +static PyObject * +_functools__lru_cache_wrapper___copy___impl(PyObject *self); + +static PyObject * +_functools__lru_cache_wrapper___copy__(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _functools__lru_cache_wrapper___copy___impl(self); +} + +PyDoc_STRVAR(_functools__lru_cache_wrapper___deepcopy____doc__, +"__deepcopy__($self, memo, /)\n" +"--\n" +"\n" +"Return a deep copy of the wrapper, which is the wrapper itself."); + +#define _FUNCTOOLS__LRU_CACHE_WRAPPER___DEEPCOPY___METHODDEF \ + {"__deepcopy__", (PyCFunction)_functools__lru_cache_wrapper___deepcopy__, METH_O, _functools__lru_cache_wrapper___deepcopy____doc__}, +/*[clinic end generated code: output=9af090694f03b4f2 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_gdbmmodule.c.h b/Modules/clinic/_gdbmmodule.c.h index fe993cc328fbd2..14903bfb2e9fa6 100644 --- a/Modules/clinic/_gdbmmodule.c.h +++ b/Modules/clinic/_gdbmmodule.c.h @@ -314,6 +314,35 @@ _gdbm_gdbm_clear(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ss return return_value; } +PyDoc_STRVAR(_gdbm_gdbm___exit____doc__, +"__exit__($self, /, *exc_info)\n" +"--\n" +"\n" +"Close the database."); + +#define _GDBM_GDBM___EXIT___METHODDEF \ + {"__exit__", _PyCFunction_CAST(_gdbm_gdbm___exit__), METH_FASTCALL, _gdbm_gdbm___exit____doc__}, + +static PyObject * +_gdbm_gdbm___exit___impl(gdbmobject *self, PyObject * const *exc_info, + Py_ssize_t exc_info_length); + +static PyObject * +_gdbm_gdbm___exit__(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject * const *exc_info; + Py_ssize_t exc_info_length; + + exc_info = args; + exc_info_length = nargs; + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _gdbm_gdbm___exit___impl((gdbmobject *)self, exc_info, exc_info_length); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + PyDoc_STRVAR(dbmopen__doc__, "open($module, filename, flags=\'r\', mode=0o666, /)\n" "--\n" @@ -389,4 +418,4 @@ dbmopen(PyObject *module, PyObject *const *args, Py_ssize_t nargs) exit: return return_value; } -/*[clinic end generated code: output=429b5db24568292e input=a9049054013a1b77]*/ +/*[clinic end generated code: output=61360ce2c8ecc748 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_interpretersmodule.c.h b/Modules/clinic/_interpretersmodule.c.h index 72792f9b583a66..406dbca93e8581 100644 --- a/Modules/clinic/_interpretersmodule.c.h +++ b/Modules/clinic/_interpretersmodule.c.h @@ -6,7 +6,71 @@ preserve # include "pycore_gc.h" // PyGC_Head # include "pycore_runtime.h" // _Py_ID() #endif -#include "pycore_modsupport.h" // _PyArg_UnpackKeywords() +#include "pycore_modsupport.h" // _PyArg_CheckPositional() + +PyDoc_STRVAR(_interpreters_new_config__doc__, +"new_config($module, name=\'isolated\', /, **overrides)\n" +"--\n" +"\n" +"Return a representation of a new PyInterpreterConfig.\n" +"\n" +"The name determines the initial values of the config. Supported named\n" +"configs are: default, isolated, legacy, and empty.\n" +"\n" +"Any keyword arguments are set on the corresponding config fields,\n" +"overriding the initial values."); + +#define _INTERPRETERS_NEW_CONFIG_METHODDEF \ + {"new_config", _PyCFunction_CAST(_interpreters_new_config), METH_VARARGS|METH_KEYWORDS, _interpreters_new_config__doc__}, + +static PyObject * +_interpreters_new_config_impl(PyObject *module, const char *name, + PyObject *overrides); + +static PyObject * +_interpreters_new_config(PyObject *module, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + const char *name = NULL; + PyObject *overrides = NULL; + + if (!_PyArg_CheckPositional("new_config", PyTuple_GET_SIZE(args), 0, 1)) { + goto exit; + } + if (PyTuple_GET_SIZE(args) < 1) { + goto skip_optional; + } + if (!PyUnicode_Check(PyTuple_GET_ITEM(args, 0))) { + _PyArg_BadArgument("new_config", "argument 1", "str", PyTuple_GET_ITEM(args, 0)); + goto exit; + } + Py_ssize_t name_length; + name = PyUnicode_AsUTF8AndSize(PyTuple_GET_ITEM(args, 0), &name_length); + if (name == NULL) { + goto exit; + } + if (strlen(name) != (size_t)name_length) { + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } +skip_optional: + if (kwargs == NULL) { + overrides = PyDict_New(); + if (overrides == NULL) { + goto exit; + } + } + else { + overrides = Py_NewRef(kwargs); + } + return_value = _interpreters_new_config_impl(module, name, overrides); + +exit: + /* Cleanup for overrides */ + Py_XDECREF(overrides); + + return return_value; +} PyDoc_STRVAR(_interpreters_create__doc__, "create($module, /, config=\'isolated\', *, reqrefs=False)\n" @@ -1200,4 +1264,4 @@ _interpreters_capture_exception(PyObject *module, PyObject *const *args, Py_ssiz exit: return return_value; } -/*[clinic end generated code: output=8c3ca09c304378ad input=a9049054013a1b77]*/ +/*[clinic end generated code: output=38892db3b955efbb input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_tkinter.c.h b/Modules/clinic/_tkinter.c.h index 3147cf7f9d2cff..21ae39737a1810 100644 --- a/Modules/clinic/_tkinter.c.h +++ b/Modules/clinic/_tkinter.c.h @@ -4,6 +4,36 @@ preserve #include "pycore_modsupport.h" // _PyArg_BadArgument() +PyDoc_STRVAR(_tkinter_tkapp_call__doc__, +"call($self, /, *args)\n" +"--\n" +"\n"); + +#define _TKINTER_TKAPP_CALL_METHODDEF \ + {"call", _PyCFunction_CAST(_tkinter_tkapp_call), METH_FASTCALL, _tkinter_tkapp_call__doc__}, + +static PyObject * +_tkinter_tkapp_call_impl(TkappObject *self, PyObject *args); + +static PyObject * +_tkinter_tkapp_call(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *__clinic_args = NULL; + + __clinic_args = PyTuple_FromArray(args, nargs); + if (__clinic_args == NULL) { + goto exit; + } + return_value = _tkinter_tkapp_call_impl((TkappObject *)self, __clinic_args); + +exit: + /* Cleanup for args */ + Py_XDECREF(__clinic_args); + + return return_value; +} + PyDoc_STRVAR(_tkinter_tkapp_eval__doc__, "eval($self, script, /)\n" "--\n" @@ -687,6 +717,41 @@ _tkinter_tkapp_loadtk(PyObject *self, PyObject *Py_UNUSED(ignored)) return _tkinter_tkapp_loadtk_impl((TkappObject *)self); } +PyDoc_STRVAR(_tkinter_tkapp_wantobjects__doc__, +"wantobjects($self, value=-1, /)\n" +"--\n" +"\n" +"Return the current setting, or set it if the argument is not -1."); + +#define _TKINTER_TKAPP_WANTOBJECTS_METHODDEF \ + {"wantobjects", _PyCFunction_CAST(_tkinter_tkapp_wantobjects), METH_FASTCALL, _tkinter_tkapp_wantobjects__doc__}, + +static PyObject * +_tkinter_tkapp_wantobjects_impl(TkappObject *self, int value); + +static PyObject * +_tkinter_tkapp_wantobjects(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + int value = -1; + + if (!_PyArg_CheckPositional("wantobjects", nargs, 0, 1)) { + goto exit; + } + if (nargs < 1) { + goto skip_optional; + } + value = PyLong_AsInt(args[0]); + if (value == -1 && PyErr_Occurred()) { + goto exit; + } +skip_optional: + return_value = _tkinter_tkapp_wantobjects_impl((TkappObject *)self, value); + +exit: + return return_value; +} + PyDoc_STRVAR(_tkinter_tkapp_settrace__doc__, "settrace($self, func, /)\n" "--\n" @@ -967,4 +1032,4 @@ _tkinter_getbusywaitinterval(PyObject *module, PyObject *Py_UNUSED(ignored)) #ifndef _TKINTER_TKAPP_DELETEFILEHANDLER_METHODDEF #define _TKINTER_TKAPP_DELETEFILEHANDLER_METHODDEF #endif /* !defined(_TKINTER_TKAPP_DELETEFILEHANDLER_METHODDEF) */ -/*[clinic end generated code: output=c807adb73e305725 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=bb55a7d4c5a8a002 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_zoneinfo.c.h b/Modules/clinic/_zoneinfo.c.h index 19564a6c13f246..d5faa34c6b22cc 100644 --- a/Modules/clinic/_zoneinfo.c.h +++ b/Modules/clinic/_zoneinfo.c.h @@ -454,4 +454,44 @@ zoneinfo_ZoneInfo__unpickle(PyObject *type, PyTypeObject *cls, PyObject *const * exit: return return_value; } -/*[clinic end generated code: output=c6df04d7b400bd7f input=a9049054013a1b77]*/ + +PyDoc_STRVAR(zoneinfo_ZoneInfo___init_subclass____doc__, +"__init_subclass__($type, /, **kwargs)\n" +"--\n" +"\n" +"Function to initialize subclasses."); + +#define ZONEINFO_ZONEINFO___INIT_SUBCLASS___METHODDEF \ + {"__init_subclass__", _PyCFunction_CAST(zoneinfo_ZoneInfo___init_subclass__), METH_VARARGS|METH_KEYWORDS|METH_CLASS, zoneinfo_ZoneInfo___init_subclass____doc__}, + +static PyObject * +zoneinfo_ZoneInfo___init_subclass___impl(PyTypeObject *type, + PyObject *kwargs); + +static PyObject * +zoneinfo_ZoneInfo___init_subclass__(PyObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + PyObject *__clinic_kwargs = NULL; + + if (!_PyArg_NoPositional("__init_subclass__", args)) { + goto exit; + } + if (kwargs == NULL) { + __clinic_kwargs = PyDict_New(); + if (__clinic_kwargs == NULL) { + goto exit; + } + } + else { + __clinic_kwargs = Py_NewRef(kwargs); + } + return_value = zoneinfo_ZoneInfo___init_subclass___impl((PyTypeObject *)type, __clinic_kwargs); + +exit: + /* Cleanup for kwargs */ + Py_XDECREF(__clinic_kwargs); + + return return_value; +} +/*[clinic end generated code: output=72997ab6d06a94f6 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/atexitmodule.c.h b/Modules/clinic/atexitmodule.c.h new file mode 100644 index 00000000000000..9afa3a15a29614 --- /dev/null +++ b/Modules/clinic/atexitmodule.c.h @@ -0,0 +1,61 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +#include "pycore_modsupport.h" // _PyArg_CheckPositional() + +PyDoc_STRVAR(atexit_register__doc__, +"register($module, func, /, *args, **kwargs)\n" +"--\n" +"\n" +"Register a function to be executed upon normal program termination\n" +"\n" +" func - function to be called at exit\n" +" args - optional arguments to pass to func\n" +" kwargs - optional keyword arguments to pass to func\n" +"\n" +" func is returned to facilitate usage as a decorator."); + +#define ATEXIT_REGISTER_METHODDEF \ + {"register", _PyCFunction_CAST(atexit_register), METH_VARARGS|METH_KEYWORDS, atexit_register__doc__}, + +static PyObject * +atexit_register_impl(PyObject *module, PyObject *func, PyObject *args, + PyObject *kwargs); + +static PyObject * +atexit_register(PyObject *module, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + PyObject *func; + PyObject *__clinic_args = NULL; + PyObject *__clinic_kwargs = NULL; + + if (!_PyArg_CheckPositional("register", PyTuple_GET_SIZE(args), 1, PY_SSIZE_T_MAX)) { + goto exit; + } + func = PyTuple_GET_ITEM(args, 0); + __clinic_args = PyTuple_GetSlice(args, 1, PY_SSIZE_T_MAX); + if (!__clinic_args) { + goto exit; + } + if (kwargs == NULL) { + __clinic_kwargs = PyDict_New(); + if (__clinic_kwargs == NULL) { + goto exit; + } + } + else { + __clinic_kwargs = Py_NewRef(kwargs); + } + return_value = atexit_register_impl(module, func, __clinic_args, __clinic_kwargs); + +exit: + /* Cleanup for args */ + Py_XDECREF(__clinic_args); + /* Cleanup for kwargs */ + Py_XDECREF(__clinic_kwargs); + + return return_value; +} +/*[clinic end generated code: output=8fd8f691fdbc4e0a input=a9049054013a1b77]*/ diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h index 7c8171c04c0727..46e223a06626d8 100644 --- a/Modules/clinic/posixmodule.c.h +++ b/Modules/clinic/posixmodule.c.h @@ -12443,6 +12443,33 @@ os_DirEntry___fspath__(PyObject *self, PyObject *Py_UNUSED(ignored)) return os_DirEntry___fspath___impl((DirEntry *)self); } +PyDoc_STRVAR(os_ScandirIterator___exit____doc__, +"__exit__($self, /, *exc_info)\n" +"--\n" +"\n" +"Close the scandir iterator."); + +#define OS_SCANDIRITERATOR___EXIT___METHODDEF \ + {"__exit__", _PyCFunction_CAST(os_ScandirIterator___exit__), METH_FASTCALL, os_ScandirIterator___exit____doc__}, + +static PyObject * +os_ScandirIterator___exit___impl(PyObject *self, PyObject * const *exc_info, + Py_ssize_t exc_info_length); + +static PyObject * +os_ScandirIterator___exit__(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject * const *exc_info; + Py_ssize_t exc_info_length; + + exc_info = args; + exc_info_length = nargs; + return_value = os_ScandirIterator___exit___impl(self, exc_info, exc_info_length); + + return return_value; +} + PyDoc_STRVAR(os_scandir__doc__, "scandir($module, /, path=None)\n" "--\n" @@ -13747,4 +13774,4 @@ os__emscripten_log(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py #ifndef OS__EMSCRIPTEN_LOG_METHODDEF #define OS__EMSCRIPTEN_LOG_METHODDEF #endif /* !defined(OS__EMSCRIPTEN_LOG_METHODDEF) */ -/*[clinic end generated code: output=d4e858cbdf280235 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=38edcd9b6f56b729 input=a9049054013a1b77]*/ diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index ead2371e341441..12ad333c5e5f27 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -16396,8 +16396,9 @@ os_set_blocking_impl(PyObject *module, int fd, int blocking) /*[clinic input] class os.DirEntry "DirEntry *" "DirEntryType" +class os.ScandirIterator "PyObject *" "ScandirIteratorType" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=3c18c7a448247980]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=b845e502eb4a0406]*/ typedef struct { PyObject_HEAD @@ -17286,11 +17287,20 @@ ScandirIterator_enter(PyObject *self, PyObject *Py_UNUSED(dummy)) return Py_NewRef(self); } +/*[clinic input] +os.ScandirIterator.__exit__ + + *exc_info: array + +Close the scandir iterator. +[clinic start generated code]*/ + static PyObject * -ScandirIterator_exit(PyObject *op, PyObject *Py_UNUSED(args)) +os_ScandirIterator___exit___impl(PyObject *self, PyObject * const *exc_info, + Py_ssize_t exc_info_length) +/*[clinic end generated code: output=5d3941725a7c97c7 input=ff3ffe83ae605a36]*/ { - ScandirIterator *self = ScandirIterator_CAST(op); - ScandirIterator_closedir(self); + ScandirIterator_closedir(ScandirIterator_CAST(self)); Py_RETURN_NONE; } @@ -17337,7 +17347,7 @@ ScandirIterator_dealloc(PyObject *op) static PyMethodDef ScandirIterator_methods[] = { {"__enter__", ScandirIterator_enter, METH_NOARGS}, - {"__exit__", ScandirIterator_exit, METH_VARARGS}, + OS_SCANDIRITERATOR___EXIT___METHODDEF {"close", ScandirIterator_close, METH_NOARGS}, {NULL} }; diff --git a/Objects/clinic/descrobject.c.h b/Objects/clinic/descrobject.c.h index a0cfbeca84db12..744e5edf922b57 100644 --- a/Objects/clinic/descrobject.c.h +++ b/Objects/clinic/descrobject.c.h @@ -65,6 +65,37 @@ mappingproxy_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) return return_value; } +PyDoc_STRVAR(property___set_name____doc__, +"__set_name__($self, owner, name, /)\n" +"--\n" +"\n" +"Method to set name of a property."); + +#define PROPERTY___SET_NAME___METHODDEF \ + {"__set_name__", _PyCFunction_CAST(property___set_name__), METH_FASTCALL, property___set_name____doc__}, + +static PyObject * +property___set_name___impl(propertyobject *self, PyObject *owner, + PyObject *name); + +static PyObject * +property___set_name__(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *owner; + PyObject *name; + + if (!_PyArg_CheckPositional("__set_name__", nargs, 2, 2)) { + goto exit; + } + owner = args[0]; + name = args[1]; + return_value = property___set_name___impl((propertyobject *)self, owner, name); + +exit: + return return_value; +} + PyDoc_STRVAR(property_init__doc__, "property(fget=None, fset=None, fdel=None, doc=None)\n" "--\n" @@ -179,4 +210,4 @@ property_init(PyObject *self, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=2e8df497abc4f915 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=fb62ee8be13af793 input=a9049054013a1b77]*/ diff --git a/Objects/clinic/fileobject.c.h b/Objects/clinic/fileobject.c.h new file mode 100644 index 00000000000000..8eb05b4f5a5d85 --- /dev/null +++ b/Objects/clinic/fileobject.c.h @@ -0,0 +1,35 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +#include "pycore_modsupport.h" // _PyArg_BadArgument() + +PyDoc_STRVAR(stdprinter_write__doc__, +"write($self, text, /)\n" +"--\n" +"\n" +"Write the text to the stream."); + +#define STDPRINTER_WRITE_METHODDEF \ + {"write", (PyCFunction)stdprinter_write, METH_O, stdprinter_write__doc__}, + +static PyObject * +stdprinter_write_impl(PyStdPrinter_Object *self, PyObject *unicode); + +static PyObject * +stdprinter_write(PyObject *self, PyObject *arg) +{ + PyObject *return_value = NULL; + PyObject *unicode; + + if (!PyUnicode_Check(arg)) { + _PyArg_BadArgument("write", "argument", "str", arg); + goto exit; + } + unicode = arg; + return_value = stdprinter_write_impl((PyStdPrinter_Object *)self, unicode); + +exit: + return return_value; +} +/*[clinic end generated code: output=7cf7d4c181518bbb input=a9049054013a1b77]*/ diff --git a/Objects/clinic/memoryobject.c.h b/Objects/clinic/memoryobject.c.h index d55e7c4ac47576..bccce41b13e137 100644 --- a/Objects/clinic/memoryobject.c.h +++ b/Objects/clinic/memoryobject.c.h @@ -147,6 +147,34 @@ memoryview_release(PyObject *self, PyObject *Py_UNUSED(ignored)) return memoryview_release_impl((PyMemoryViewObject *)self); } +PyDoc_STRVAR(memoryview___exit____doc__, +"__exit__($self, /, *exc_info)\n" +"--\n" +"\n" +"Release the underlying buffer exposed by the memoryview object."); + +#define MEMORYVIEW___EXIT___METHODDEF \ + {"__exit__", _PyCFunction_CAST(memoryview___exit__), METH_FASTCALL, memoryview___exit____doc__}, + +static PyObject * +memoryview___exit___impl(PyMemoryViewObject *self, + PyObject * const *exc_info, + Py_ssize_t exc_info_length); + +static PyObject * +memoryview___exit__(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject * const *exc_info; + Py_ssize_t exc_info_length; + + exc_info = args; + exc_info_length = nargs; + return_value = memoryview___exit___impl((PyMemoryViewObject *)self, exc_info, exc_info_length); + + return return_value; +} + PyDoc_STRVAR(memoryview_cast__doc__, "cast($self, /, format, shape=, *, order=\'C\')\n" "--\n" @@ -532,4 +560,4 @@ memoryview_index(PyObject *self, PyObject *const *args, Py_ssize_t nargs) exit: return return_value; } -/*[clinic end generated code: output=17a403895f4f778c input=a9049054013a1b77]*/ +/*[clinic end generated code: output=a597307395a568ef input=a9049054013a1b77]*/ diff --git a/Objects/clinic/namespaceobject.c.h b/Objects/clinic/namespaceobject.c.h new file mode 100644 index 00000000000000..cdd9ef586c79ec --- /dev/null +++ b/Objects/clinic/namespaceobject.c.h @@ -0,0 +1,45 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +#include "pycore_modsupport.h" // _PyArg_NoPositional() + +PyDoc_STRVAR(namespace___replace____doc__, +"__replace__($self, /, **changes)\n" +"--\n" +"\n" +"Return a copy with the specified attributes replaced."); + +#define NAMESPACE___REPLACE___METHODDEF \ + {"__replace__", _PyCFunction_CAST(namespace___replace__), METH_VARARGS|METH_KEYWORDS, namespace___replace____doc__}, + +static PyObject * +namespace___replace___impl(_PyNamespaceObject *self, PyObject *changes); + +static PyObject * +namespace___replace__(PyObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + PyObject *changes = NULL; + + if (!_PyArg_NoPositional("__replace__", args)) { + goto exit; + } + if (kwargs == NULL) { + changes = PyDict_New(); + if (changes == NULL) { + goto exit; + } + } + else { + changes = Py_NewRef(kwargs); + } + return_value = namespace___replace___impl((_PyNamespaceObject *)self, changes); + +exit: + /* Cleanup for changes */ + Py_XDECREF(changes); + + return return_value; +} +/*[clinic end generated code: output=67b5fcb6a6aee559 input=a9049054013a1b77]*/ diff --git a/Objects/clinic/structseq.c.h b/Objects/clinic/structseq.c.h index 9642b480fa18b9..f115f8ddcf490c 100644 --- a/Objects/clinic/structseq.c.h +++ b/Objects/clinic/structseq.c.h @@ -65,4 +65,43 @@ structseq_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=112d59f5e98d652b input=a9049054013a1b77]*/ + +PyDoc_STRVAR(structseq___replace____doc__, +"__replace__($self, /, **changes)\n" +"--\n" +"\n" +"Return a copy with new values for the specified fields."); + +#define STRUCTSEQ___REPLACE___METHODDEF \ + {"__replace__", _PyCFunction_CAST(structseq___replace__), METH_VARARGS|METH_KEYWORDS, structseq___replace____doc__}, + +static PyObject * +structseq___replace___impl(PyStructSequence *self, PyObject *changes); + +static PyObject * +structseq___replace__(PyObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + PyObject *changes = NULL; + + if (!_PyArg_NoPositional("__replace__", args)) { + goto exit; + } + if (kwargs == NULL) { + changes = PyDict_New(); + if (changes == NULL) { + goto exit; + } + } + else { + changes = Py_NewRef(kwargs); + } + return_value = structseq___replace___impl((PyStructSequence *)self, changes); + +exit: + /* Cleanup for changes */ + Py_XDECREF(changes); + + return return_value; +} +/*[clinic end generated code: output=18fcf88e5df26774 input=a9049054013a1b77]*/ diff --git a/Objects/descrobject.c b/Objects/descrobject.c index 8ceef648988167..0b2ab25050de49 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -19,6 +19,8 @@ class property "propertyobject *" "&PyProperty_Type" [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=556352653fd4c02e]*/ +#include "clinic/descrobject.c.h" + static void descr_dealloc(PyObject *self) { @@ -1618,26 +1620,22 @@ property_deleter(PyObject *self, PyObject *deleter) } -PyDoc_STRVAR(set_name_doc, - "__set_name__($self, owner, name, /)\n" - "--\n" - "\n" - "Method to set name of a property."); +/*[clinic input] +property.__set_name__ -static PyObject * -property_set_name(PyObject *self, PyObject *args) { - if (PyTuple_GET_SIZE(args) != 2) { - PyErr_Format( - PyExc_TypeError, - "__set_name__() takes 2 positional arguments but %zd were given", - PyTuple_GET_SIZE(args)); - return NULL; - } + owner: object + name: object + / - propertyobject *prop = (propertyobject *)self; - PyObject *name = PyTuple_GET_ITEM(args, 1); +Method to set name of a property. +[clinic start generated code]*/ - Py_XSETREF(prop->prop_name, Py_XNewRef(name)); +static PyObject * +property___set_name___impl(propertyobject *self, PyObject *owner, + PyObject *name) +/*[clinic end generated code: output=959e301a91f7fb85 input=0211b5b7ace099c5]*/ +{ + Py_XSETREF(self->prop_name, Py_XNewRef(name)); Py_RETURN_NONE; } @@ -1646,7 +1644,7 @@ static PyMethodDef property_methods[] = { {"getter", property_getter, METH_O, getter_doc}, {"setter", property_setter, METH_O, setter_doc}, {"deleter", property_deleter, METH_O, deleter_doc}, - {"__set_name__", property_set_name, METH_VARARGS, set_name_doc}, + PROPERTY___SET_NAME___METHODDEF {0} }; @@ -2014,7 +2012,6 @@ property_clear(PyObject *self) return 0; } -#include "clinic/descrobject.c.h" PyTypeObject PyDictProxy_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) diff --git a/Objects/fileobject.c b/Objects/fileobject.c index d5cdea1410b46a..79aa8889c1aa4f 100644 --- a/Objects/fileobject.c +++ b/Objects/fileobject.c @@ -297,6 +297,13 @@ typedef struct { int fd; } PyStdPrinter_Object; +/*[clinic input] +class stdprinter "PyStdPrinter_Object *" "&PyStdPrinter_Type" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=031bf557c18c5df5]*/ + +#include "clinic/fileobject.c.h" + PyObject * PyFile_NewStdPrinter(int fd) { @@ -315,11 +322,19 @@ PyFile_NewStdPrinter(int fd) return (PyObject*)self; } +/*[clinic input] +stdprinter.write + + text as unicode: unicode + / + +Write the text to the stream. +[clinic start generated code]*/ + static PyObject * -stdprinter_write(PyObject *op, PyObject *args) +stdprinter_write_impl(PyStdPrinter_Object *self, PyObject *unicode) +/*[clinic end generated code: output=069c9645803fe8ad input=65041d6d7a23aff4]*/ { - PyStdPrinter_Object *self = (PyStdPrinter_Object*)op; - PyObject *unicode; PyObject *bytes = NULL; const char *str; Py_ssize_t n; @@ -336,10 +351,6 @@ stdprinter_write(PyObject *op, PyObject *args) Py_RETURN_NONE; } - if (!PyArg_ParseTuple(args, "U", &unicode)) { - return NULL; - } - /* Encode Unicode to UTF-8/backslashreplace */ str = PyUnicode_AsUTF8AndSize(unicode, &n); if (str == NULL) { @@ -410,7 +421,7 @@ static PyMethodDef stdprinter_methods[] = { {"flush", stdprinter_noop, METH_NOARGS, ""}, {"fileno", stdprinter_fileno, METH_NOARGS, ""}, {"isatty", stdprinter_isatty, METH_NOARGS, ""}, - {"write", stdprinter_write, METH_VARARGS, ""}, + STDPRINTER_WRITE_METHODDEF {NULL, NULL} /*sentinel */ }; diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c index f419795d1eb3ca..5a8ae6ad149a75 100644 --- a/Objects/memoryobject.c +++ b/Objects/memoryobject.c @@ -1186,10 +1186,21 @@ memory_enter(PyObject *self, PyObject *args) return Py_NewRef(self); } +/*[clinic input] +memoryview.__exit__ + + *exc_info: array + +Release the underlying buffer exposed by the memoryview object. +[clinic start generated code]*/ + static PyObject * -memory_exit(PyObject *self, PyObject *args) +memoryview___exit___impl(PyMemoryViewObject *self, + PyObject * const *exc_info, + Py_ssize_t exc_info_length) +/*[clinic end generated code: output=c055c4c69baf495d input=881969146ff4d413]*/ { - return memoryview_release_impl((PyMemoryViewObject *)self); + return memoryview_release_impl(self); } @@ -3570,11 +3581,6 @@ PyDoc_STRVAR(memory_f_contiguous_doc, "A bool indicating whether the memory is Fortran contiguous."); PyDoc_STRVAR(memory_contiguous_doc, "A bool indicating whether the memory is contiguous."); -PyDoc_STRVAR(memory_exit_doc, - "__exit__($self, /, *exc_info)\n--\n\n" - "Release the underlying buffer exposed by the memoryview object."); - - static PyGetSetDef memory_getsetlist[] = { {"obj", memory_obj_get, NULL, memory_obj_doc}, {"nbytes", memory_nbytes_get, NULL, memory_nbytes_doc}, @@ -3603,7 +3609,7 @@ static PyMethodDef memory_methods[] = { MEMORYVIEW_COUNT_METHODDEF MEMORYVIEW_INDEX_METHODDEF {"__enter__", memory_enter, METH_NOARGS, NULL}, - {"__exit__", memory_exit, METH_VARARGS, memory_exit_doc}, + MEMORYVIEW___EXIT___METHODDEF {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("memoryviews are generic over the type of their underlying data")}, {NULL, NULL} diff --git a/Objects/namespaceobject.c b/Objects/namespaceobject.c index 3803c41027dd85..e1ed2f6df9a6e2 100644 --- a/Objects/namespaceobject.c +++ b/Objects/namespaceobject.c @@ -4,6 +4,11 @@ #include "pycore_modsupport.h" // _PyArg_NoPositional() #include "pycore_namespace.h" // _PyNamespace_Type +/*[clinic input] +class namespace "_PyNamespaceObject *" "&_PyNamespace_Type" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=0c19150c7306c8cf]*/ + #include // offsetof() @@ -15,6 +20,8 @@ typedef struct { #define _PyNamespace_CAST(op) _Py_CAST(_PyNamespaceObject*, (op)) #define _PyNamespace_Check(op) PyObject_TypeCheck((op), &_PyNamespace_Type) +#include "clinic/namespaceobject.c.h" + static PyMemberDef namespace_members[] = { {"__dict__", _Py_T_OBJECT, offsetof(_PyNamespaceObject, ns_dict), Py_READONLY}, @@ -224,13 +231,18 @@ namespace_reduce(PyObject *op, PyObject *Py_UNUSED(ignored)) } +/*[clinic input] +namespace.__replace__ + + **changes: dict + +Return a copy with the specified attributes replaced. +[clinic start generated code]*/ + static PyObject * -namespace_replace(PyObject *self, PyObject *args, PyObject *kwargs) +namespace___replace___impl(_PyNamespaceObject *self, PyObject *changes) +/*[clinic end generated code: output=16bc56d7900c95ba input=c34d09667d34e300]*/ { - if (!_PyArg_NoPositional("__replace__", args)) { - return NULL; - } - PyObject *result = PyObject_CallNoArgs((PyObject *)Py_TYPE(self)); if (!result) { return NULL; @@ -249,11 +261,9 @@ namespace_replace(PyObject *self, PyObject *args, PyObject *kwargs) Py_DECREF(result); return NULL; } - if (kwargs) { - if (PyDict_Update(((_PyNamespaceObject*)result)->ns_dict, kwargs) < 0) { - Py_DECREF(result); - return NULL; - } + if (PyDict_Update(((_PyNamespaceObject*)result)->ns_dict, changes) < 0) { + Py_DECREF(result); + return NULL; } return result; } @@ -262,9 +272,7 @@ namespace_replace(PyObject *self, PyObject *args, PyObject *kwargs) static PyMethodDef namespace_methods[] = { {"__reduce__", namespace_reduce, METH_NOARGS, namespace_reduce__doc__}, - {"__replace__", _PyCFunction_CAST(namespace_replace), METH_VARARGS|METH_KEYWORDS, - PyDoc_STR("__replace__($self, /, **changes)\n--\n\n" - "Return a copy of the namespace object with new values for the specified attributes.")}, + NAMESPACE___REPLACE___METHODDEF {NULL, NULL} // sentinel }; diff --git a/Objects/structseq.c b/Objects/structseq.c index 9130fe6a133b1e..36daf523d8004f 100644 --- a/Objects/structseq.c +++ b/Objects/structseq.c @@ -385,17 +385,21 @@ structseq_reduce(PyObject *op, PyObject *Py_UNUSED(ignored)) } +/*[clinic input] +structseq.__replace__ + + **changes: dict + +Return a copy with new values for the specified fields. +[clinic start generated code]*/ + static PyObject * -structseq_replace(PyObject *op, PyObject *args, PyObject *kwargs) +structseq___replace___impl(PyStructSequence *self, PyObject *changes) +/*[clinic end generated code: output=d90566015d93695f input=bf709d26db77afd6]*/ { - PyStructSequence *self = (PyStructSequence*)op; PyStructSequence *result = NULL; Py_ssize_t n_fields, n_unnamed_fields, i; - if (!_PyArg_NoPositional("__replace__", args)) { - return NULL; - } - n_fields = REAL_SIZE(self); if (n_fields < 0) { return NULL; @@ -417,36 +421,27 @@ structseq_replace(PyObject *op, PyObject *args, PyObject *kwargs) return NULL; } - if (kwargs != NULL) { - // We do not support types with unnamed fields, so we can iterate over - // i >= n_visible_fields case without slicing with (i - n_unnamed_fields). - for (i = 0; i < n_fields; ++i) { - PyObject *ob; - if (PyDict_PopString(kwargs, Py_TYPE(self)->tp_members[i].name, - &ob) < 0) { - goto error; - } - if (ob == NULL) { - ob = Py_NewRef(self->ob_item[i]); - } - result->ob_item[i] = ob; - } - // Check if there are any unexpected fields. - if (PyDict_GET_SIZE(kwargs) > 0) { - PyObject *names = PyDict_Keys(kwargs); - if (names) { - PyErr_Format(PyExc_TypeError, "Got unexpected field name(s): %R", names); - Py_DECREF(names); - } + // We do not support types with unnamed fields, so we can iterate over + // i >= n_visible_fields case without slicing with (i - n_unnamed_fields). + for (i = 0; i < n_fields; ++i) { + PyObject *ob; + if (PyDict_PopString(changes, Py_TYPE(self)->tp_members[i].name, + &ob) < 0) { goto error; } - } - else - { - // Just create a copy of the original. - for (i = 0; i < n_fields; ++i) { - result->ob_item[i] = Py_NewRef(self->ob_item[i]); + if (ob == NULL) { + ob = Py_NewRef(self->ob_item[i]); } + result->ob_item[i] = ob; + } + // Check if there are any unexpected fields. + if (PyDict_GET_SIZE(changes) > 0) { + PyObject *names = PyDict_Keys(changes); + if (names) { + PyErr_Format(PyExc_TypeError, "Got unexpected field name(s): %R", names); + Py_DECREF(names); + } + goto error; } _PyObject_GC_TRACK(result); @@ -459,9 +454,7 @@ structseq_replace(PyObject *op, PyObject *args, PyObject *kwargs) static PyMethodDef structseq_methods[] = { {"__reduce__", structseq_reduce, METH_NOARGS, NULL}, - {"__replace__", _PyCFunction_CAST(structseq_replace), METH_VARARGS | METH_KEYWORDS, - PyDoc_STR("__replace__($self, /, **changes)\n--\n\n" - "Return a copy of the structure with new values for the specified fields.")}, + STRUCTSEQ___REPLACE___METHODDEF {NULL, NULL} // sentinel }; diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 965cf20fe61778..796897ff24cdc0 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -979,30 +979,33 @@ builtin_compile_impl(PyObject *module, PyObject *source, PyObject *filename, } /* AC: cannot convert yet, as needs PEP 457 group support in inspect */ +/*[clinic input] +dir as builtin_dir + + object as arg: object = NULL + / + +Return an alphabetized list of the attributes of the object. + +If called without an argument, return the names in the current scope. +Else, return an alphabetized list of names comprising (some of) the +attributes of the given object, and of attributes reachable from it. +If the object supplies a method named __dir__, it will be used; +otherwise the default dir() logic is used and returns: + for a module object: the module's attributes. + for a class object: its attributes, and recursively the attributes + of its bases. + for any other object: its attributes, its class's attributes, and + recursively the attributes of its class's base classes. +[clinic start generated code]*/ + static PyObject * -builtin_dir(PyObject *self, PyObject *args) +builtin_dir_impl(PyObject *module, PyObject *arg) +/*[clinic end generated code: output=24f2c7a52c1e3b08 input=7fe1b2a5ca9ae355]*/ { - PyObject *arg = NULL; - - if (!PyArg_UnpackTuple(args, "dir", 0, 1, &arg)) - return NULL; return PyObject_Dir(arg); } -PyDoc_STRVAR(dir_doc, -"dir([object]) -> list of strings\n" -"\n" -"If called without an argument, return the names in the current scope.\n" -"Else, return an alphabetized list of names comprising (some of) the\n" -"attributes of the given object, and of attributes reachable from it.\n" -"If the object supplies a method named __dir__, it will be used;\n" -"otherwise the default dir() logic is used and returns:\n" -" for a module object: the module's attributes.\n" -" for a class object: its attributes, and recursively the attributes\n" -" of its bases.\n" -" for any other object: its attributes, its class's attributes, and\n" -" recursively the attributes of its class's base classes."); - /*[clinic input] divmod as builtin_divmod @@ -2749,14 +2752,24 @@ builtin_sorted(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject /* AC: cannot convert yet, as needs PEP 457 group support in inspect */ +/*[clinic input] +vars as builtin_vars + + object as v: object = NULL + / + +Show vars. + +Without arguments, equivalent to locals(). +With an argument, equivalent to object.__dict__. +[clinic start generated code]*/ + static PyObject * -builtin_vars(PyObject *self, PyObject *args) +builtin_vars_impl(PyObject *module, PyObject *v) +/*[clinic end generated code: output=a64017e4a4dc53fc input=577550318240f012]*/ { - PyObject *v = NULL; PyObject *d; - if (!PyArg_UnpackTuple(args, "vars", 0, 1, &v)) - return NULL; if (v == NULL) { if (_PyEval_GetFrame() != NULL) { d = _PyEval_GetFrameLocals(); @@ -2784,12 +2797,6 @@ builtin_vars(PyObject *self, PyObject *args) return d; } -PyDoc_STRVAR(vars_doc, -"vars([object]) -> dictionary\n\ -\n\ -Without arguments, equivalent to locals().\n\ -With an argument, equivalent to object.__dict__."); - /* Improved Kahan–Babuška algorithm by Arnold Neumaier Neumaier, A. (1974), Rundungsfehleranalyse einiger Verfahren @@ -3433,7 +3440,7 @@ static PyMethodDef builtin_methods[] = { BUILTIN_CHR_METHODDEF BUILTIN_COMPILE_METHODDEF BUILTIN_DELATTR_METHODDEF - {"dir", builtin_dir, METH_VARARGS, dir_doc}, + BUILTIN_DIR_METHODDEF BUILTIN_DIVMOD_METHODDEF BUILTIN_EVAL_METHODDEF BUILTIN_EXEC_METHODDEF @@ -3463,7 +3470,7 @@ static PyMethodDef builtin_methods[] = { BUILTIN_SETATTR_METHODDEF BUILTIN_SORTED_METHODDEF BUILTIN_SUM_METHODDEF - {"vars", builtin_vars, METH_VARARGS, vars_doc}, + BUILTIN_VARS_METHODDEF {NULL, NULL}, }; diff --git a/Python/clinic/bltinmodule.c.h b/Python/clinic/bltinmodule.c.h index 5858ca9ff88ec2..890dee5a51b546 100644 --- a/Python/clinic/bltinmodule.c.h +++ b/Python/clinic/bltinmodule.c.h @@ -478,6 +478,49 @@ builtin_compile(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObj return return_value; } +PyDoc_STRVAR(builtin_dir__doc__, +"dir($module, object=, /)\n" +"--\n" +"\n" +"Return an alphabetized list of the attributes of the object.\n" +"\n" +"If called without an argument, return the names in the current scope.\n" +"Else, return an alphabetized list of names comprising (some of) the\n" +"attributes of the given object, and of attributes reachable from it.\n" +"If the object supplies a method named __dir__, it will be used;\n" +"otherwise the default dir() logic is used and returns:\n" +" for a module object: the module\'s attributes.\n" +" for a class object: its attributes, and recursively the attributes\n" +" of its bases.\n" +" for any other object: its attributes, its class\'s attributes, and\n" +" recursively the attributes of its class\'s base classes."); + +#define BUILTIN_DIR_METHODDEF \ + {"dir", _PyCFunction_CAST(builtin_dir), METH_FASTCALL, builtin_dir__doc__}, + +static PyObject * +builtin_dir_impl(PyObject *module, PyObject *arg); + +static PyObject * +builtin_dir(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *arg = NULL; + + if (!_PyArg_CheckPositional("dir", nargs, 0, 1)) { + goto exit; + } + if (nargs < 1) { + goto skip_optional; + } + arg = args[0]; +skip_optional: + return_value = builtin_dir_impl(module, arg); + +exit: + return return_value; +} + PyDoc_STRVAR(builtin_divmod__doc__, "divmod($module, x, y, /)\n" "--\n" @@ -1363,6 +1406,41 @@ builtin_round(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObjec return return_value; } +PyDoc_STRVAR(builtin_vars__doc__, +"vars($module, object=, /)\n" +"--\n" +"\n" +"Show vars.\n" +"\n" +"Without arguments, equivalent to locals().\n" +"With an argument, equivalent to object.__dict__."); + +#define BUILTIN_VARS_METHODDEF \ + {"vars", _PyCFunction_CAST(builtin_vars), METH_FASTCALL, builtin_vars__doc__}, + +static PyObject * +builtin_vars_impl(PyObject *module, PyObject *v); + +static PyObject * +builtin_vars(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *v = NULL; + + if (!_PyArg_CheckPositional("vars", nargs, 0, 1)) { + goto exit; + } + if (nargs < 1) { + goto skip_optional; + } + v = args[0]; +skip_optional: + return_value = builtin_vars_impl(module, v); + +exit: + return return_value; +} + PyDoc_STRVAR(builtin_sum__doc__, "sum($module, iterable, /, start=0)\n" "--\n" @@ -1501,4 +1579,4 @@ builtin_issubclass(PyObject *module, PyObject *const *args, Py_ssize_t nargs) exit: return return_value; } -/*[clinic end generated code: output=b56739f2e13f616a input=a9049054013a1b77]*/ +/*[clinic end generated code: output=2454c3867f2a73f3 input=a9049054013a1b77]*/ diff --git a/Python/clinic/hamt.c.h b/Python/clinic/hamt.c.h new file mode 100644 index 00000000000000..c35df925bb4ea6 --- /dev/null +++ b/Python/clinic/hamt.c.h @@ -0,0 +1,70 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +#include "pycore_modsupport.h" // _PyArg_CheckPositional() + +PyDoc_STRVAR(hamt_set__doc__, +"set($self, key, val, /)\n" +"--\n" +"\n" +"Return a copy of the mapping with the key set to the value."); + +#define HAMT_SET_METHODDEF \ + {"set", _PyCFunction_CAST(hamt_set), METH_FASTCALL, hamt_set__doc__}, + +static PyObject * +hamt_set_impl(PyHamtObject *self, PyObject *key, PyObject *val); + +static PyObject * +hamt_set(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *key; + PyObject *val; + + if (!_PyArg_CheckPositional("set", nargs, 2, 2)) { + goto exit; + } + key = args[0]; + val = args[1]; + return_value = hamt_set_impl((PyHamtObject *)self, key, val); + +exit: + return return_value; +} + +PyDoc_STRVAR(hamt_get__doc__, +"get($self, key, default=None, /)\n" +"--\n" +"\n" +"Return the value for the key, or the default if it is not found."); + +#define HAMT_GET_METHODDEF \ + {"get", _PyCFunction_CAST(hamt_get), METH_FASTCALL, hamt_get__doc__}, + +static PyObject * +hamt_get_impl(PyHamtObject *self, PyObject *key, PyObject *def); + +static PyObject * +hamt_get(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *key; + PyObject *def = Py_None; + + if (!_PyArg_CheckPositional("get", nargs, 1, 2)) { + goto exit; + } + key = args[0]; + if (nargs < 2) { + goto skip_optional; + } + def = args[1]; +skip_optional: + return_value = hamt_get_impl((PyHamtObject *)self, key, def); + +exit: + return return_value; +} +/*[clinic end generated code: output=2531b93a9a37546f input=a9049054013a1b77]*/ diff --git a/Python/clinic/sysmodule.c.h b/Python/clinic/sysmodule.c.h index 0c72760f69a4c4..955ced2e493764 100644 --- a/Python/clinic/sysmodule.c.h +++ b/Python/clinic/sysmodule.c.h @@ -687,6 +687,78 @@ sys_get_coroutine_origin_tracking_depth(PyObject *module, PyObject *Py_UNUSED(ig return return_value; } +PyDoc_STRVAR(sys_set_asyncgen_hooks__doc__, +"set_asyncgen_hooks($module, /, firstiter=,\n" +" finalizer=)\n" +"--\n" +"\n" +"Set a finalizer for async generators objects."); + +#define SYS_SET_ASYNCGEN_HOOKS_METHODDEF \ + {"set_asyncgen_hooks", _PyCFunction_CAST(sys_set_asyncgen_hooks), METH_FASTCALL|METH_KEYWORDS, sys_set_asyncgen_hooks__doc__}, + +static PyObject * +sys_set_asyncgen_hooks_impl(PyObject *module, PyObject *firstiter, + PyObject *finalizer); + +static PyObject * +sys_set_asyncgen_hooks(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(firstiter), &_Py_ID(finalizer), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"firstiter", "finalizer", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "set_asyncgen_hooks", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *firstiter = NULL; + PyObject *finalizer = NULL; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 0, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (args[0]) { + firstiter = args[0]; + if (!--noptargs) { + goto skip_optional_pos; + } + } + finalizer = args[1]; +skip_optional_pos: + return_value = sys_set_asyncgen_hooks_impl(module, firstiter, finalizer); + +exit: + return return_value; +} + PyDoc_STRVAR(sys_get_asyncgen_hooks__doc__, "get_asyncgen_hooks($module, /)\n" "--\n" @@ -935,6 +1007,71 @@ sys_set_int_max_str_digits(PyObject *module, PyObject *const *args, Py_ssize_t n return return_value; } +PyDoc_STRVAR(sys_getsizeof__doc__, +"getsizeof($module, /, object, default=)\n" +"--\n" +"\n" +"Return the size of object in bytes."); + +#define SYS_GETSIZEOF_METHODDEF \ + {"getsizeof", _PyCFunction_CAST(sys_getsizeof), METH_FASTCALL|METH_KEYWORDS, sys_getsizeof__doc__}, + +static PyObject * +sys_getsizeof_impl(PyObject *module, PyObject *o, PyObject *dflt); + +static PyObject * +sys_getsizeof(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(object), &_Py_ID(default), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"object", "default", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "getsizeof", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + PyObject *o; + PyObject *dflt = NULL; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + o = args[0]; + if (!noptargs) { + goto skip_optional_pos; + } + dflt = args[1]; +skip_optional_pos: + return_value = sys_getsizeof_impl(module, o, dflt); + +exit: + return return_value; +} + PyDoc_STRVAR(sys_getrefcount__doc__, "getrefcount($module, object, /)\n" "--\n" @@ -2089,4 +2226,4 @@ _jit_is_active(PyObject *module, PyObject *Py_UNUSED(ignored)) #ifndef SYS_GETANDROIDAPILEVEL_METHODDEF #define SYS_GETANDROIDAPILEVEL_METHODDEF #endif /* !defined(SYS_GETANDROIDAPILEVEL_METHODDEF) */ -/*[clinic end generated code: output=8a4482f9c5c493e5 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=0de5ea347ec24d8a input=a9049054013a1b77]*/ diff --git a/Python/hamt.c b/Python/hamt.c index 92ce686863964a..68bb11c0964e62 100644 --- a/Python/hamt.c +++ b/Python/hamt.c @@ -8,6 +8,13 @@ #include // offsetof() +/*[clinic input] +class hamt "PyHamtObject *" "&_PyHamt_Type" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=ab743c139c849b8e]*/ + +#include "clinic/hamt.c.h" + /* This file provides an implementation of an immutable mapping using the Hash Array Mapped Trie (or HAMT) datastructure. @@ -2732,32 +2739,38 @@ hamt_tp_iter(PyObject *op) return _PyHamt_NewIterKeys(self); } -static PyObject * -hamt_py_set(PyObject *op, PyObject *args) -{ - PyObject *key; - PyObject *val; +/*[clinic input] +hamt.set - if (!PyArg_UnpackTuple(args, "set", 2, 2, &key, &val)) { - return NULL; - } + key: object + val: object + / - PyHamtObject *self = _PyHamtObject_CAST(op); - return (PyObject *)_PyHamt_Assoc(self, key, val); -} +Return a copy of the mapping with the key set to the value. +[clinic start generated code]*/ static PyObject * -hamt_py_get(PyObject *op, PyObject *args) +hamt_set_impl(PyHamtObject *self, PyObject *key, PyObject *val) +/*[clinic end generated code: output=2256fa2f6cf80a86 input=d0775605f5ad8fc1]*/ { - PyObject *key; - PyObject *def = NULL; + return (PyObject *)_PyHamt_Assoc(self, key, val); +} - if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &def)) { - return NULL; - } +/*[clinic input] +hamt.get + + key: object + default as def: object = None + / +Return the value for the key, or the default if it is not found. +[clinic start generated code]*/ + +static PyObject * +hamt_get_impl(PyHamtObject *self, PyObject *key, PyObject *def) +/*[clinic end generated code: output=32bfe9cfd2ac5b22 input=2636859ec1bf5912]*/ +{ PyObject *val = NULL; - PyHamtObject *self = _PyHamtObject_CAST(op); hamt_find_t res = hamt_find(self, key, &val); switch (res) { case F_ERROR: @@ -2765,9 +2778,6 @@ hamt_py_get(PyObject *op, PyObject *args) case F_FOUND: return Py_NewRef(val); case F_NOT_FOUND: - if (def == NULL) { - Py_RETURN_NONE; - } return Py_NewRef(def); default: Py_UNREACHABLE(); @@ -2813,8 +2823,8 @@ hamt_py_dump(PyObject *op, PyObject *Py_UNUSED(args)) static PyMethodDef PyHamt_methods[] = { - {"set", hamt_py_set, METH_VARARGS, NULL}, - {"get", hamt_py_get, METH_VARARGS, NULL}, + HAMT_SET_METHODDEF + HAMT_GET_METHODDEF {"delete", hamt_py_delete, METH_O, NULL}, {"items", hamt_py_items, METH_NOARGS, NULL}, {"keys", hamt_py_keys, METH_NOARGS, NULL}, diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 718ae51944faf2..afc90d9bf5d7dd 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1435,19 +1435,20 @@ static PyStructSequence_Desc asyncgen_hooks_desc = { 2 }; -static PyObject * -sys_set_asyncgen_hooks(PyObject *self, PyObject *args, PyObject *kw) -{ - static char *keywords[] = {"firstiter", "finalizer", NULL}; - PyObject *firstiter = NULL; - PyObject *finalizer = NULL; +/*[clinic input] +sys.set_asyncgen_hooks - if (!PyArg_ParseTupleAndKeywords( - args, kw, "|OO", keywords, - &firstiter, &finalizer)) { - return NULL; - } + firstiter: object = NULL + finalizer: object = NULL + +Set a finalizer for async generators objects. +[clinic start generated code]*/ +static PyObject * +sys_set_asyncgen_hooks_impl(PyObject *module, PyObject *firstiter, + PyObject *finalizer) +/*[clinic end generated code: output=6fe3b2dd3f9a9db5 input=ef6a1e96361234be]*/ +{ if (finalizer && finalizer != Py_None) { if (!PyCallable_Check(finalizer)) { PyErr_Format(PyExc_TypeError, @@ -1493,12 +1494,6 @@ sys_set_asyncgen_hooks(PyObject *self, PyObject *args, PyObject *kw) return NULL; } -PyDoc_STRVAR(set_asyncgen_hooks_doc, -"set_asyncgen_hooks([firstiter] [, finalizer])\n\ -\n\ -Set a finalizer for async generators objects." -); - /*[clinic input] sys.get_asyncgen_hooks @@ -1957,19 +1952,22 @@ _PySys_GetSizeOf(PyObject *o) return (size_t)size + presize; } +/*[clinic input] +sys.getsizeof + + object as o: object + default as dflt: object = NULL + +Return the size of object in bytes. +[clinic start generated code]*/ + static PyObject * -sys_getsizeof(PyObject *self, PyObject *args, PyObject *kwds) +sys_getsizeof_impl(PyObject *module, PyObject *o, PyObject *dflt) +/*[clinic end generated code: output=c9dee8179ae2a973 input=fd71e98f0e3ae131]*/ { - static char *kwlist[] = {"object", "default", 0}; size_t size; - PyObject *o, *dflt = NULL; PyThreadState *tstate = _PyThreadState_GET(); - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:getsizeof", - kwlist, &o, &dflt)) { - return NULL; - } - size = _PySys_GetSizeOf(o); if (size == (size_t)-1 && _PyErr_Occurred(tstate)) { @@ -1985,11 +1983,6 @@ sys_getsizeof(PyObject *self, PyObject *args, PyObject *kwds) return PyLong_FromSize_t(size); } -PyDoc_STRVAR(getsizeof_doc, -"getsizeof(object [, default]) -> int\n\ -\n\ -Return the size of object in bytes."); - /*[clinic input] sys.getrefcount -> Py_ssize_t @@ -2914,8 +2907,7 @@ static PyMethodDef sys_methods[] = { SYS_GETTOTALREFCOUNT_METHODDEF SYS_GETREFCOUNT_METHODDEF SYS_GETRECURSIONLIMIT_METHODDEF - {"getsizeof", _PyCFunction_CAST(sys_getsizeof), - METH_VARARGS | METH_KEYWORDS, getsizeof_doc}, + SYS_GETSIZEOF_METHODDEF SYS__GETFRAME_METHODDEF SYS__GETFRAMEMODULENAME_METHODDEF SYS_GETWINDOWSVERSION_METHODDEF @@ -2938,8 +2930,7 @@ static PyMethodDef sys_methods[] = { SYS__DEBUGMALLOCSTATS_METHODDEF SYS_SET_COROUTINE_ORIGIN_TRACKING_DEPTH_METHODDEF SYS_GET_COROUTINE_ORIGIN_TRACKING_DEPTH_METHODDEF - {"set_asyncgen_hooks", _PyCFunction_CAST(sys_set_asyncgen_hooks), - METH_VARARGS | METH_KEYWORDS, set_asyncgen_hooks_doc}, + SYS_SET_ASYNCGEN_HOOKS_METHODDEF SYS_GET_ASYNCGEN_HOOKS_METHODDEF SYS_GETANDROIDAPILEVEL_METHODDEF SYS_ACTIVATE_STACK_TRAMPOLINE_METHODDEF From 4abf0d4b3a615944a1f7ece56ccf8576ffc38249 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 27 Sep 2026 19:03:15 +0300 Subject: [PATCH 4/5] gh-158078: Fix building curses with narrow ncurses (GH-158088) Detect curses functions with a link check instead of a compile check, since the header can declare a function that the library lacks, for example term_attrs() in the narrow ncurses library. Fix test_curses on the narrow build. Co-authored-by: Claude Opus 5.5 (1M context) --- Lib/test/test_curses.py | 50 ++++---- configure | 245 +++++++++++++++++++++++----------------- configure.ac | 6 +- 3 files changed, 173 insertions(+), 128 deletions(-) diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index 9cc6eee266bdd8..5db44ebedd2ee0 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -48,6 +48,26 @@ def wrapped(self, *args, **kwargs): WIDE_BUILD = import_module('_curses')._wide_character_support +def encodable(s, encoding): + # Wide characters are only supported in a locale that can encode them. + try: + s.encode(encoding) + except UnicodeEncodeError: + return False + return True + +def storable(s, encoding): + # Text the current build can place in character cells. A wide build + # stores any locale-encodable text (combining sequences and multibyte + # characters included). A narrow build has no wide-character cells, so + # each character must occupy a single cell -- that is, encode to exactly + # one byte. + if not encodable(s, encoding): + return False + if WIDE_BUILD: + return True + return len(s.encode(encoding)) == len(s) + def requires_wide_build(test): @functools.wraps(test) def wrapped(self, *args, **kwargs): @@ -387,24 +407,10 @@ def test_refresh_control(self): # combining sequence or a multibyte character are guarded with _storable(). def _encodable(self, s): - # Wide characters are only supported in a locale that can encode them. - try: - s.encode(self.stdscr.encoding) - except UnicodeEncodeError: - return False - return True + return encodable(s, self.stdscr.encoding) def _storable(self, s): - # Text the current build can place in character cells. A wide build - # stores any locale-encodable text (combining sequences and multibyte - # characters included). A narrow build has no wide-character cells, so - # each character must occupy a single cell -- that is, encode to exactly - # one byte. - if not self._encodable(s): - return False - if WIDE_BUILD: - return True - return len(s.encode(self.stdscr.encoding)) == len(s) + return storable(s, self.stdscr.encoding) def _char_code(self, ch): # The integer the int-input API (addch(int), do_command()) uses for a @@ -1124,7 +1130,11 @@ def test_cell_null_char(self): # A cell holding a NUL reads back as the cell that writes it. win = curses.newwin(3, 8, 0, 0) win.insch(0, 0, '\0') - self.assertEqual(win.in_wch(0, 0), cell) + if WIDE_BUILD: + self.assertEqual(win.in_wch(0, 0), cell) + else: + # A narrow build inserts a NUL as "^@". + self.assertEqual(str(win.in_wch(0, 0)), '^') # A string of cells cannot hold a NUL: it would end a batch write. self.assertRaises(ValueError, curses.complexstr, 'a\0b') self.assertRaises(ValueError, curses.complexstr, '\0') @@ -3593,10 +3603,8 @@ def test_set_and_label(self): def test_set_wide(self): screen = self.make_slk_screen() label = 'Ångström' - try: - label.encode(screen.stdscr.encoding) - except UnicodeEncodeError: - self.skipTest('the locale cannot encode %r' % label) + if not storable(label, screen.stdscr.encoding): + self.skipTest('cannot store %r in this locale' % label) curses.slk_set(1, label, 0) # The label can be truncated to fit the soft label width, e.g. in the # EUC-JP locale, where "Å" and "ö" are double-width JIS X 0212 diff --git a/configure b/configure index e5d3f0091058ac..8b8bab4ca425db 100755 --- a/configure +++ b/configure @@ -31718,21 +31718,22 @@ main (void) { #ifndef is_pad - void *x=is_pad + void * volatile x = (void *)is_pad; (void)x; #endif ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_curses_is_pad=yes else case e in #( e) ac_cv_lib_curses_is_pad=no ;; esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext ;; esac fi @@ -31778,21 +31779,22 @@ main (void) { #ifndef is_term_resized - void *x=is_term_resized + void * volatile x = (void *)is_term_resized; (void)x; #endif ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_curses_is_term_resized=yes else case e in #( e) ac_cv_lib_curses_is_term_resized=no ;; esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext ;; esac fi @@ -31838,21 +31840,22 @@ main (void) { #ifndef resize_term - void *x=resize_term + void * volatile x = (void *)resize_term; (void)x; #endif ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_curses_resize_term=yes else case e in #( e) ac_cv_lib_curses_resize_term=no ;; esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext ;; esac fi @@ -31898,21 +31901,22 @@ main (void) { #ifndef resizeterm - void *x=resizeterm + void * volatile x = (void *)resizeterm; (void)x; #endif ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_curses_resizeterm=yes else case e in #( e) ac_cv_lib_curses_resizeterm=no ;; esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext ;; esac fi @@ -31958,21 +31962,22 @@ main (void) { #ifndef immedok - void *x=immedok + void * volatile x = (void *)immedok; (void)x; #endif ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_curses_immedok=yes else case e in #( e) ac_cv_lib_curses_immedok=no ;; esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext ;; esac fi @@ -32018,21 +32023,22 @@ main (void) { #ifndef syncok - void *x=syncok + void * volatile x = (void *)syncok; (void)x; #endif ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_curses_syncok=yes else case e in #( e) ac_cv_lib_curses_syncok=no ;; esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext ;; esac fi @@ -32078,21 +32084,22 @@ main (void) { #ifndef wchgat - void *x=wchgat + void * volatile x = (void *)wchgat; (void)x; #endif ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_curses_wchgat=yes else case e in #( e) ac_cv_lib_curses_wchgat=no ;; esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext ;; esac fi @@ -32138,21 +32145,22 @@ main (void) { #ifndef filter - void *x=filter + void * volatile x = (void *)filter; (void)x; #endif ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_curses_filter=yes else case e in #( e) ac_cv_lib_curses_filter=no ;; esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext ;; esac fi @@ -32198,21 +32206,22 @@ main (void) { #ifndef nofilter - void *x=nofilter + void * volatile x = (void *)nofilter; (void)x; #endif ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_curses_nofilter=yes else case e in #( e) ac_cv_lib_curses_nofilter=no ;; esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext ;; esac fi @@ -32258,21 +32267,22 @@ main (void) { #ifndef has_key - void *x=has_key + void * volatile x = (void *)has_key; (void)x; #endif ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_curses_has_key=yes else case e in #( e) ac_cv_lib_curses_has_key=no ;; esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext ;; esac fi @@ -32318,21 +32328,22 @@ main (void) { #ifndef has_mouse - void *x=has_mouse + void * volatile x = (void *)has_mouse; (void)x; #endif ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_curses_has_mouse=yes else case e in #( e) ac_cv_lib_curses_has_mouse=no ;; esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext ;; esac fi @@ -32378,21 +32389,22 @@ main (void) { #ifndef is_keypad - void *x=is_keypad + void * volatile x = (void *)is_keypad; (void)x; #endif ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_curses_is_keypad=yes else case e in #( e) ac_cv_lib_curses_is_keypad=no ;; esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext ;; esac fi @@ -32438,21 +32450,22 @@ main (void) { #ifndef is_leaveok - void *x=is_leaveok + void * volatile x = (void *)is_leaveok; (void)x; #endif ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_curses_is_leaveok=yes else case e in #( e) ac_cv_lib_curses_is_leaveok=no ;; esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext ;; esac fi @@ -32498,21 +32511,22 @@ main (void) { #ifndef typeahead - void *x=typeahead + void * volatile x = (void *)typeahead; (void)x; #endif ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_curses_typeahead=yes else case e in #( e) ac_cv_lib_curses_typeahead=no ;; esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext ;; esac fi @@ -32558,21 +32572,22 @@ main (void) { #ifndef use_env - void *x=use_env + void * volatile x = (void *)use_env; (void)x; #endif ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_curses_use_env=yes else case e in #( e) ac_cv_lib_curses_use_env=no ;; esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext ;; esac fi @@ -32618,21 +32633,22 @@ main (void) { #ifndef new_prescr - void *x=new_prescr + void * volatile x = (void *)new_prescr; (void)x; #endif ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_curses_new_prescr=yes else case e in #( e) ac_cv_lib_curses_new_prescr=no ;; esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext ;; esac fi @@ -32678,21 +32694,22 @@ main (void) { #ifndef use_screen - void *x=use_screen + void * volatile x = (void *)use_screen; (void)x; #endif ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_curses_use_screen=yes else case e in #( e) ac_cv_lib_curses_use_screen=no ;; esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext ;; esac fi @@ -32738,21 +32755,22 @@ main (void) { #ifndef use_window - void *x=use_window + void * volatile x = (void *)use_window; (void)x; #endif ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_curses_use_window=yes else case e in #( e) ac_cv_lib_curses_use_window=no ;; esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext ;; esac fi @@ -32798,21 +32816,22 @@ main (void) { #ifndef key_defined - void *x=key_defined + void * volatile x = (void *)key_defined; (void)x; #endif ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_curses_key_defined=yes else case e in #( e) ac_cv_lib_curses_key_defined=no ;; esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext ;; esac fi @@ -32858,21 +32877,22 @@ main (void) { #ifndef term_attrs - void *x=term_attrs + void * volatile x = (void *)term_attrs; (void)x; #endif ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_curses_term_attrs=yes else case e in #( e) ac_cv_lib_curses_term_attrs=no ;; esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext ;; esac fi @@ -32918,21 +32938,22 @@ main (void) { #ifndef define_key - void *x=define_key + void * volatile x = (void *)define_key; (void)x; #endif ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_curses_define_key=yes else case e in #( e) ac_cv_lib_curses_define_key=no ;; esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext ;; esac fi @@ -32978,21 +32999,22 @@ main (void) { #ifndef keyok - void *x=keyok + void * volatile x = (void *)keyok; (void)x; #endif ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_curses_keyok=yes else case e in #( e) ac_cv_lib_curses_keyok=no ;; esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext ;; esac fi @@ -33038,21 +33060,22 @@ main (void) { #ifndef set_escdelay - void *x=set_escdelay + void * volatile x = (void *)set_escdelay; (void)x; #endif ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_curses_set_escdelay=yes else case e in #( e) ac_cv_lib_curses_set_escdelay=no ;; esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext ;; esac fi @@ -33098,21 +33121,22 @@ main (void) { #ifndef set_tabsize - void *x=set_tabsize + void * volatile x = (void *)set_tabsize; (void)x; #endif ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_curses_set_tabsize=yes else case e in #( e) ac_cv_lib_curses_set_tabsize=no ;; esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext ;; esac fi @@ -33158,21 +33182,22 @@ main (void) { #ifndef wattr_get - void *x=wattr_get + void * volatile x = (void *)wattr_get; (void)x; #endif ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_curses_wattr_get=yes else case e in #( e) ac_cv_lib_curses_wattr_get=no ;; esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext ;; esac fi @@ -33218,21 +33243,22 @@ main (void) { #ifndef wattr_set - void *x=wattr_set + void * volatile x = (void *)wattr_set; (void)x; #endif ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_curses_wattr_set=yes else case e in #( e) ac_cv_lib_curses_wattr_set=no ;; esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext ;; esac fi @@ -33278,21 +33304,22 @@ main (void) { #ifndef wattr_on - void *x=wattr_on + void * volatile x = (void *)wattr_on; (void)x; #endif ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_curses_wattr_on=yes else case e in #( e) ac_cv_lib_curses_wattr_on=no ;; esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext ;; esac fi @@ -33338,21 +33365,22 @@ main (void) { #ifndef wattr_off - void *x=wattr_off + void * volatile x = (void *)wattr_off; (void)x; #endif ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_curses_wattr_off=yes else case e in #( e) ac_cv_lib_curses_wattr_off=no ;; esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext ;; esac fi @@ -33398,21 +33426,22 @@ main (void) { #ifndef wcolor_set - void *x=wcolor_set + void * volatile x = (void *)wcolor_set; (void)x; #endif ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_curses_wcolor_set=yes else case e in #( e) ac_cv_lib_curses_wcolor_set=no ;; esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext ;; esac fi @@ -33458,21 +33487,22 @@ main (void) { #ifndef slk_attr_on - void *x=slk_attr_on + void * volatile x = (void *)slk_attr_on; (void)x; #endif ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_curses_slk_attr_on=yes else case e in #( e) ac_cv_lib_curses_slk_attr_on=no ;; esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext ;; esac fi @@ -33518,21 +33548,22 @@ main (void) { #ifndef slk_attr_off - void *x=slk_attr_off + void * volatile x = (void *)slk_attr_off; (void)x; #endif ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_curses_slk_attr_off=yes else case e in #( e) ac_cv_lib_curses_slk_attr_off=no ;; esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext ;; esac fi @@ -33578,21 +33609,22 @@ main (void) { #ifndef slk_attr_set - void *x=slk_attr_set + void * volatile x = (void *)slk_attr_set; (void)x; #endif ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_curses_slk_attr_set=yes else case e in #( e) ac_cv_lib_curses_slk_attr_set=no ;; esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext ;; esac fi @@ -33638,21 +33670,22 @@ main (void) { #ifndef slk_color - void *x=slk_color + void * volatile x = (void *)slk_color; (void)x; #endif ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_curses_slk_color=yes else case e in #( e) ac_cv_lib_curses_slk_color=no ;; esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext ;; esac fi @@ -33866,21 +33899,22 @@ main (void) { #ifndef scr_dump - void *x=scr_dump + void * volatile x = (void *)scr_dump; (void)x; #endif ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_curses_scr_dump=yes else case e in #( e) ac_cv_lib_curses_scr_dump=no ;; esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext ;; esac fi @@ -33926,21 +33960,22 @@ main (void) { #ifndef scr_set - void *x=scr_set + void * volatile x = (void *)scr_set; (void)x; #endif ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_curses_scr_set=yes else case e in #( e) ac_cv_lib_curses_scr_set=no ;; esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext ;; esac fi diff --git a/configure.ac b/configure.ac index 82a623fedb8192..40191c05952290 100644 --- a/configure.ac +++ b/configure.ac @@ -7426,16 +7426,18 @@ then fi dnl PY_CHECK_CURSES_FUNC(FUNCTION) +dnl Link, not just compile: a header can declare a function that the library +dnl lacks, for example term_attrs() in the narrow ncurses library. AC_DEFUN([PY_CHECK_CURSES_FUNC], [ AS_VAR_PUSHDEF([py_var], [ac_cv_lib_curses_$1]) AS_VAR_PUSHDEF([py_define], [HAVE_CURSES_]m4_toupper($1)) AC_CACHE_CHECK( [for curses function $1], [py_var], - [AC_COMPILE_IFELSE( + [AC_LINK_IFELSE( [AC_LANG_PROGRAM(_CURSES_INCLUDES, [ #ifndef $1 - void *x=$1 + void * volatile x = (void *)$1; (void)x; #endif ])], [AS_VAR_SET([py_var], [yes])], From db3ffd065ca31e3c0c7c3a4f313102b3e3564fb9 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 27 Sep 2026 19:08:10 +0300 Subject: [PATCH 5/5] gh-156261: Use the uid_t and gid_t converters in the pwd and grp modules (GH-156294) They are moved to Argument Clinic, so that pwd.getpwuid() and grp.getgrgid() can declare the type of their parameter instead of converting it in the "impl" function. pwd.getpwuid() now raises OverflowError instead of KeyError for a user id out of the range of uid_t, as grp.getgrgid() already did. --- Lib/test/test_clinic.py | 2 ++ Lib/test/test_pwd.py | 4 ++-- ...-08-22-19-00-00.gh-issue-156261.Nq4tWv.rst | 3 +++ ...-08-23-18-10-00.gh-issue-156261.Rw8pKd.rst | 6 +++--- Modules/clinic/grpmodule.c.h | 12 ++++++----- Modules/clinic/pwdmodule.c.h | 20 ++++++++++++++++++- Modules/grpmodule.c | 10 +++------- Modules/posixmodule.c | 10 +--------- Modules/pwdmodule.c | 13 +++--------- Tools/clinic/libclinic/converters.py | 10 ++++++++++ 10 files changed, 53 insertions(+), 37 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-08-22-19-00-00.gh-issue-156261.Nq4tWv.rst diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index f5334f70768dc4..2243c43bdcbf80 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -4014,6 +4014,7 @@ def test_cli_converters(self): "DWORD", "fildes", "float", + "gid_t", "HANDLE", "int", "long", @@ -4032,6 +4033,7 @@ def test_cli_converters(self): "size_t", "slice_index", "str", + "uid_t", "uint16", "uint32", "uint64", diff --git a/Lib/test/test_pwd.py b/Lib/test/test_pwd.py index 82acce85f1db57..2ad89444348376 100644 --- a/Lib/test/test_pwd.py +++ b/Lib/test/test_pwd.py @@ -61,8 +61,8 @@ def test_errors(self): self.assertRaises(TypeError, pwd.getpwuid, 0.0) self.assertRaises(TypeError, pwd.getpwuid, 0, 0) # should be out of uid_t range - self.assertRaises(KeyError, pwd.getpwuid, 2**128) - self.assertRaises(KeyError, pwd.getpwuid, -2**128) + self.assertRaises(OverflowError, pwd.getpwuid, 2**128) + self.assertRaises(OverflowError, pwd.getpwuid, -2**128) self.assertRaises(TypeError, pwd.getpwnam) self.assertRaises(TypeError, pwd.getpwnam, 42) self.assertRaises(TypeError, pwd.getpwnam, b'root') diff --git a/Misc/NEWS.d/next/Library/2026-08-22-19-00-00.gh-issue-156261.Nq4tWv.rst b/Misc/NEWS.d/next/Library/2026-08-22-19-00-00.gh-issue-156261.Nq4tWv.rst new file mode 100644 index 00000000000000..a641f8371b368f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-08-22-19-00-00.gh-issue-156261.Nq4tWv.rst @@ -0,0 +1,3 @@ +:func:`pwd.getpwuid` now raises :exc:`OverflowError` instead of +:exc:`KeyError` if the user id is out of the range of the C ``uid_t`` type, +as :func:`grp.getgrgid` does for the group id. diff --git a/Misc/NEWS.d/next/Tools-Demos/2026-08-23-18-10-00.gh-issue-156261.Rw8pKd.rst b/Misc/NEWS.d/next/Tools-Demos/2026-08-23-18-10-00.gh-issue-156261.Rw8pKd.rst index da5e42dfa74429..d2f55f626f6d32 100644 --- a/Misc/NEWS.d/next/Tools-Demos/2026-08-23-18-10-00.gh-issue-156261.Rw8pKd.rst +++ b/Misc/NEWS.d/next/Tools-Demos/2026-08-23-18-10-00.gh-issue-156261.Rw8pKd.rst @@ -1,3 +1,3 @@ -Argument Clinic: the ``pid_t``, ``Py_off_t``, ``HANDLE``, ``DWORD`` and -``BOOL`` converters, previously defined in 9 different files, are now -provided by Argument Clinic itself. +Argument Clinic: the ``pid_t``, ``uid_t``, ``gid_t``, ``Py_off_t``, +``HANDLE``, ``DWORD`` and ``BOOL`` converters, previously defined in +individual files, are now provided by Argument Clinic itself. diff --git a/Modules/clinic/grpmodule.c.h b/Modules/clinic/grpmodule.c.h index 665c2f2dfdac14..9f1ea181d9bc4c 100644 --- a/Modules/clinic/grpmodule.c.h +++ b/Modules/clinic/grpmodule.c.h @@ -20,7 +20,7 @@ PyDoc_STRVAR(grp_getgrgid__doc__, {"getgrgid", _PyCFunction_CAST(grp_getgrgid), METH_FASTCALL|METH_KEYWORDS, grp_getgrgid__doc__}, static PyObject * -grp_getgrgid_impl(PyObject *module, PyObject *id); +grp_getgrgid_impl(PyObject *module, gid_t gid); static PyObject * grp_getgrgid(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) @@ -54,15 +54,17 @@ grp_getgrgid(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject }; #undef KWTUPLE PyObject *argsbuf[1]; - PyObject *id; + gid_t gid; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); if (!args) { goto exit; } - id = args[0]; - return_value = grp_getgrgid_impl(module, id); + if (!_Py_Gid_Converter(args[0], &gid)) { + goto exit; + } + return_value = grp_getgrgid_impl(module, gid); exit: return return_value; @@ -152,4 +154,4 @@ grp_getgrall(PyObject *module, PyObject *Py_UNUSED(ignored)) { return grp_getgrall_impl(module); } -/*[clinic end generated code: output=35aa81c00dbd3229 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=9052db62d986262c input=a9049054013a1b77]*/ diff --git a/Modules/clinic/pwdmodule.c.h b/Modules/clinic/pwdmodule.c.h index 43d4825031c7e6..64127ff8e494db 100644 --- a/Modules/clinic/pwdmodule.c.h +++ b/Modules/clinic/pwdmodule.c.h @@ -15,6 +15,24 @@ PyDoc_STRVAR(pwd_getpwuid__doc__, #define PWD_GETPWUID_METHODDEF \ {"getpwuid", (PyCFunction)pwd_getpwuid, METH_O, pwd_getpwuid__doc__}, +static PyObject * +pwd_getpwuid_impl(PyObject *module, uid_t uid); + +static PyObject * +pwd_getpwuid(PyObject *module, PyObject *arg) +{ + PyObject *return_value = NULL; + uid_t uid; + + if (!_Py_Uid_Converter(arg, &uid)) { + goto exit; + } + return_value = pwd_getpwuid_impl(module, uid); + +exit: + return return_value; +} + PyDoc_STRVAR(pwd_getpwnam__doc__, "getpwnam($module, name, /)\n" "--\n" @@ -73,4 +91,4 @@ pwd_getpwall(PyObject *module, PyObject *Py_UNUSED(ignored)) #ifndef PWD_GETPWALL_METHODDEF #define PWD_GETPWALL_METHODDEF #endif /* !defined(PWD_GETPWALL_METHODDEF) */ -/*[clinic end generated code: output=5a8fb12939ff4ea3 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=5bca0b2c2f4c5e89 input=a9049054013a1b77]*/ diff --git a/Modules/grpmodule.c b/Modules/grpmodule.c index 32ead259803614..fe1d16d8322005 100644 --- a/Modules/grpmodule.c +++ b/Modules/grpmodule.c @@ -117,7 +117,7 @@ mkgrent(PyObject *module, struct group *p) /*[clinic input] grp.getgrgid - id: object + id as gid: gid_t Return the group database entry for the given numeric group ID. @@ -125,18 +125,14 @@ If id is not valid, raise KeyError. [clinic start generated code]*/ static PyObject * -grp_getgrgid_impl(PyObject *module, PyObject *id) -/*[clinic end generated code: output=30797c289504a1ba input=15fa0e2ccf5cda25]*/ +grp_getgrgid_impl(PyObject *module, gid_t gid) +/*[clinic end generated code: output=a9e7385cd6df08da input=fca15128dd772588]*/ { PyObject *retval = NULL; int nomem = 0; char *buf = NULL, *buf2 = NULL; - gid_t gid; struct group *p; - if (!_Py_Gid_Converter(id, &gid)) { - return NULL; - } #ifdef HAVE_GETGRGID_R int status; Py_ssize_t bufsize; diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 12ad333c5e5f27..0a451b8a833e67 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -3204,14 +3204,6 @@ class dir_fd_converter(CConverter): def c_default_init(self): self.c_default = 'DEFAULT_DIR_FD' -class uid_t_converter(CConverter): - type = "uid_t" - converter = '_Py_Uid_Converter' - -class gid_t_converter(CConverter): - type = "gid_t" - converter = '_Py_Gid_Converter' - class dev_t_converter(CConverter): type = 'dev_t' converter = '_Py_Dev_Converter' @@ -3268,7 +3260,7 @@ class confname_converter(CConverter): """, argname=argname, converter=self.converter, table=self.table) [python start generated code]*/ -/*[python end generated code: output=da39a3ee5e6b4b0d input=e459765bdf453ebf]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=7ceccf55bb600f61]*/ /*[clinic input] diff --git a/Modules/pwdmodule.c b/Modules/pwdmodule.c index 4a2b33f8700d10..be5e0d4d0c29ae 100644 --- a/Modules/pwdmodule.c +++ b/Modules/pwdmodule.c @@ -121,7 +121,7 @@ mkpwent(PyObject *module, struct passwd *p) /*[clinic input] pwd.getpwuid - uidobj: object + uidobj as uid: uid_t / Return the password database entry for the given numeric user ID. @@ -130,21 +130,14 @@ See `help(pwd)` for more on password database entries. [clinic start generated code]*/ static PyObject * -pwd_getpwuid(PyObject *module, PyObject *uidobj) -/*[clinic end generated code: output=c4ee1d4d429b86c4 input=ae64d507a1c6d3e8]*/ +pwd_getpwuid_impl(PyObject *module, uid_t uid) +/*[clinic end generated code: output=631bad376fa670c3 input=506d3a592ef19799]*/ { PyObject *retval = NULL; - uid_t uid; int nomem = 0; struct passwd *p; char *buf = NULL, *buf2 = NULL; - if (!_Py_Uid_Converter(uidobj, &uid)) { - if (PyErr_ExceptionMatches(PyExc_OverflowError)) - PyErr_Format(PyExc_KeyError, - "getpwuid(): uid not found"); - return NULL; - } #ifdef HAVE_GETPWUID_R int status; Py_ssize_t bufsize; diff --git a/Tools/clinic/libclinic/converters.py b/Tools/clinic/libclinic/converters.py index c2ac6fd22d5bdc..5f663a50ab8ce8 100644 --- a/Tools/clinic/libclinic/converters.py +++ b/Tools/clinic/libclinic/converters.py @@ -601,6 +601,16 @@ def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> st argname=argname) +class gid_t_converter(CConverter): + type = 'gid_t' + converter = '_Py_Gid_Converter' + + +class uid_t_converter(CConverter): + type = 'uid_t' + converter = '_Py_Uid_Converter' + + class pid_t_converter(CConverter): type = 'pid_t' format_unit = '" _Py_PARSE_PID "'