diff options
author | RĂ©mi Lapeyre <remi.lapeyre@henki.fr> | 2019-08-29 14:49:08 (GMT) |
---|---|---|
committer | Serhiy Storchaka <storchaka@gmail.com> | 2019-08-29 14:49:08 (GMT) |
commit | 4901fe274bc82b95dc89bcb3de8802a3dfedab32 (patch) | |
tree | 2e6e4d0b1cdcb499df7f049ebc9dbbdb9f392bbe /Tools/clinic | |
parent | 59725f3badb3028636c8906ecac4ceb0a37f3982 (diff) | |
download | cpython-4901fe274bc82b95dc89bcb3de8802a3dfedab32.zip cpython-4901fe274bc82b95dc89bcb3de8802a3dfedab32.tar.gz cpython-4901fe274bc82b95dc89bcb3de8802a3dfedab32.tar.bz2 |
bpo-37034: Display argument name on errors with keyword arguments with Argument Clinic. (GH-13593)
Diffstat (limited to 'Tools/clinic')
-rwxr-xr-x | Tools/clinic/clinic.py | 181 |
1 files changed, 101 insertions, 80 deletions
diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index d5863a3..cec7c53 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -806,7 +806,8 @@ class CLanguage(Language): {c_basename}({self_type}{self_name}, PyObject *%s) """ % argname) - parsearg = converters[0].parse_arg(argname, 0) + displayname = parameters[0].get_displayname(0) + parsearg = converters[0].parse_arg(argname, displayname) if parsearg is None: parsearg = """ if (!PyArg_Parse(%s, "{format_units}:{name}", {parse_arguments})) {{ @@ -851,7 +852,8 @@ class CLanguage(Language): """ % (nargs, min_pos, max_pos), indent=4)] has_optional = False for i, p in enumerate(parameters): - parsearg = p.converter.parse_arg(argname_fmt % i, i + 1) + displayname = p.get_displayname(i+1) + parsearg = p.converter.parse_arg(argname_fmt % i, displayname) if parsearg is None: #print('Cannot convert %s %r for %s' % (p.converter.__class__.__name__, p.converter.format_unit, p.converter.name), file=sys.stderr) parser_code = None @@ -927,7 +929,8 @@ class CLanguage(Language): add_label = None for i, p in enumerate(parameters): - parsearg = p.converter.parse_arg(argname_fmt % i, i + 1) + displayname = p.get_displayname(i+1) + parsearg = p.converter.parse_arg(argname_fmt % i, displayname) if parsearg is None: #print('Cannot convert %s %r for %s' % (p.converter.__class__.__name__, p.converter.format_unit, p.converter.name), file=sys.stderr) parser_code = None @@ -2287,6 +2290,13 @@ class Parameter: kwargs['converter'] = converter return Parameter(**kwargs) + def get_displayname(self, i): + if i == 0: + return '"argument"' + if not self.is_positional_only(): + return '''"argument '{}'"'''.format(self.name) + else: + return '"argument {}"'.format(i) class LandMine: @@ -2634,7 +2644,7 @@ class CConverter(metaclass=CConverterAutoRegister): """ pass - def parse_arg(self, argname, argnum): + def parse_arg(self, argname, displayname): if self.format_unit == 'O&': return """ if (!{converter}({argname}, &{paramname})) {{{{ @@ -2648,21 +2658,22 @@ class CConverter(metaclass=CConverterAutoRegister): typecheck, typename = type_checks[self.subclass_of] return """ if (!{typecheck}({argname})) {{{{ - _PyArg_BadArgument("{{name}}", {argnum}, "{typename}", {argname}); + _PyArg_BadArgument("{{name}}", {displayname}, "{typename}", {argname}); goto exit; }}}} {paramname} = {cast}{argname}; """.format(argname=argname, paramname=self.name, - argnum=argnum, - typecheck=typecheck, typename=typename, cast=cast) + displayname=displayname, typecheck=typecheck, + typename=typename, cast=cast) return """ if (!PyObject_TypeCheck({argname}, {subclass_of})) {{{{ - _PyArg_BadArgument("{{name}}", {argnum}, ({subclass_of})->tp_name, {argname}); + _PyArg_BadArgument("{{name}}", {displayname}, ({subclass_of})->tp_name, {argname}); goto exit; }}}} {paramname} = {cast}{argname}; - """.format(argname=argname, paramname=self.name, argnum=argnum, - subclass_of=self.subclass_of, cast=cast) + """.format(argname=argname, paramname=self.name, + subclass_of=self.subclass_of, cast=cast, + displayname=displayname) if self.format_unit == 'O': cast = '(%s)' % self.type if self.type != 'PyObject *' else '' return """ @@ -2698,7 +2709,7 @@ class bool_converter(CConverter): self.default = bool(self.default) self.c_default = str(int(self.default)) - def parse_arg(self, argname, argnum): + def parse_arg(self, argname, displayname): if self.format_unit == 'i': # XXX PyFloat_Check can be removed after the end of the # deprecation in _PyLong_FromNbIndexOrNbInt. @@ -2720,7 +2731,7 @@ class bool_converter(CConverter): goto exit; }}}} """.format(argname=argname, paramname=self.name) - return super().parse_arg(argname, argnum) + return super().parse_arg(argname, displayname) class char_converter(CConverter): type = 'char' @@ -2737,7 +2748,7 @@ class char_converter(CConverter): if self.c_default == '"\'"': self.c_default = r"'\''" - def parse_arg(self, argname, argnum): + def parse_arg(self, argname, displayname): if self.format_unit == 'c': return """ if (PyBytes_Check({argname}) && PyBytes_GET_SIZE({argname}) == 1) {{{{ @@ -2747,11 +2758,12 @@ class char_converter(CConverter): {paramname} = PyByteArray_AS_STRING({argname})[0]; }}}} else {{{{ - _PyArg_BadArgument("{{name}}", {argnum}, "a byte string of length 1", {argname}); + _PyArg_BadArgument("{{name}}", {displayname}, "a byte string of length 1", {argname}); goto exit; }}}} - """.format(argname=argname, paramname=self.name, argnum=argnum) - return super().parse_arg(argname, argnum) + """.format(argname=argname, paramname=self.name, + displayname=displayname) + return super().parse_arg(argname, displayname) @add_legacy_c_converter('B', bitwise=True) @@ -2765,7 +2777,7 @@ class unsigned_char_converter(CConverter): if bitwise: self.format_unit = 'B' - def parse_arg(self, argname, argnum): + def parse_arg(self, argname, displayname): if self.format_unit == 'b': return """ if (PyFloat_Check({argname})) {{{{ @@ -2810,7 +2822,7 @@ class unsigned_char_converter(CConverter): }}}} }}}} """.format(argname=argname, paramname=self.name) - return super().parse_arg(argname, argnum) + return super().parse_arg(argname, displayname) class byte_converter(unsigned_char_converter): pass @@ -2820,7 +2832,7 @@ class short_converter(CConverter): format_unit = 'h' c_ignored_default = "0" - def parse_arg(self, argname, argnum): + def parse_arg(self, argname, displayname): if self.format_unit == 'h': return """ if (PyFloat_Check({argname})) {{{{ @@ -2848,7 +2860,7 @@ class short_converter(CConverter): }}}} }}}} """.format(argname=argname, paramname=self.name) - return super().parse_arg(argname, argnum) + return super().parse_arg(argname, displayname) class unsigned_short_converter(CConverter): type = 'unsigned short' @@ -2861,7 +2873,7 @@ class unsigned_short_converter(CConverter): else: self.converter = '_PyLong_UnsignedShort_Converter' - def parse_arg(self, argname, argnum): + def parse_arg(self, argname, displayname): if self.format_unit == 'H': return """ if (PyFloat_Check({argname})) {{{{ @@ -2874,7 +2886,7 @@ class unsigned_short_converter(CConverter): goto exit; }}}} """.format(argname=argname, paramname=self.name) - return super().parse_arg(argname, argnum) + return super().parse_arg(argname, displayname) @add_legacy_c_converter('C', accept={str}) class int_converter(CConverter): @@ -2891,7 +2903,7 @@ class int_converter(CConverter): if type != None: self.type = type - def parse_arg(self, argname, argnum): + def parse_arg(self, argname, displayname): if self.format_unit == 'i': return """ if (PyFloat_Check({argname})) {{{{ @@ -2907,19 +2919,20 @@ class int_converter(CConverter): elif self.format_unit == 'C': return """ if (!PyUnicode_Check({argname})) {{{{ - _PyArg_BadArgument("{{name}}", {argnum}, "a unicode character", {argname}); + _PyArg_BadArgument("{{name}}", {displayname}, "a unicode character", {argname}); goto exit; }}}} if (PyUnicode_READY({argname})) {{{{ goto exit; }}}} if (PyUnicode_GET_LENGTH({argname}) != 1) {{{{ - _PyArg_BadArgument("{{name}}", {argnum}, "a unicode character", {argname}); + _PyArg_BadArgument("{{name}}", {displayname}, "a unicode character", {argname}); goto exit; }}}} {paramname} = PyUnicode_READ_CHAR({argname}, 0); - """.format(argname=argname, paramname=self.name, argnum=argnum) - return super().parse_arg(argname, argnum) + """.format(argname=argname, paramname=self.name, + displayname=displayname) + return super().parse_arg(argname, displayname) class unsigned_int_converter(CConverter): type = 'unsigned int' @@ -2932,7 +2945,7 @@ class unsigned_int_converter(CConverter): else: self.converter = '_PyLong_UnsignedInt_Converter' - def parse_arg(self, argname, argnum): + def parse_arg(self, argname, displayname): if self.format_unit == 'I': return """ if (PyFloat_Check({argname})) {{{{ @@ -2945,7 +2958,7 @@ class unsigned_int_converter(CConverter): goto exit; }}}} """.format(argname=argname, paramname=self.name) - return super().parse_arg(argname, argnum) + return super().parse_arg(argname, displayname) class long_converter(CConverter): type = 'long' @@ -2953,7 +2966,7 @@ class long_converter(CConverter): format_unit = 'l' c_ignored_default = "0" - def parse_arg(self, argname, argnum): + def parse_arg(self, argname, displayname): if self.format_unit == 'l': return """ if (PyFloat_Check({argname})) {{{{ @@ -2966,7 +2979,7 @@ class long_converter(CConverter): goto exit; }}}} """.format(argname=argname, paramname=self.name) - return super().parse_arg(argname, argnum) + return super().parse_arg(argname, displayname) class unsigned_long_converter(CConverter): type = 'unsigned long' @@ -2979,16 +2992,17 @@ class unsigned_long_converter(CConverter): else: self.converter = '_PyLong_UnsignedLong_Converter' - def parse_arg(self, argname, argnum): + def parse_arg(self, argname, displayname): if self.format_unit == 'k': return """ if (!PyLong_Check({argname})) {{{{ - _PyArg_BadArgument("{{name}}", {argnum}, "int", {argname}); + _PyArg_BadArgument("{{name}}", {displayname}, "int", {argname}); goto exit; }}}} {paramname} = PyLong_AsUnsignedLongMask({argname}); - """.format(argname=argname, paramname=self.name, argnum=argnum) - return super().parse_arg(argname, argnum) + """.format(argname=argname, paramname=self.name, + displayname=displayname) + return super().parse_arg(argname, displayname) class long_long_converter(CConverter): type = 'long long' @@ -2996,7 +3010,7 @@ class long_long_converter(CConverter): format_unit = 'L' c_ignored_default = "0" - def parse_arg(self, argname, argnum): + def parse_arg(self, argname, displayname): if self.format_unit == 'L': return """ if (PyFloat_Check({argname})) {{{{ @@ -3009,7 +3023,7 @@ class long_long_converter(CConverter): goto exit; }}}} """.format(argname=argname, paramname=self.name) - return super().parse_arg(argname, argnum) + return super().parse_arg(argname, displayname) class unsigned_long_long_converter(CConverter): type = 'unsigned long long' @@ -3022,16 +3036,17 @@ class unsigned_long_long_converter(CConverter): else: self.converter = '_PyLong_UnsignedLongLong_Converter' - def parse_arg(self, argname, argnum): + def parse_arg(self, argname, displayname): if self.format_unit == 'K': return """ if (!PyLong_Check({argname})) {{{{ - _PyArg_BadArgument("{{name}}", {argnum}, "int", {argname}); + _PyArg_BadArgument("{{name}}", {displayname}, "int", {argname}); goto exit; }}}} {paramname} = PyLong_AsUnsignedLongLongMask({argname}); - """.format(argname=argname, paramname=self.name, argnum=argnum) - return super().parse_arg(argname, argnum) + """.format(argname=argname, paramname=self.name, + displayname=displayname) + return super().parse_arg(argname, displayname) class Py_ssize_t_converter(CConverter): type = 'Py_ssize_t' @@ -3046,7 +3061,7 @@ class Py_ssize_t_converter(CConverter): else: fail("Py_ssize_t_converter: illegal 'accept' argument " + repr(accept)) - def parse_arg(self, argname, argnum): + def parse_arg(self, argname, displayname): if self.format_unit == 'n': return """ if (PyFloat_Check({argname})) {{{{ @@ -3067,7 +3082,7 @@ class Py_ssize_t_converter(CConverter): {paramname} = ival; }}}} """.format(argname=argname, paramname=self.name) - return super().parse_arg(argname, argnum) + return super().parse_arg(argname, displayname) class slice_index_converter(CConverter): @@ -3086,7 +3101,7 @@ class size_t_converter(CConverter): converter = '_PyLong_Size_t_Converter' c_ignored_default = "0" - def parse_arg(self, argname, argnum): + def parse_arg(self, argname, displayname): if self.format_unit == 'n': return """ {paramname} = PyNumber_AsSsize_t({argname}, PyExc_OverflowError); @@ -3094,7 +3109,7 @@ class size_t_converter(CConverter): goto exit; }}}} """.format(argname=argname, paramname=self.name) - return super().parse_arg(argname, argnum) + return super().parse_arg(argname, displayname) class float_converter(CConverter): @@ -3103,7 +3118,7 @@ class float_converter(CConverter): format_unit = 'f' c_ignored_default = "0.0" - def parse_arg(self, argname, argnum): + def parse_arg(self, argname, displayname): if self.format_unit == 'f': return """ if (PyFloat_CheckExact({argname})) {{{{ @@ -3117,7 +3132,7 @@ class float_converter(CConverter): }}}} }}}} """.format(argname=argname, paramname=self.name) - return super().parse_arg(argname, argnum) + return super().parse_arg(argname, displayname) class double_converter(CConverter): type = 'double' @@ -3125,7 +3140,7 @@ class double_converter(CConverter): format_unit = 'd' c_ignored_default = "0.0" - def parse_arg(self, argname, argnum): + def parse_arg(self, argname, displayname): if self.format_unit == 'd': return """ if (PyFloat_CheckExact({argname})) {{{{ @@ -3139,7 +3154,7 @@ class double_converter(CConverter): }}}} }}}} """.format(argname=argname, paramname=self.name) - return super().parse_arg(argname, argnum) + return super().parse_arg(argname, displayname) class Py_complex_converter(CConverter): @@ -3148,7 +3163,7 @@ class Py_complex_converter(CConverter): format_unit = 'D' c_ignored_default = "{0.0, 0.0}" - def parse_arg(self, argname, argnum): + def parse_arg(self, argname, displayname): if self.format_unit == 'D': return """ {paramname} = PyComplex_AsCComplex({argname}); @@ -3156,7 +3171,7 @@ class Py_complex_converter(CConverter): goto exit; }}}} """.format(argname=argname, paramname=self.name) - return super().parse_arg(argname, argnum) + return super().parse_arg(argname, displayname) class object_converter(CConverter): @@ -3222,11 +3237,11 @@ class str_converter(CConverter): name = self.name return "".join(["if (", name, ") {\n PyMem_FREE(", name, ");\n}\n"]) - def parse_arg(self, argname, argnum): + def parse_arg(self, argname, displayname): if self.format_unit == 's': return """ if (!PyUnicode_Check({argname})) {{{{ - _PyArg_BadArgument("{{name}}", {argnum}, "str", {argname}); + _PyArg_BadArgument("{{name}}", {displayname}, "str", {argname}); goto exit; }}}} Py_ssize_t {paramname}_length; @@ -3238,7 +3253,8 @@ class str_converter(CConverter): PyErr_SetString(PyExc_ValueError, "embedded null character"); goto exit; }}}} - """.format(argname=argname, paramname=self.name, argnum=argnum) + """.format(argname=argname, paramname=self.name, + displayname=displayname) if self.format_unit == 'z': return """ if ({argname} == Py_None) {{{{ @@ -3256,11 +3272,12 @@ class str_converter(CConverter): }}}} }}}} else {{{{ - _PyArg_BadArgument("{{name}}", {argnum}, "str or None", {argname}); + _PyArg_BadArgument("{{name}}", {displayname}, "str or None", {argname}); goto exit; }}}} - """.format(argname=argname, paramname=self.name, argnum=argnum) - return super().parse_arg(argname, argnum) + """.format(argname=argname, paramname=self.name, + displayname=displayname) + return super().parse_arg(argname, displayname) # # This is the fourth or fifth rewrite of registering all the @@ -3315,53 +3332,54 @@ class PyBytesObject_converter(CConverter): format_unit = 'S' # accept = {bytes} - def parse_arg(self, argname, argnum): + def parse_arg(self, argname, displayname): if self.format_unit == 'S': return """ if (!PyBytes_Check({argname})) {{{{ - _PyArg_BadArgument("{{name}}", {argnum}, "bytes", {argname}); + _PyArg_BadArgument("{{name}}", {displayname}, "bytes", {argname}); goto exit; }}}} {paramname} = ({type}){argname}; - """.format(argname=argname, paramname=self.name, argnum=argnum, - type=self.type) - return super().parse_arg(argname, argnum) + """.format(argname=argname, paramname=self.name, + type=self.type, displayname=displayname) + return super().parse_arg(argname, displayname) class PyByteArrayObject_converter(CConverter): type = 'PyByteArrayObject *' format_unit = 'Y' # accept = {bytearray} - def parse_arg(self, argname, argnum): + def parse_arg(self, argname, displayname): if self.format_unit == 'Y': return """ if (!PyByteArray_Check({argname})) {{{{ - _PyArg_BadArgument("{{name}}", {argnum}, "bytearray", {argname}); + _PyArg_BadArgument("{{name}}", {displayname}, "bytearray", {argname}); goto exit; }}}} {paramname} = ({type}){argname}; - """.format(argname=argname, paramname=self.name, argnum=argnum, - type=self.type) - return super().parse_arg(argname, argnum) + """.format(argname=argname, paramname=self.name, + type=self.type, displayname=displayname) + return super().parse_arg(argname, displayname) class unicode_converter(CConverter): type = 'PyObject *' default_type = (str, Null, NoneType) format_unit = 'U' - def parse_arg(self, argname, argnum): + def parse_arg(self, argname, displayname): if self.format_unit == 'U': return """ if (!PyUnicode_Check({argname})) {{{{ - _PyArg_BadArgument("{{name}}", {argnum}, "str", {argname}); + _PyArg_BadArgument("{{name}}", {displayname}, "str", {argname}); goto exit; }}}} if (PyUnicode_READY({argname}) == -1) {{{{ goto exit; }}}} {paramname} = {argname}; - """.format(argname=argname, paramname=self.name, argnum=argnum) - return super().parse_arg(argname, argnum) + """.format(argname=argname, paramname=self.name, + displayname=displayname) + return super().parse_arg(argname, displayname) @add_legacy_c_converter('u#', zeroes=True) @add_legacy_c_converter('Z', accept={str, NoneType}) @@ -3410,17 +3428,18 @@ class Py_buffer_converter(CConverter): name = self.name return "".join(["if (", name, ".obj) {\n PyBuffer_Release(&", name, ");\n}\n"]) - def parse_arg(self, argname, argnum): + def parse_arg(self, argname, displayname): if self.format_unit == 'y*': return """ if (PyObject_GetBuffer({argname}, &{paramname}, PyBUF_SIMPLE) != 0) {{{{ goto exit; }}}} if (!PyBuffer_IsContiguous(&{paramname}, 'C')) {{{{ - _PyArg_BadArgument("{{name}}", {argnum}, "contiguous buffer", {argname}); + _PyArg_BadArgument("{{name}}", {displayname}, "contiguous buffer", {argname}); goto exit; }}}} - """.format(argname=argname, paramname=self.name, argnum=argnum) + """.format(argname=argname, paramname=self.name, + displayname=displayname) elif self.format_unit == 's*': return """ if (PyUnicode_Check({argname})) {{{{ @@ -3436,24 +3455,26 @@ class Py_buffer_converter(CConverter): goto exit; }}}} if (!PyBuffer_IsContiguous(&{paramname}, 'C')) {{{{ - _PyArg_BadArgument("{{name}}", {argnum}, "contiguous buffer", {argname}); + _PyArg_BadArgument("{{name}}", {displayname}, "contiguous buffer", {argname}); goto exit; }}}} }}}} - """.format(argname=argname, paramname=self.name, argnum=argnum) + """.format(argname=argname, paramname=self.name, + displayname=displayname) elif self.format_unit == 'w*': return """ if (PyObject_GetBuffer({argname}, &{paramname}, PyBUF_WRITABLE) < 0) {{{{ PyErr_Clear(); - _PyArg_BadArgument("{{name}}", {argnum}, "read-write bytes-like object", {argname}); + _PyArg_BadArgument("{{name}}", {displayname}, "read-write bytes-like object", {argname}); goto exit; }}}} if (!PyBuffer_IsContiguous(&{paramname}, 'C')) {{{{ - _PyArg_BadArgument("{{name}}", {argnum}, "contiguous buffer", {argname}); + _PyArg_BadArgument("{{name}}", {displayname}, "contiguous buffer", {argname}); goto exit; }}}} - """.format(argname=argname, paramname=self.name, argnum=argnum) - return super().parse_arg(argname, argnum) + """.format(argname=argname, paramname=self.name, + displayname=displayname) + return super().parse_arg(argname, displayname) def correct_name_for_self(f): |