From 6b1d95666f558a41ca3d0760175c560c9179150f Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 5 Apr 2024 11:03:21 +0200 Subject: [PATCH 1/8] gh-117557: Raise ValueError iso. TypeError if str length is wrong for int(accept={str}) Argument Clinic converter --- Lib/test/clinic.test.c | 4 ++-- Lib/test/test_unicodedata.py | 20 ++++++++++---------- Modules/clinic/_testclinic.c.h | 4 ++-- Modules/clinic/arraymodule.c.h | 4 ++-- Modules/clinic/unicodedata.c.h | 22 +++++++++++----------- PC/clinic/msvcrtmodule.c.h | 6 +++--- Tools/clinic/libclinic/converters.py | 2 +- 7 files changed, 31 insertions(+), 31 deletions(-) diff --git a/Lib/test/clinic.test.c b/Lib/test/clinic.test.c index 58ffc0ad4ab88b..220962d2d99ff7 100644 --- a/Lib/test/clinic.test.c +++ b/Lib/test/clinic.test.c @@ -1028,7 +1028,7 @@ 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_ValueError, "a single unicode character expected"); goto exit; } c = PyUnicode_READ_CHAR(args[2], 0); @@ -1048,7 +1048,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=ec176dff0664c4a5 input=d20541fc1ca0553e]*/ /*[clinic input] diff --git a/Lib/test/test_unicodedata.py b/Lib/test/test_unicodedata.py index d3bf4ea7c7d437..cf5278c21606ae 100644 --- a/Lib/test/test_unicodedata.py +++ b/Lib/test/test_unicodedata.py @@ -133,7 +133,7 @@ def test_digit(self): self.assertEqual(self.db.digit('\U0001D7FD'), 7) self.assertRaises(TypeError, self.db.digit) - self.assertRaises(TypeError, self.db.digit, 'xx') + self.assertRaises(ValueError, self.db.digit, 'xx') self.assertRaises(ValueError, self.db.digit, 'x') def test_numeric(self): @@ -146,7 +146,7 @@ def test_numeric(self): self.assertEqual(self.db.numeric('\U0001012A'), 9000) self.assertRaises(TypeError, self.db.numeric) - self.assertRaises(TypeError, self.db.numeric, 'xx') + self.assertRaises(ValueError, self.db.numeric, 'xx') self.assertRaises(ValueError, self.db.numeric, 'x') def test_decimal(self): @@ -158,7 +158,7 @@ def test_decimal(self): self.assertEqual(self.db.decimal('\U0001D7FD'), 7) self.assertRaises(TypeError, self.db.decimal) - self.assertRaises(TypeError, self.db.decimal, 'xx') + self.assertRaises(ValueError, self.db.decimal, 'xx') self.assertRaises(ValueError, self.db.decimal, 'x') def test_category(self): @@ -169,7 +169,7 @@ def test_category(self): self.assertEqual(self.db.category('\U0001012A'), 'No') self.assertRaises(TypeError, self.db.category) - self.assertRaises(TypeError, self.db.category, 'xx') + self.assertRaises(ValueError, self.db.category, 'xx') def test_bidirectional(self): self.assertEqual(self.db.bidirectional('\uFFFE'), '') @@ -178,14 +178,14 @@ def test_bidirectional(self): self.assertEqual(self.db.bidirectional('\U00020000'), 'L') self.assertRaises(TypeError, self.db.bidirectional) - self.assertRaises(TypeError, self.db.bidirectional, 'xx') + self.assertRaises(ValueError, self.db.bidirectional, 'xx') def test_decomposition(self): self.assertEqual(self.db.decomposition('\uFFFE'),'') self.assertEqual(self.db.decomposition('\u00bc'), ' 0031 2044 0034') self.assertRaises(TypeError, self.db.decomposition) - self.assertRaises(TypeError, self.db.decomposition, 'xx') + self.assertRaises(ValueError, self.db.decomposition, 'xx') def test_mirrored(self): self.assertEqual(self.db.mirrored('\uFFFE'), 0) @@ -194,7 +194,7 @@ def test_mirrored(self): self.assertEqual(self.db.mirrored('\U00020000'), 0) self.assertRaises(TypeError, self.db.mirrored) - self.assertRaises(TypeError, self.db.mirrored, 'xx') + self.assertRaises(ValueError, self.db.mirrored, 'xx') def test_combining(self): self.assertEqual(self.db.combining('\uFFFE'), 0) @@ -203,7 +203,7 @@ def test_combining(self): self.assertEqual(self.db.combining('\U00020000'), 0) self.assertRaises(TypeError, self.db.combining) - self.assertRaises(TypeError, self.db.combining, 'xx') + self.assertRaises(ValueError, self.db.combining, 'xx') def test_pr29(self): # https://www.unicode.org/review/pr-29.html @@ -239,8 +239,8 @@ def test_east_asian_width(self): eaw = self.db.east_asian_width self.assertRaises(TypeError, eaw, b'a') self.assertRaises(TypeError, eaw, bytearray()) - self.assertRaises(TypeError, eaw, '') - self.assertRaises(TypeError, eaw, 'ra') + self.assertRaises(ValueError, eaw, '') + self.assertRaises(ValueError, eaw, 'ra') self.assertEqual(eaw('\x1e'), 'N') self.assertEqual(eaw('\x20'), 'Na') self.assertEqual(eaw('\uC894'), 'W') diff --git a/Modules/clinic/_testclinic.c.h b/Modules/clinic/_testclinic.c.h index bb516be37ec3f0..34e8390fcc725b 100644 --- a/Modules/clinic/_testclinic.c.h +++ b/Modules/clinic/_testclinic.c.h @@ -648,7 +648,7 @@ 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_ValueError, "a single unicode character expected"); goto exit; } c = PyUnicode_READ_CHAR(args[2], 0); @@ -3163,4 +3163,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=3f752442d1ce8437 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/arraymodule.c.h b/Modules/clinic/arraymodule.c.h index 60a03fe012550e..09895adfa67c39 100644 --- a/Modules/clinic/arraymodule.c.h +++ b/Modules/clinic/arraymodule.c.h @@ -596,7 +596,7 @@ 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_ValueError, "a single unicode character expected"); goto exit; } typecode = PyUnicode_READ_CHAR(args[1], 0); @@ -685,4 +685,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=1baf4861b983d7d7 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/unicodedata.c.h b/Modules/clinic/unicodedata.c.h index 739f498f1d2672..0a08c9f749da45 100644 --- a/Modules/clinic/unicodedata.c.h +++ b/Modules/clinic/unicodedata.c.h @@ -36,7 +36,7 @@ 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_ValueError, "a single unicode character expected"); goto exit; } chr = PyUnicode_READ_CHAR(args[0], 0); @@ -82,7 +82,7 @@ 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_ValueError, "a single unicode character expected"); goto exit; } chr = PyUnicode_READ_CHAR(args[0], 0); @@ -129,7 +129,7 @@ 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_ValueError, "a single unicode character expected"); goto exit; } chr = PyUnicode_READ_CHAR(args[0], 0); @@ -167,7 +167,7 @@ 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_ValueError, "a single unicode character expected"); goto exit; } chr = PyUnicode_READ_CHAR(arg, 0); @@ -202,7 +202,7 @@ 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_ValueError, "a single unicode character expected"); goto exit; } chr = PyUnicode_READ_CHAR(arg, 0); @@ -238,7 +238,7 @@ 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_ValueError, "a single unicode character expected"); goto exit; } chr = PyUnicode_READ_CHAR(arg, 0); @@ -279,7 +279,7 @@ 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_ValueError, "a single unicode character expected"); goto exit; } chr = PyUnicode_READ_CHAR(arg, 0); @@ -316,7 +316,7 @@ 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_ValueError, "a single unicode character expected"); goto exit; } chr = PyUnicode_READ_CHAR(arg, 0); @@ -351,7 +351,7 @@ 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_ValueError, "a single unicode character expected"); goto exit; } chr = PyUnicode_READ_CHAR(arg, 0); @@ -473,7 +473,7 @@ 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_ValueError, "a single unicode character expected"); goto exit; } chr = PyUnicode_READ_CHAR(args[0], 0); @@ -519,4 +519,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=8f0ea4bd0e419f9a input=a9049054013a1b77]*/ diff --git a/PC/clinic/msvcrtmodule.c.h b/PC/clinic/msvcrtmodule.c.h index e3f7ea43f38211..35bf7d3db4e785 100644 --- a/PC/clinic/msvcrtmodule.c.h +++ b/PC/clinic/msvcrtmodule.c.h @@ -396,7 +396,7 @@ 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_ValueError, "a single unicode character expected"); goto exit; } unicode_char = PyUnicode_READ_CHAR(arg, 0); @@ -471,7 +471,7 @@ 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_ValueError, "a single unicode character expected"); goto exit; } unicode_char = PyUnicode_READ_CHAR(arg, 0); @@ -697,4 +697,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=3fd55f8b3d349250 input=a9049054013a1b77]*/ diff --git a/Tools/clinic/libclinic/converters.py b/Tools/clinic/libclinic/converters.py index 7fc16f17450aaa..5b59ccfa6e54ae 100644 --- a/Tools/clinic/libclinic/converters.py +++ b/Tools/clinic/libclinic/converters.py @@ -272,7 +272,7 @@ 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_ValueError, "a single unicode character expected"); goto exit; }}}} {paramname} = PyUnicode_READ_CHAR({argname}, 0); From af25677bf9a2b5a0021682f51b811d334a097937 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 5 Apr 2024 11:19:16 +0200 Subject: [PATCH 2/8] Amend test_ucn.test_errors --- Lib/test/test_ucn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_ucn.py b/Lib/test/test_ucn.py index cbfd5af2bb751c..3d8e08aee50b4d 100644 --- a/Lib/test/test_ucn.py +++ b/Lib/test/test_ucn.py @@ -198,7 +198,7 @@ def check_version(testfile): def test_errors(self): self.assertRaises(TypeError, unicodedata.name) - self.assertRaises(TypeError, unicodedata.name, 'xx') + self.assertRaises(ValueError, unicodedata.name, 'xx') self.assertRaises(TypeError, unicodedata.lookup) self.assertRaises(KeyError, unicodedata.lookup, 'unknown') From 235b594c034ad447467f4b66708936f2b0a9c545 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 5 Apr 2024 11:28:59 +0200 Subject: [PATCH 3/8] Better error message --- Lib/test/clinic.test.c | 6 ++-- Modules/clinic/_testclinic.c.h | 6 ++-- Modules/clinic/arraymodule.c.h | 6 ++-- Modules/clinic/unicodedata.c.h | 42 ++++++++++++++++++++-------- PC/clinic/msvcrtmodule.c.h | 10 +++++-- Tools/clinic/libclinic/converters.py | 5 +++- 6 files changed, 54 insertions(+), 21 deletions(-) diff --git a/Lib/test/clinic.test.c b/Lib/test/clinic.test.c index 220962d2d99ff7..1480492230dc3c 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) { - PyErr_SetString(PyExc_ValueError, "a single unicode character expected"); + PyErr_Format(PyExc_ValueError, + "test_int_converter(): argument 3 must be a single unicode character, not %T", + args[2]); 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=ec176dff0664c4a5 input=d20541fc1ca0553e]*/ +/*[clinic end generated code: output=fcb777a9311da2f5 input=d20541fc1ca0553e]*/ /*[clinic input] diff --git a/Modules/clinic/_testclinic.c.h b/Modules/clinic/_testclinic.c.h index 34e8390fcc725b..f548396fe687e2 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) { - PyErr_SetString(PyExc_ValueError, "a single unicode character expected"); + PyErr_Format(PyExc_ValueError, + "int_converter(): argument 3 must be a single unicode character, not %T", + args[2]); 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=3f752442d1ce8437 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=e96c223b763729db input=a9049054013a1b77]*/ diff --git a/Modules/clinic/arraymodule.c.h b/Modules/clinic/arraymodule.c.h index 09895adfa67c39..caf9de8bc22ff1 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) { - PyErr_SetString(PyExc_ValueError, "a single unicode character expected"); + PyErr_Format(PyExc_ValueError, + "_array_reconstructor(): argument 2 must be a single unicode character, not %T", + args[1]); 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=1baf4861b983d7d7 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=e65b6b6a624901d1 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/unicodedata.c.h b/Modules/clinic/unicodedata.c.h index 0a08c9f749da45..8513defd142579 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) { - PyErr_SetString(PyExc_ValueError, "a single unicode character expected"); + PyErr_Format(PyExc_ValueError, + "decimal(): argument 1 must be a single unicode character, not %T", + args[0]); 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) { - PyErr_SetString(PyExc_ValueError, "a single unicode character expected"); + PyErr_Format(PyExc_ValueError, + "digit(): argument 1 must be a single unicode character, not %T", + args[0]); 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) { - PyErr_SetString(PyExc_ValueError, "a single unicode character expected"); + PyErr_Format(PyExc_ValueError, + "numeric(): argument 1 must be a single unicode character, not %T", + args[0]); 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) { - PyErr_SetString(PyExc_ValueError, "a single unicode character expected"); + PyErr_Format(PyExc_ValueError, + "category(): argument must be a single unicode character, not %T", + arg); 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) { - PyErr_SetString(PyExc_ValueError, "a single unicode character expected"); + PyErr_Format(PyExc_ValueError, + "bidirectional(): argument must be a single unicode character, not %T", + arg); 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) { - PyErr_SetString(PyExc_ValueError, "a single unicode character expected"); + PyErr_Format(PyExc_ValueError, + "combining(): argument must be a single unicode character, not %T", + arg); 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) { - PyErr_SetString(PyExc_ValueError, "a single unicode character expected"); + PyErr_Format(PyExc_ValueError, + "mirrored(): argument must be a single unicode character, not %T", + arg); 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) { - PyErr_SetString(PyExc_ValueError, "a single unicode character expected"); + PyErr_Format(PyExc_ValueError, + "east_asian_width(): argument must be a single unicode character, not %T", + arg); 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) { - PyErr_SetString(PyExc_ValueError, "a single unicode character expected"); + PyErr_Format(PyExc_ValueError, + "decomposition(): argument must be a single unicode character, not %T", + arg); 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) { - PyErr_SetString(PyExc_ValueError, "a single unicode character expected"); + PyErr_Format(PyExc_ValueError, + "name(): argument 1 must be a single unicode character, not %T", + args[0]); 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=8f0ea4bd0e419f9a input=a9049054013a1b77]*/ +/*[clinic end generated code: output=a523cb9d95c65999 input=a9049054013a1b77]*/ diff --git a/PC/clinic/msvcrtmodule.c.h b/PC/clinic/msvcrtmodule.c.h index 35bf7d3db4e785..cd70200c2cd965 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) { - PyErr_SetString(PyExc_ValueError, "a single unicode character expected"); + PyErr_Format(PyExc_ValueError, + "putwch(): argument must be a single unicode character, not %T", + arg); 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) { - PyErr_SetString(PyExc_ValueError, "a single unicode character expected"); + PyErr_Format(PyExc_ValueError, + "ungetwch(): argument must be a single unicode character, not %T", + arg); 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=3fd55f8b3d349250 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=8572a2bd458907f5 input=a9049054013a1b77]*/ diff --git a/Tools/clinic/libclinic/converters.py b/Tools/clinic/libclinic/converters.py index 5b59ccfa6e54ae..e5ba9e502fe46a 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) {{{{ - PyErr_SetString(PyExc_ValueError, "a single unicode character expected"); + PyErr_Format(PyExc_ValueError, + "{{name}}(): {displayname} must be a single unicode character, not %T", + {argname}); 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), ) From 6b787fc66a694f63e94fbe5b4dfa14de4f0757c7 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 5 Apr 2024 13:02:52 +0200 Subject: [PATCH 4/8] New strategy: retain TypeError, but improve the error message --- Lib/test/clinic.test.c | 6 ++-- Lib/test/test_ucn.py | 2 +- Lib/test/test_unicodedata.py | 20 ++++++------- Modules/clinic/_testclinic.c.h | 6 ++-- Modules/clinic/arraymodule.c.h | 6 ++-- Modules/clinic/unicodedata.c.h | 42 ++++++++++++++-------------- PC/clinic/msvcrtmodule.c.h | 10 +++---- Tools/clinic/libclinic/converters.py | 4 +-- 8 files changed, 48 insertions(+), 48 deletions(-) diff --git a/Lib/test/clinic.test.c b/Lib/test/clinic.test.c index 1480492230dc3c..96e1f37ed81350 100644 --- a/Lib/test/clinic.test.c +++ b/Lib/test/clinic.test.c @@ -1028,8 +1028,8 @@ test_int_converter(PyObject *module, PyObject *const *args, Py_ssize_t nargs) goto exit; } if (PyUnicode_GET_LENGTH(args[2]) != 1) { - PyErr_Format(PyExc_ValueError, - "test_int_converter(): argument 3 must be a single unicode character, not %T", + PyErr_Format(PyExc_TypeError, + "test_int_converter(): argument 3 must be exactly one character long, not %T", args[2]); goto exit; } @@ -1050,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=fcb777a9311da2f5 input=d20541fc1ca0553e]*/ +/*[clinic end generated code: output=ef1676a7f1b18b1d input=d20541fc1ca0553e]*/ /*[clinic input] diff --git a/Lib/test/test_ucn.py b/Lib/test/test_ucn.py index 3d8e08aee50b4d..cbfd5af2bb751c 100644 --- a/Lib/test/test_ucn.py +++ b/Lib/test/test_ucn.py @@ -198,7 +198,7 @@ def check_version(testfile): def test_errors(self): self.assertRaises(TypeError, unicodedata.name) - self.assertRaises(ValueError, unicodedata.name, 'xx') + self.assertRaises(TypeError, unicodedata.name, 'xx') self.assertRaises(TypeError, unicodedata.lookup) self.assertRaises(KeyError, unicodedata.lookup, 'unknown') diff --git a/Lib/test/test_unicodedata.py b/Lib/test/test_unicodedata.py index cf5278c21606ae..d3bf4ea7c7d437 100644 --- a/Lib/test/test_unicodedata.py +++ b/Lib/test/test_unicodedata.py @@ -133,7 +133,7 @@ def test_digit(self): self.assertEqual(self.db.digit('\U0001D7FD'), 7) self.assertRaises(TypeError, self.db.digit) - self.assertRaises(ValueError, self.db.digit, 'xx') + self.assertRaises(TypeError, self.db.digit, 'xx') self.assertRaises(ValueError, self.db.digit, 'x') def test_numeric(self): @@ -146,7 +146,7 @@ def test_numeric(self): self.assertEqual(self.db.numeric('\U0001012A'), 9000) self.assertRaises(TypeError, self.db.numeric) - self.assertRaises(ValueError, self.db.numeric, 'xx') + self.assertRaises(TypeError, self.db.numeric, 'xx') self.assertRaises(ValueError, self.db.numeric, 'x') def test_decimal(self): @@ -158,7 +158,7 @@ def test_decimal(self): self.assertEqual(self.db.decimal('\U0001D7FD'), 7) self.assertRaises(TypeError, self.db.decimal) - self.assertRaises(ValueError, self.db.decimal, 'xx') + self.assertRaises(TypeError, self.db.decimal, 'xx') self.assertRaises(ValueError, self.db.decimal, 'x') def test_category(self): @@ -169,7 +169,7 @@ def test_category(self): self.assertEqual(self.db.category('\U0001012A'), 'No') self.assertRaises(TypeError, self.db.category) - self.assertRaises(ValueError, self.db.category, 'xx') + self.assertRaises(TypeError, self.db.category, 'xx') def test_bidirectional(self): self.assertEqual(self.db.bidirectional('\uFFFE'), '') @@ -178,14 +178,14 @@ def test_bidirectional(self): self.assertEqual(self.db.bidirectional('\U00020000'), 'L') self.assertRaises(TypeError, self.db.bidirectional) - self.assertRaises(ValueError, self.db.bidirectional, 'xx') + self.assertRaises(TypeError, self.db.bidirectional, 'xx') def test_decomposition(self): self.assertEqual(self.db.decomposition('\uFFFE'),'') self.assertEqual(self.db.decomposition('\u00bc'), ' 0031 2044 0034') self.assertRaises(TypeError, self.db.decomposition) - self.assertRaises(ValueError, self.db.decomposition, 'xx') + self.assertRaises(TypeError, self.db.decomposition, 'xx') def test_mirrored(self): self.assertEqual(self.db.mirrored('\uFFFE'), 0) @@ -194,7 +194,7 @@ def test_mirrored(self): self.assertEqual(self.db.mirrored('\U00020000'), 0) self.assertRaises(TypeError, self.db.mirrored) - self.assertRaises(ValueError, self.db.mirrored, 'xx') + self.assertRaises(TypeError, self.db.mirrored, 'xx') def test_combining(self): self.assertEqual(self.db.combining('\uFFFE'), 0) @@ -203,7 +203,7 @@ def test_combining(self): self.assertEqual(self.db.combining('\U00020000'), 0) self.assertRaises(TypeError, self.db.combining) - self.assertRaises(ValueError, self.db.combining, 'xx') + self.assertRaises(TypeError, self.db.combining, 'xx') def test_pr29(self): # https://www.unicode.org/review/pr-29.html @@ -239,8 +239,8 @@ def test_east_asian_width(self): eaw = self.db.east_asian_width self.assertRaises(TypeError, eaw, b'a') self.assertRaises(TypeError, eaw, bytearray()) - self.assertRaises(ValueError, eaw, '') - self.assertRaises(ValueError, eaw, 'ra') + self.assertRaises(TypeError, eaw, '') + self.assertRaises(TypeError, eaw, 'ra') self.assertEqual(eaw('\x1e'), 'N') self.assertEqual(eaw('\x20'), 'Na') self.assertEqual(eaw('\uC894'), 'W') diff --git a/Modules/clinic/_testclinic.c.h b/Modules/clinic/_testclinic.c.h index f548396fe687e2..eccea6702c52a3 100644 --- a/Modules/clinic/_testclinic.c.h +++ b/Modules/clinic/_testclinic.c.h @@ -648,8 +648,8 @@ int_converter(PyObject *module, PyObject *const *args, Py_ssize_t nargs) goto exit; } if (PyUnicode_GET_LENGTH(args[2]) != 1) { - PyErr_Format(PyExc_ValueError, - "int_converter(): argument 3 must be a single unicode character, not %T", + PyErr_Format(PyExc_TypeError, + "int_converter(): argument 3 must be exactly one character long, not %T", args[2]); goto exit; } @@ -3165,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=e96c223b763729db input=a9049054013a1b77]*/ +/*[clinic end generated code: output=efbf18a3c23de5e3 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/arraymodule.c.h b/Modules/clinic/arraymodule.c.h index caf9de8bc22ff1..6c602f1bb72f9f 100644 --- a/Modules/clinic/arraymodule.c.h +++ b/Modules/clinic/arraymodule.c.h @@ -596,8 +596,8 @@ array__array_reconstructor(PyObject *module, PyObject *const *args, Py_ssize_t n goto exit; } if (PyUnicode_GET_LENGTH(args[1]) != 1) { - PyErr_Format(PyExc_ValueError, - "_array_reconstructor(): argument 2 must be a single unicode character, not %T", + PyErr_Format(PyExc_TypeError, + "_array_reconstructor(): argument 2 must be exactly one character long, not %T", args[1]); goto exit; } @@ -687,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=e65b6b6a624901d1 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=f87c52e879636326 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/unicodedata.c.h b/Modules/clinic/unicodedata.c.h index 8513defd142579..36e6b7400124a9 100644 --- a/Modules/clinic/unicodedata.c.h +++ b/Modules/clinic/unicodedata.c.h @@ -36,8 +36,8 @@ unicodedata_UCD_decimal(PyObject *self, PyObject *const *args, Py_ssize_t nargs) goto exit; } if (PyUnicode_GET_LENGTH(args[0]) != 1) { - PyErr_Format(PyExc_ValueError, - "decimal(): argument 1 must be a single unicode character, not %T", + PyErr_Format(PyExc_TypeError, + "decimal(): argument 1 must be exactly one character long, not %T", args[0]); goto exit; } @@ -84,8 +84,8 @@ unicodedata_UCD_digit(PyObject *self, PyObject *const *args, Py_ssize_t nargs) goto exit; } if (PyUnicode_GET_LENGTH(args[0]) != 1) { - PyErr_Format(PyExc_ValueError, - "digit(): argument 1 must be a single unicode character, not %T", + PyErr_Format(PyExc_TypeError, + "digit(): argument 1 must be exactly one character long, not %T", args[0]); goto exit; } @@ -133,8 +133,8 @@ unicodedata_UCD_numeric(PyObject *self, PyObject *const *args, Py_ssize_t nargs) goto exit; } if (PyUnicode_GET_LENGTH(args[0]) != 1) { - PyErr_Format(PyExc_ValueError, - "numeric(): argument 1 must be a single unicode character, not %T", + PyErr_Format(PyExc_TypeError, + "numeric(): argument 1 must be exactly one character long, not %T", args[0]); goto exit; } @@ -173,8 +173,8 @@ unicodedata_UCD_category(PyObject *self, PyObject *arg) goto exit; } if (PyUnicode_GET_LENGTH(arg) != 1) { - PyErr_Format(PyExc_ValueError, - "category(): argument must be a single unicode character, not %T", + PyErr_Format(PyExc_TypeError, + "category(): argument must be exactly one character long, not %T", arg); goto exit; } @@ -210,8 +210,8 @@ unicodedata_UCD_bidirectional(PyObject *self, PyObject *arg) goto exit; } if (PyUnicode_GET_LENGTH(arg) != 1) { - PyErr_Format(PyExc_ValueError, - "bidirectional(): argument must be a single unicode character, not %T", + PyErr_Format(PyExc_TypeError, + "bidirectional(): argument must be exactly one character long, not %T", arg); goto exit; } @@ -248,8 +248,8 @@ unicodedata_UCD_combining(PyObject *self, PyObject *arg) goto exit; } if (PyUnicode_GET_LENGTH(arg) != 1) { - PyErr_Format(PyExc_ValueError, - "combining(): argument must be a single unicode character, not %T", + PyErr_Format(PyExc_TypeError, + "combining(): argument must be exactly one character long, not %T", arg); goto exit; } @@ -291,8 +291,8 @@ unicodedata_UCD_mirrored(PyObject *self, PyObject *arg) goto exit; } if (PyUnicode_GET_LENGTH(arg) != 1) { - PyErr_Format(PyExc_ValueError, - "mirrored(): argument must be a single unicode character, not %T", + PyErr_Format(PyExc_TypeError, + "mirrored(): argument must be exactly one character long, not %T", arg); goto exit; } @@ -330,8 +330,8 @@ unicodedata_UCD_east_asian_width(PyObject *self, PyObject *arg) goto exit; } if (PyUnicode_GET_LENGTH(arg) != 1) { - PyErr_Format(PyExc_ValueError, - "east_asian_width(): argument must be a single unicode character, not %T", + PyErr_Format(PyExc_TypeError, + "east_asian_width(): argument must be exactly one character long, not %T", arg); goto exit; } @@ -367,8 +367,8 @@ unicodedata_UCD_decomposition(PyObject *self, PyObject *arg) goto exit; } if (PyUnicode_GET_LENGTH(arg) != 1) { - PyErr_Format(PyExc_ValueError, - "decomposition(): argument must be a single unicode character, not %T", + PyErr_Format(PyExc_TypeError, + "decomposition(): argument must be exactly one character long, not %T", arg); goto exit; } @@ -491,8 +491,8 @@ unicodedata_UCD_name(PyObject *self, PyObject *const *args, Py_ssize_t nargs) goto exit; } if (PyUnicode_GET_LENGTH(args[0]) != 1) { - PyErr_Format(PyExc_ValueError, - "name(): argument 1 must be a single unicode character, not %T", + PyErr_Format(PyExc_TypeError, + "name(): argument 1 must be exactly one character long, not %T", args[0]); goto exit; } @@ -539,4 +539,4 @@ unicodedata_UCD_lookup(PyObject *self, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=a523cb9d95c65999 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=88b439204c969e4d input=a9049054013a1b77]*/ diff --git a/PC/clinic/msvcrtmodule.c.h b/PC/clinic/msvcrtmodule.c.h index cd70200c2cd965..4faa21e169d29c 100644 --- a/PC/clinic/msvcrtmodule.c.h +++ b/PC/clinic/msvcrtmodule.c.h @@ -396,8 +396,8 @@ msvcrt_putwch(PyObject *module, PyObject *arg) goto exit; } if (PyUnicode_GET_LENGTH(arg) != 1) { - PyErr_Format(PyExc_ValueError, - "putwch(): argument must be a single unicode character, not %T", + PyErr_Format(PyExc_TypeError, + "putwch(): argument must be exactly one character long, not %T", arg); goto exit; } @@ -473,8 +473,8 @@ msvcrt_ungetwch(PyObject *module, PyObject *arg) goto exit; } if (PyUnicode_GET_LENGTH(arg) != 1) { - PyErr_Format(PyExc_ValueError, - "ungetwch(): argument must be a single unicode character, not %T", + PyErr_Format(PyExc_TypeError, + "ungetwch(): argument must be exactly one character long, not %T", arg); goto exit; } @@ -701,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=8572a2bd458907f5 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=9635f1093e1136ca input=a9049054013a1b77]*/ diff --git a/Tools/clinic/libclinic/converters.py b/Tools/clinic/libclinic/converters.py index e5ba9e502fe46a..d744eccb7f7ce1 100644 --- a/Tools/clinic/libclinic/converters.py +++ b/Tools/clinic/libclinic/converters.py @@ -272,8 +272,8 @@ def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> st goto exit; }}}} if (PyUnicode_GET_LENGTH({argname}) != 1) {{{{ - PyErr_Format(PyExc_ValueError, - "{{name}}(): {displayname} must be a single unicode character, not %T", + PyErr_Format(PyExc_TypeError, + "{{name}}(): {displayname} must be exactly one character long, not %T", {argname}); goto exit; }}}} From 35586b101de5f5a72a07602fa54ce0420f63021c Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 5 Apr 2024 13:08:08 +0200 Subject: [PATCH 5/8] Add NEWS --- .../Tools-Demos/2024-04-05-13-08-02.gh-issue-117557.tPewu9.rst | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 Misc/NEWS.d/next/Tools-Demos/2024-04-05-13-08-02.gh-issue-117557.tPewu9.rst 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. From 98362598fe0c88803fbe104fb01c5940ca1f536c Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 5 Apr 2024 13:10:26 +0200 Subject: [PATCH 6/8] Amendment --- Lib/test/clinic.test.c | 7 ++-- Modules/clinic/_testclinic.c.h | 7 ++-- Modules/clinic/arraymodule.c.h | 7 ++-- Modules/clinic/unicodedata.c.h | 52 +++++++++++----------------- PC/clinic/msvcrtmodule.c.h | 12 +++---- Tools/clinic/libclinic/converters.py | 5 ++- 6 files changed, 37 insertions(+), 53 deletions(-) diff --git a/Lib/test/clinic.test.c b/Lib/test/clinic.test.c index 96e1f37ed81350..d1eca50ff006a7 100644 --- a/Lib/test/clinic.test.c +++ b/Lib/test/clinic.test.c @@ -1028,9 +1028,8 @@ test_int_converter(PyObject *module, PyObject *const *args, Py_ssize_t nargs) goto exit; } if (PyUnicode_GET_LENGTH(args[2]) != 1) { - PyErr_Format(PyExc_TypeError, - "test_int_converter(): argument 3 must be exactly one character long, not %T", - args[2]); + PyErr_SetString(PyExc_TypeError, + "test_int_converter(): argument 3 must be exactly one character long"); goto exit; } c = PyUnicode_READ_CHAR(args[2], 0); @@ -1050,7 +1049,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=ef1676a7f1b18b1d input=d20541fc1ca0553e]*/ +/*[clinic end generated code: output=fd8e758049e1d836 input=d20541fc1ca0553e]*/ /*[clinic input] diff --git a/Modules/clinic/_testclinic.c.h b/Modules/clinic/_testclinic.c.h index eccea6702c52a3..3b1f0e7912840b 100644 --- a/Modules/clinic/_testclinic.c.h +++ b/Modules/clinic/_testclinic.c.h @@ -648,9 +648,8 @@ int_converter(PyObject *module, PyObject *const *args, Py_ssize_t nargs) goto exit; } if (PyUnicode_GET_LENGTH(args[2]) != 1) { - PyErr_Format(PyExc_TypeError, - "int_converter(): argument 3 must be exactly one character long, not %T", - args[2]); + PyErr_SetString(PyExc_TypeError, + "int_converter(): argument 3 must be exactly one character long"); goto exit; } c = PyUnicode_READ_CHAR(args[2], 0); @@ -3165,4 +3164,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=efbf18a3c23de5e3 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=0cc42a88f33c93c0 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/arraymodule.c.h b/Modules/clinic/arraymodule.c.h index 6c602f1bb72f9f..281aa536f07856 100644 --- a/Modules/clinic/arraymodule.c.h +++ b/Modules/clinic/arraymodule.c.h @@ -596,9 +596,8 @@ array__array_reconstructor(PyObject *module, PyObject *const *args, Py_ssize_t n goto exit; } if (PyUnicode_GET_LENGTH(args[1]) != 1) { - PyErr_Format(PyExc_TypeError, - "_array_reconstructor(): argument 2 must be exactly one character long, not %T", - args[1]); + PyErr_SetString(PyExc_TypeError, + "_array_reconstructor(): argument 2 must be exactly one character long"); goto exit; } typecode = PyUnicode_READ_CHAR(args[1], 0); @@ -687,4 +686,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=f87c52e879636326 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=777e73110300258f input=a9049054013a1b77]*/ diff --git a/Modules/clinic/unicodedata.c.h b/Modules/clinic/unicodedata.c.h index 36e6b7400124a9..9eb60e218485d0 100644 --- a/Modules/clinic/unicodedata.c.h +++ b/Modules/clinic/unicodedata.c.h @@ -36,9 +36,8 @@ unicodedata_UCD_decimal(PyObject *self, PyObject *const *args, Py_ssize_t nargs) goto exit; } if (PyUnicode_GET_LENGTH(args[0]) != 1) { - PyErr_Format(PyExc_TypeError, - "decimal(): argument 1 must be exactly one character long, not %T", - args[0]); + PyErr_SetString(PyExc_TypeError, + "decimal(): argument 1 must be exactly one character long"); goto exit; } chr = PyUnicode_READ_CHAR(args[0], 0); @@ -84,9 +83,8 @@ unicodedata_UCD_digit(PyObject *self, PyObject *const *args, Py_ssize_t nargs) goto exit; } if (PyUnicode_GET_LENGTH(args[0]) != 1) { - PyErr_Format(PyExc_TypeError, - "digit(): argument 1 must be exactly one character long, not %T", - args[0]); + PyErr_SetString(PyExc_TypeError, + "digit(): argument 1 must be exactly one character long"); goto exit; } chr = PyUnicode_READ_CHAR(args[0], 0); @@ -133,9 +131,8 @@ unicodedata_UCD_numeric(PyObject *self, PyObject *const *args, Py_ssize_t nargs) goto exit; } if (PyUnicode_GET_LENGTH(args[0]) != 1) { - PyErr_Format(PyExc_TypeError, - "numeric(): argument 1 must be exactly one character long, not %T", - args[0]); + PyErr_SetString(PyExc_TypeError, + "numeric(): argument 1 must be exactly one character long"); goto exit; } chr = PyUnicode_READ_CHAR(args[0], 0); @@ -173,9 +170,8 @@ unicodedata_UCD_category(PyObject *self, PyObject *arg) goto exit; } if (PyUnicode_GET_LENGTH(arg) != 1) { - PyErr_Format(PyExc_TypeError, - "category(): argument must be exactly one character long, not %T", - arg); + PyErr_SetString(PyExc_TypeError, + "category(): argument must be exactly one character long"); goto exit; } chr = PyUnicode_READ_CHAR(arg, 0); @@ -210,9 +206,8 @@ unicodedata_UCD_bidirectional(PyObject *self, PyObject *arg) goto exit; } if (PyUnicode_GET_LENGTH(arg) != 1) { - PyErr_Format(PyExc_TypeError, - "bidirectional(): argument must be exactly one character long, not %T", - arg); + PyErr_SetString(PyExc_TypeError, + "bidirectional(): argument must be exactly one character long"); goto exit; } chr = PyUnicode_READ_CHAR(arg, 0); @@ -248,9 +243,8 @@ unicodedata_UCD_combining(PyObject *self, PyObject *arg) goto exit; } if (PyUnicode_GET_LENGTH(arg) != 1) { - PyErr_Format(PyExc_TypeError, - "combining(): argument must be exactly one character long, not %T", - arg); + PyErr_SetString(PyExc_TypeError, + "combining(): argument must be exactly one character long"); goto exit; } chr = PyUnicode_READ_CHAR(arg, 0); @@ -291,9 +285,8 @@ unicodedata_UCD_mirrored(PyObject *self, PyObject *arg) goto exit; } if (PyUnicode_GET_LENGTH(arg) != 1) { - PyErr_Format(PyExc_TypeError, - "mirrored(): argument must be exactly one character long, not %T", - arg); + PyErr_SetString(PyExc_TypeError, + "mirrored(): argument must be exactly one character long"); goto exit; } chr = PyUnicode_READ_CHAR(arg, 0); @@ -330,9 +323,8 @@ unicodedata_UCD_east_asian_width(PyObject *self, PyObject *arg) goto exit; } if (PyUnicode_GET_LENGTH(arg) != 1) { - PyErr_Format(PyExc_TypeError, - "east_asian_width(): argument must be exactly one character long, not %T", - arg); + PyErr_SetString(PyExc_TypeError, + "east_asian_width(): argument must be exactly one character long"); goto exit; } chr = PyUnicode_READ_CHAR(arg, 0); @@ -367,9 +359,8 @@ unicodedata_UCD_decomposition(PyObject *self, PyObject *arg) goto exit; } if (PyUnicode_GET_LENGTH(arg) != 1) { - PyErr_Format(PyExc_TypeError, - "decomposition(): argument must be exactly one character long, not %T", - arg); + PyErr_SetString(PyExc_TypeError, + "decomposition(): argument must be exactly one character long"); goto exit; } chr = PyUnicode_READ_CHAR(arg, 0); @@ -491,9 +482,8 @@ unicodedata_UCD_name(PyObject *self, PyObject *const *args, Py_ssize_t nargs) goto exit; } if (PyUnicode_GET_LENGTH(args[0]) != 1) { - PyErr_Format(PyExc_TypeError, - "name(): argument 1 must be exactly one character long, not %T", - args[0]); + PyErr_SetString(PyExc_TypeError, + "name(): argument 1 must be exactly one character long"); goto exit; } chr = PyUnicode_READ_CHAR(args[0], 0); @@ -539,4 +529,4 @@ unicodedata_UCD_lookup(PyObject *self, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=88b439204c969e4d input=a9049054013a1b77]*/ +/*[clinic end generated code: output=1a5c1195b439dbca input=a9049054013a1b77]*/ diff --git a/PC/clinic/msvcrtmodule.c.h b/PC/clinic/msvcrtmodule.c.h index 4faa21e169d29c..72d34719a35999 100644 --- a/PC/clinic/msvcrtmodule.c.h +++ b/PC/clinic/msvcrtmodule.c.h @@ -396,9 +396,8 @@ msvcrt_putwch(PyObject *module, PyObject *arg) goto exit; } if (PyUnicode_GET_LENGTH(arg) != 1) { - PyErr_Format(PyExc_TypeError, - "putwch(): argument must be exactly one character long, not %T", - arg); + PyErr_SetString(PyExc_TypeError, + "putwch(): argument must be exactly one character long"); goto exit; } unicode_char = PyUnicode_READ_CHAR(arg, 0); @@ -473,9 +472,8 @@ msvcrt_ungetwch(PyObject *module, PyObject *arg) goto exit; } if (PyUnicode_GET_LENGTH(arg) != 1) { - PyErr_Format(PyExc_TypeError, - "ungetwch(): argument must be exactly one character long, not %T", - arg); + PyErr_SetString(PyExc_TypeError, + "ungetwch(): argument must be exactly one character long"); goto exit; } unicode_char = PyUnicode_READ_CHAR(arg, 0); @@ -701,4 +699,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=9635f1093e1136ca input=a9049054013a1b77]*/ +/*[clinic end generated code: output=ca7f38fa5bf7043e input=a9049054013a1b77]*/ diff --git a/Tools/clinic/libclinic/converters.py b/Tools/clinic/libclinic/converters.py index d744eccb7f7ce1..a1dc1ea4c4ec92 100644 --- a/Tools/clinic/libclinic/converters.py +++ b/Tools/clinic/libclinic/converters.py @@ -272,9 +272,8 @@ def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> st goto exit; }}}} if (PyUnicode_GET_LENGTH({argname}) != 1) {{{{ - PyErr_Format(PyExc_TypeError, - "{{name}}(): {displayname} must be exactly one character long, not %T", - {argname}); + PyErr_SetString(PyExc_TypeError, + "{{name}}(): {displayname} must be exactly one character long"); goto exit; }}}} {paramname} = PyUnicode_READ_CHAR({argname}, 0); From fe02eddf96e9b03d4b16a2da67883fe312eb43f1 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 5 Apr 2024 23:39:01 +0200 Subject: [PATCH 7/8] Address Serhiy's review - try to make the error message even clearer - sync with PyArg_Parse --- Lib/test/clinic.test.c | 5 +++-- Modules/clinic/_testclinic.c.h | 5 +++-- Modules/clinic/arraymodule.c.h | 5 +++-- Modules/clinic/unicodedata.c.h | 32 ++++++++++++++++++---------- PC/clinic/msvcrtmodule.c.h | 8 ++++--- Python/getargs.c | 7 ++++-- Tools/clinic/libclinic/converters.py | 3 ++- 7 files changed, 42 insertions(+), 23 deletions(-) diff --git a/Lib/test/clinic.test.c b/Lib/test/clinic.test.c index d1eca50ff006a7..7d2a1bb66cc9b1 100644 --- a/Lib/test/clinic.test.c +++ b/Lib/test/clinic.test.c @@ -1029,7 +1029,8 @@ test_int_converter(PyObject *module, PyObject *const *args, Py_ssize_t nargs) } if (PyUnicode_GET_LENGTH(args[2]) != 1) { PyErr_SetString(PyExc_TypeError, - "test_int_converter(): argument 3 must be exactly one character long"); + "test_int_converter(): argument 3 must be a string containing " + "exactly one unicode character"); goto exit; } c = PyUnicode_READ_CHAR(args[2], 0); @@ -1049,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=fd8e758049e1d836 input=d20541fc1ca0553e]*/ +/*[clinic end generated code: output=9c44e10850d9b44c input=d20541fc1ca0553e]*/ /*[clinic input] diff --git a/Modules/clinic/_testclinic.c.h b/Modules/clinic/_testclinic.c.h index 3b1f0e7912840b..7d3e1dd83a7897 100644 --- a/Modules/clinic/_testclinic.c.h +++ b/Modules/clinic/_testclinic.c.h @@ -649,7 +649,8 @@ int_converter(PyObject *module, PyObject *const *args, Py_ssize_t nargs) } if (PyUnicode_GET_LENGTH(args[2]) != 1) { PyErr_SetString(PyExc_TypeError, - "int_converter(): argument 3 must be exactly one character long"); + "int_converter(): argument 3 must be a string containing " + "exactly one unicode character"); goto exit; } c = PyUnicode_READ_CHAR(args[2], 0); @@ -3164,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=0cc42a88f33c93c0 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 281aa536f07856..7b0b5a4fdedd5f 100644 --- a/Modules/clinic/arraymodule.c.h +++ b/Modules/clinic/arraymodule.c.h @@ -597,7 +597,8 @@ array__array_reconstructor(PyObject *module, PyObject *const *args, Py_ssize_t n } if (PyUnicode_GET_LENGTH(args[1]) != 1) { PyErr_SetString(PyExc_TypeError, - "_array_reconstructor(): argument 2 must be exactly one character long"); + "_array_reconstructor(): argument 2 must be a string containing " + "exactly one unicode character"); goto exit; } typecode = PyUnicode_READ_CHAR(args[1], 0); @@ -686,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=777e73110300258f 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 9eb60e218485d0..68ae8e5928b74d 100644 --- a/Modules/clinic/unicodedata.c.h +++ b/Modules/clinic/unicodedata.c.h @@ -37,7 +37,8 @@ unicodedata_UCD_decimal(PyObject *self, PyObject *const *args, Py_ssize_t nargs) } if (PyUnicode_GET_LENGTH(args[0]) != 1) { PyErr_SetString(PyExc_TypeError, - "decimal(): argument 1 must be exactly one character long"); + "decimal(): argument 1 must be a string containing " + "exactly one unicode character"); goto exit; } chr = PyUnicode_READ_CHAR(args[0], 0); @@ -84,7 +85,8 @@ unicodedata_UCD_digit(PyObject *self, PyObject *const *args, Py_ssize_t nargs) } if (PyUnicode_GET_LENGTH(args[0]) != 1) { PyErr_SetString(PyExc_TypeError, - "digit(): argument 1 must be exactly one character long"); + "digit(): argument 1 must be a string containing " + "exactly one unicode character"); goto exit; } chr = PyUnicode_READ_CHAR(args[0], 0); @@ -132,7 +134,8 @@ unicodedata_UCD_numeric(PyObject *self, PyObject *const *args, Py_ssize_t nargs) } if (PyUnicode_GET_LENGTH(args[0]) != 1) { PyErr_SetString(PyExc_TypeError, - "numeric(): argument 1 must be exactly one character long"); + "numeric(): argument 1 must be a string containing " + "exactly one unicode character"); goto exit; } chr = PyUnicode_READ_CHAR(args[0], 0); @@ -171,7 +174,8 @@ unicodedata_UCD_category(PyObject *self, PyObject *arg) } if (PyUnicode_GET_LENGTH(arg) != 1) { PyErr_SetString(PyExc_TypeError, - "category(): argument must be exactly one character long"); + "category(): argument must be a string containing " + "exactly one unicode character"); goto exit; } chr = PyUnicode_READ_CHAR(arg, 0); @@ -207,7 +211,8 @@ unicodedata_UCD_bidirectional(PyObject *self, PyObject *arg) } if (PyUnicode_GET_LENGTH(arg) != 1) { PyErr_SetString(PyExc_TypeError, - "bidirectional(): argument must be exactly one character long"); + "bidirectional(): argument must be a string containing " + "exactly one unicode character"); goto exit; } chr = PyUnicode_READ_CHAR(arg, 0); @@ -244,7 +249,8 @@ unicodedata_UCD_combining(PyObject *self, PyObject *arg) } if (PyUnicode_GET_LENGTH(arg) != 1) { PyErr_SetString(PyExc_TypeError, - "combining(): argument must be exactly one character long"); + "combining(): argument must be a string containing " + "exactly one unicode character"); goto exit; } chr = PyUnicode_READ_CHAR(arg, 0); @@ -286,7 +292,8 @@ unicodedata_UCD_mirrored(PyObject *self, PyObject *arg) } if (PyUnicode_GET_LENGTH(arg) != 1) { PyErr_SetString(PyExc_TypeError, - "mirrored(): argument must be exactly one character long"); + "mirrored(): argument must be a string containing " + "exactly one unicode character"); goto exit; } chr = PyUnicode_READ_CHAR(arg, 0); @@ -324,7 +331,8 @@ unicodedata_UCD_east_asian_width(PyObject *self, PyObject *arg) } if (PyUnicode_GET_LENGTH(arg) != 1) { PyErr_SetString(PyExc_TypeError, - "east_asian_width(): argument must be exactly one character long"); + "east_asian_width(): argument must be a string containing " + "exactly one unicode character"); goto exit; } chr = PyUnicode_READ_CHAR(arg, 0); @@ -360,7 +368,8 @@ unicodedata_UCD_decomposition(PyObject *self, PyObject *arg) } if (PyUnicode_GET_LENGTH(arg) != 1) { PyErr_SetString(PyExc_TypeError, - "decomposition(): argument must be exactly one character long"); + "decomposition(): argument must be a string containing " + "exactly one unicode character"); goto exit; } chr = PyUnicode_READ_CHAR(arg, 0); @@ -483,7 +492,8 @@ unicodedata_UCD_name(PyObject *self, PyObject *const *args, Py_ssize_t nargs) } if (PyUnicode_GET_LENGTH(args[0]) != 1) { PyErr_SetString(PyExc_TypeError, - "name(): argument 1 must be exactly one character long"); + "name(): argument 1 must be a string containing " + "exactly one unicode character"); goto exit; } chr = PyUnicode_READ_CHAR(args[0], 0); @@ -529,4 +539,4 @@ unicodedata_UCD_lookup(PyObject *self, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=1a5c1195b439dbca 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 72d34719a35999..6d80ea5c301c74 100644 --- a/PC/clinic/msvcrtmodule.c.h +++ b/PC/clinic/msvcrtmodule.c.h @@ -397,7 +397,8 @@ msvcrt_putwch(PyObject *module, PyObject *arg) } if (PyUnicode_GET_LENGTH(arg) != 1) { PyErr_SetString(PyExc_TypeError, - "putwch(): argument must be exactly one character long"); + "putwch(): argument must be a string containing " + "exactly one unicode character"); goto exit; } unicode_char = PyUnicode_READ_CHAR(arg, 0); @@ -473,7 +474,8 @@ msvcrt_ungetwch(PyObject *module, PyObject *arg) } if (PyUnicode_GET_LENGTH(arg) != 1) { PyErr_SetString(PyExc_TypeError, - "ungetwch(): argument must be exactly one character long"); + "ungetwch(): argument must be a string containing " + "exactly one unicode character"); goto exit; } unicode_char = PyUnicode_READ_CHAR(arg, 0); @@ -699,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=ca7f38fa5bf7043e input=a9049054013a1b77]*/ +/*[clinic end generated code: output=32225d72078b5172 input=a9049054013a1b77]*/ diff --git a/Python/getargs.c b/Python/getargs.c index bec981698767ca..ee4173964ed661 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 a1dc1ea4c4ec92..de75d7326137ea 100644 --- a/Tools/clinic/libclinic/converters.py +++ b/Tools/clinic/libclinic/converters.py @@ -273,7 +273,8 @@ def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> st }}}} if (PyUnicode_GET_LENGTH({argname}) != 1) {{{{ PyErr_SetString(PyExc_TypeError, - "{{name}}(): {displayname} must be exactly one character long"); + "{{name}}(): {displayname} must be a string containing " + "exactly one unicode character"); goto exit; }}}} {paramname} = PyUnicode_READ_CHAR({argname}, 0); From 5586fcdf4ccdbc356cbd4c57232c182a035b29bc Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 5 Apr 2024 23:41:06 +0200 Subject: [PATCH 8/8] Syntax error --- Python/getargs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/getargs.c b/Python/getargs.c index ee4173964ed661..efe9ba695c6266 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -579,7 +579,7 @@ converterr(const char *expected, PyObject *arg, char *msgbuf, size_t bufsize) PyOS_snprintf(msgbuf, bufsize, "%.100s", expected); } - else if (arg == NULL} { + else if (arg == NULL) { PyOS_snprintf(msgbuf, bufsize, "must be %.100s", expected); } else {