diff --git a/Lib/test/clinic.test.c b/Lib/test/clinic.test.c index 58ffc0ad4ab88b..7d2a1bb66cc9b1 100644 --- a/Lib/test/clinic.test.c +++ b/Lib/test/clinic.test.c @@ -1028,7 +1028,9 @@ test_int_converter(PyObject *module, PyObject *const *args, Py_ssize_t nargs) goto exit; } if (PyUnicode_GET_LENGTH(args[2]) != 1) { - _PyArg_BadArgument("test_int_converter", "argument 3", "a unicode character", args[2]); + PyErr_SetString(PyExc_TypeError, + "test_int_converter(): argument 3 must be a string containing " + "exactly one unicode character"); goto exit; } c = PyUnicode_READ_CHAR(args[2], 0); @@ -1048,7 +1050,7 @@ test_int_converter(PyObject *module, PyObject *const *args, Py_ssize_t nargs) static PyObject * test_int_converter_impl(PyObject *module, int a, int b, int c, myenum d) -/*[clinic end generated code: output=5aed87a7589eefb2 input=d20541fc1ca0553e]*/ +/*[clinic end generated code: output=9c44e10850d9b44c input=d20541fc1ca0553e]*/ /*[clinic input] diff --git a/Misc/NEWS.d/next/Tools-Demos/2024-04-05-13-08-02.gh-issue-117557.tPewu9.rst b/Misc/NEWS.d/next/Tools-Demos/2024-04-05-13-08-02.gh-issue-117557.tPewu9.rst new file mode 100644 index 00000000000000..4119418e181868 --- /dev/null +++ b/Misc/NEWS.d/next/Tools-Demos/2024-04-05-13-08-02.gh-issue-117557.tPewu9.rst @@ -0,0 +1,3 @@ +Argument Clinic now generates slightly more accurate error messages for +``int(accept={str})`` converters if the given string is not exactly one +character long. diff --git a/Modules/clinic/_testclinic.c.h b/Modules/clinic/_testclinic.c.h index bb516be37ec3f0..7d3e1dd83a7897 100644 --- a/Modules/clinic/_testclinic.c.h +++ b/Modules/clinic/_testclinic.c.h @@ -648,7 +648,9 @@ int_converter(PyObject *module, PyObject *const *args, Py_ssize_t nargs) goto exit; } if (PyUnicode_GET_LENGTH(args[2]) != 1) { - _PyArg_BadArgument("int_converter", "argument 3", "a unicode character", args[2]); + PyErr_SetString(PyExc_TypeError, + "int_converter(): argument 3 must be a string containing " + "exactly one unicode character"); goto exit; } c = PyUnicode_READ_CHAR(args[2], 0); @@ -3163,4 +3165,4 @@ _testclinic_TestClass_meth_method_no_params(PyObject *self, PyTypeObject *cls, P } return _testclinic_TestClass_meth_method_no_params_impl(self, cls); } -/*[clinic end generated code: output=6520c1ca5392a3f0 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=6abe2db2328c2ecc input=a9049054013a1b77]*/ diff --git a/Modules/clinic/arraymodule.c.h b/Modules/clinic/arraymodule.c.h index 60a03fe012550e..7b0b5a4fdedd5f 100644 --- a/Modules/clinic/arraymodule.c.h +++ b/Modules/clinic/arraymodule.c.h @@ -596,7 +596,9 @@ array__array_reconstructor(PyObject *module, PyObject *const *args, Py_ssize_t n goto exit; } if (PyUnicode_GET_LENGTH(args[1]) != 1) { - _PyArg_BadArgument("_array_reconstructor", "argument 2", "a unicode character", args[1]); + PyErr_SetString(PyExc_TypeError, + "_array_reconstructor(): argument 2 must be a string containing " + "exactly one unicode character"); goto exit; } typecode = PyUnicode_READ_CHAR(args[1], 0); @@ -685,4 +687,4 @@ PyDoc_STRVAR(array_arrayiterator___setstate____doc__, #define ARRAY_ARRAYITERATOR___SETSTATE___METHODDEF \ {"__setstate__", (PyCFunction)array_arrayiterator___setstate__, METH_O, array_arrayiterator___setstate____doc__}, -/*[clinic end generated code: output=52c55d9b1d026c1c input=a9049054013a1b77]*/ +/*[clinic end generated code: output=cdad784deb1e4c46 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/unicodedata.c.h b/Modules/clinic/unicodedata.c.h index 739f498f1d2672..68ae8e5928b74d 100644 --- a/Modules/clinic/unicodedata.c.h +++ b/Modules/clinic/unicodedata.c.h @@ -36,7 +36,9 @@ unicodedata_UCD_decimal(PyObject *self, PyObject *const *args, Py_ssize_t nargs) goto exit; } if (PyUnicode_GET_LENGTH(args[0]) != 1) { - _PyArg_BadArgument("decimal", "argument 1", "a unicode character", args[0]); + PyErr_SetString(PyExc_TypeError, + "decimal(): argument 1 must be a string containing " + "exactly one unicode character"); goto exit; } chr = PyUnicode_READ_CHAR(args[0], 0); @@ -82,7 +84,9 @@ unicodedata_UCD_digit(PyObject *self, PyObject *const *args, Py_ssize_t nargs) goto exit; } if (PyUnicode_GET_LENGTH(args[0]) != 1) { - _PyArg_BadArgument("digit", "argument 1", "a unicode character", args[0]); + PyErr_SetString(PyExc_TypeError, + "digit(): argument 1 must be a string containing " + "exactly one unicode character"); goto exit; } chr = PyUnicode_READ_CHAR(args[0], 0); @@ -129,7 +133,9 @@ unicodedata_UCD_numeric(PyObject *self, PyObject *const *args, Py_ssize_t nargs) goto exit; } if (PyUnicode_GET_LENGTH(args[0]) != 1) { - _PyArg_BadArgument("numeric", "argument 1", "a unicode character", args[0]); + PyErr_SetString(PyExc_TypeError, + "numeric(): argument 1 must be a string containing " + "exactly one unicode character"); goto exit; } chr = PyUnicode_READ_CHAR(args[0], 0); @@ -167,7 +173,9 @@ unicodedata_UCD_category(PyObject *self, PyObject *arg) goto exit; } if (PyUnicode_GET_LENGTH(arg) != 1) { - _PyArg_BadArgument("category", "argument", "a unicode character", arg); + PyErr_SetString(PyExc_TypeError, + "category(): argument must be a string containing " + "exactly one unicode character"); goto exit; } chr = PyUnicode_READ_CHAR(arg, 0); @@ -202,7 +210,9 @@ unicodedata_UCD_bidirectional(PyObject *self, PyObject *arg) goto exit; } if (PyUnicode_GET_LENGTH(arg) != 1) { - _PyArg_BadArgument("bidirectional", "argument", "a unicode character", arg); + PyErr_SetString(PyExc_TypeError, + "bidirectional(): argument must be a string containing " + "exactly one unicode character"); goto exit; } chr = PyUnicode_READ_CHAR(arg, 0); @@ -238,7 +248,9 @@ unicodedata_UCD_combining(PyObject *self, PyObject *arg) goto exit; } if (PyUnicode_GET_LENGTH(arg) != 1) { - _PyArg_BadArgument("combining", "argument", "a unicode character", arg); + PyErr_SetString(PyExc_TypeError, + "combining(): argument must be a string containing " + "exactly one unicode character"); goto exit; } chr = PyUnicode_READ_CHAR(arg, 0); @@ -279,7 +291,9 @@ unicodedata_UCD_mirrored(PyObject *self, PyObject *arg) goto exit; } if (PyUnicode_GET_LENGTH(arg) != 1) { - _PyArg_BadArgument("mirrored", "argument", "a unicode character", arg); + PyErr_SetString(PyExc_TypeError, + "mirrored(): argument must be a string containing " + "exactly one unicode character"); goto exit; } chr = PyUnicode_READ_CHAR(arg, 0); @@ -316,7 +330,9 @@ unicodedata_UCD_east_asian_width(PyObject *self, PyObject *arg) goto exit; } if (PyUnicode_GET_LENGTH(arg) != 1) { - _PyArg_BadArgument("east_asian_width", "argument", "a unicode character", arg); + PyErr_SetString(PyExc_TypeError, + "east_asian_width(): argument must be a string containing " + "exactly one unicode character"); goto exit; } chr = PyUnicode_READ_CHAR(arg, 0); @@ -351,7 +367,9 @@ unicodedata_UCD_decomposition(PyObject *self, PyObject *arg) goto exit; } if (PyUnicode_GET_LENGTH(arg) != 1) { - _PyArg_BadArgument("decomposition", "argument", "a unicode character", arg); + PyErr_SetString(PyExc_TypeError, + "decomposition(): argument must be a string containing " + "exactly one unicode character"); goto exit; } chr = PyUnicode_READ_CHAR(arg, 0); @@ -473,7 +491,9 @@ unicodedata_UCD_name(PyObject *self, PyObject *const *args, Py_ssize_t nargs) goto exit; } if (PyUnicode_GET_LENGTH(args[0]) != 1) { - _PyArg_BadArgument("name", "argument 1", "a unicode character", args[0]); + PyErr_SetString(PyExc_TypeError, + "name(): argument 1 must be a string containing " + "exactly one unicode character"); goto exit; } chr = PyUnicode_READ_CHAR(args[0], 0); @@ -519,4 +539,4 @@ unicodedata_UCD_lookup(PyObject *self, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=ea30f89007b2bfff input=a9049054013a1b77]*/ +/*[clinic end generated code: output=a5c5e02b4dc4951c input=a9049054013a1b77]*/ diff --git a/PC/clinic/msvcrtmodule.c.h b/PC/clinic/msvcrtmodule.c.h index e3f7ea43f38211..6d80ea5c301c74 100644 --- a/PC/clinic/msvcrtmodule.c.h +++ b/PC/clinic/msvcrtmodule.c.h @@ -396,7 +396,9 @@ msvcrt_putwch(PyObject *module, PyObject *arg) goto exit; } if (PyUnicode_GET_LENGTH(arg) != 1) { - _PyArg_BadArgument("putwch", "argument", "a unicode character", arg); + PyErr_SetString(PyExc_TypeError, + "putwch(): argument must be a string containing " + "exactly one unicode character"); goto exit; } unicode_char = PyUnicode_READ_CHAR(arg, 0); @@ -471,7 +473,9 @@ msvcrt_ungetwch(PyObject *module, PyObject *arg) goto exit; } if (PyUnicode_GET_LENGTH(arg) != 1) { - _PyArg_BadArgument("ungetwch", "argument", "a unicode character", arg); + PyErr_SetString(PyExc_TypeError, + "ungetwch(): argument must be a string containing " + "exactly one unicode character"); goto exit; } unicode_char = PyUnicode_READ_CHAR(arg, 0); @@ -697,4 +701,4 @@ msvcrt_SetErrorMode(PyObject *module, PyObject *arg) #ifndef MSVCRT_GETERRORMODE_METHODDEF #define MSVCRT_GETERRORMODE_METHODDEF #endif /* !defined(MSVCRT_GETERRORMODE_METHODDEF) */ -/*[clinic end generated code: output=de9687b46212c2ed input=a9049054013a1b77]*/ +/*[clinic end generated code: output=32225d72078b5172 input=a9049054013a1b77]*/ diff --git a/Python/getargs.c b/Python/getargs.c index bec981698767ca..efe9ba695c6266 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -575,11 +575,13 @@ static const char * converterr(const char *expected, PyObject *arg, char *msgbuf, size_t bufsize) { assert(expected != NULL); - assert(arg != NULL); if (expected[0] == '(') { PyOS_snprintf(msgbuf, bufsize, "%.100s", expected); } + else if (arg == NULL) { + PyOS_snprintf(msgbuf, bufsize, "must be %.100s", expected); + } else { PyOS_snprintf(msgbuf, bufsize, "must be %.50s, not %.50s", expected, @@ -812,7 +814,8 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, return converterr("a unicode character", arg, msgbuf, bufsize); if (PyUnicode_GET_LENGTH(arg) != 1) - return converterr("a unicode character", arg, msgbuf, bufsize); + return converterr("a string containing exactly one unicode character", + NULL, msgbuf, bufsize); kind = PyUnicode_KIND(arg); data = PyUnicode_DATA(arg); diff --git a/Tools/clinic/libclinic/converters.py b/Tools/clinic/libclinic/converters.py index 7fc16f17450aaa..de75d7326137ea 100644 --- a/Tools/clinic/libclinic/converters.py +++ b/Tools/clinic/libclinic/converters.py @@ -272,11 +272,14 @@ def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> st goto exit; }}}} if (PyUnicode_GET_LENGTH({argname}) != 1) {{{{ - {bad_argument} + PyErr_SetString(PyExc_TypeError, + "{{name}}(): {displayname} must be a string containing " + "exactly one unicode character"); goto exit; }}}} {paramname} = PyUnicode_READ_CHAR({argname}, 0); """, + displayname=displayname, argname=argname, bad_argument=self.bad_argument(displayname, 'a unicode character', limited_capi=limited_capi), )