diff options
author | Serhiy Storchaka <storchaka@gmail.com> | 2019-03-14 08:32:22 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-03-14 08:32:22 (GMT) |
commit | 3191391515824fa7f3c573d807f1034c6a28fab3 (patch) | |
tree | ff8213b07b206de4df88dc352ee957ce68f0f2de /Python | |
parent | 2c0d3f454705bb5ccf5f6189f3cf77bbae4f056b (diff) | |
download | cpython-3191391515824fa7f3c573d807f1034c6a28fab3.zip cpython-3191391515824fa7f3c573d807f1034c6a28fab3.tar.gz cpython-3191391515824fa7f3c573d807f1034c6a28fab3.tar.bz2 |
bpo-36127: Argument Clinic: inline parsing code for keyword parameters. (GH-12058)
Diffstat (limited to 'Python')
-rw-r--r-- | Python/clinic/_warnings.c.h | 44 | ||||
-rw-r--r-- | Python/clinic/bltinmodule.c.h | 110 | ||||
-rw-r--r-- | Python/clinic/import.c.h | 25 | ||||
-rw-r--r-- | Python/clinic/sysmodule.c.h | 18 | ||||
-rw-r--r-- | Python/clinic/traceback.c.h | 35 | ||||
-rw-r--r-- | Python/getargs.c | 320 |
6 files changed, 471 insertions, 81 deletions
diff --git a/Python/clinic/_warnings.c.h b/Python/clinic/_warnings.c.h index d1e50de..67ab0e3 100644 --- a/Python/clinic/_warnings.c.h +++ b/Python/clinic/_warnings.c.h @@ -20,19 +20,55 @@ warnings_warn(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObjec { PyObject *return_value = NULL; static const char * const _keywords[] = {"message", "category", "stacklevel", "source", NULL}; - static _PyArg_Parser _parser = {"O|OnO:warn", _keywords, 0}; + static _PyArg_Parser _parser = {NULL, _keywords, "warn", 0}; + PyObject *argsbuf[4]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; PyObject *message; PyObject *category = Py_None; Py_ssize_t stacklevel = 1; PyObject *source = Py_None; - if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, - &message, &category, &stacklevel, &source)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 4, 0, argsbuf); + if (!args) { goto exit; } + message = args[0]; + if (!noptargs) { + goto skip_optional_pos; + } + if (args[1]) { + category = args[1]; + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (args[2]) { + if (PyFloat_Check(args[2])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + { + Py_ssize_t ival = -1; + PyObject *iobj = PyNumber_Index(args[2]); + if (iobj != NULL) { + ival = PyLong_AsSsize_t(iobj); + Py_DECREF(iobj); + } + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + stacklevel = ival; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + source = args[3]; +skip_optional_pos: return_value = warnings_warn_impl(module, message, category, stacklevel, source); exit: return return_value; } -/*[clinic end generated code: output=a4fbe6e2d1cc2091 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=b7bb54c73b5433ec input=a9049054013a1b77]*/ diff --git a/Python/clinic/bltinmodule.c.h b/Python/clinic/bltinmodule.c.h index df99709..0ed11bc 100644 --- a/Python/clinic/bltinmodule.c.h +++ b/Python/clinic/bltinmodule.c.h @@ -180,7 +180,9 @@ builtin_compile(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObj { PyObject *return_value = NULL; static const char * const _keywords[] = {"source", "filename", "mode", "flags", "dont_inherit", "optimize", "feature_version", NULL}; - static _PyArg_Parser _parser = {"OO&s|iiii:compile", _keywords, 0}; + static _PyArg_Parser _parser = {NULL, _keywords, "compile", 0}; + PyObject *argsbuf[7]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 3; PyObject *source; PyObject *filename; const char *mode; @@ -189,10 +191,82 @@ builtin_compile(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObj int optimize = -1; int feature_version = -1; - if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, - &source, PyUnicode_FSDecoder, &filename, &mode, &flags, &dont_inherit, &optimize, &feature_version)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 3, 7, 0, argsbuf); + if (!args) { goto exit; } + source = args[0]; + if (!PyUnicode_FSDecoder(args[1], &filename)) { + goto exit; + } + if (!PyUnicode_Check(args[2])) { + _PyArg_BadArgument("compile", 3, "str", args[2]); + goto exit; + } + Py_ssize_t mode_length; + mode = PyUnicode_AsUTF8AndSize(args[2], &mode_length); + if (mode == NULL) { + goto exit; + } + if (strlen(mode) != (size_t)mode_length) { + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (args[3]) { + if (PyFloat_Check(args[3])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + flags = _PyLong_AsInt(args[3]); + if (flags == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (args[4]) { + if (PyFloat_Check(args[4])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + dont_inherit = _PyLong_AsInt(args[4]); + if (dont_inherit == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (args[5]) { + if (PyFloat_Check(args[5])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + optimize = _PyLong_AsInt(args[5]); + if (optimize == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (PyFloat_Check(args[6])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + feature_version = _PyLong_AsInt(args[6]); + if (feature_version == -1 && PyErr_Occurred()) { + goto exit; + } +skip_optional_pos: return_value = builtin_compile_impl(module, source, filename, mode, flags, dont_inherit, optimize, feature_version); exit: @@ -637,14 +711,22 @@ builtin_round(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObjec { PyObject *return_value = NULL; static const char * const _keywords[] = {"number", "ndigits", NULL}; - static _PyArg_Parser _parser = {"O|O:round", _keywords, 0}; + static _PyArg_Parser _parser = {NULL, _keywords, "round", 0}; + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; PyObject *number; PyObject *ndigits = NULL; - if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, - &number, &ndigits)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 2, 0, argsbuf); + if (!args) { goto exit; } + number = args[0]; + if (!noptargs) { + goto skip_optional_pos; + } + ndigits = args[1]; +skip_optional_pos: return_value = builtin_round_impl(module, number, ndigits); exit: @@ -672,14 +754,22 @@ builtin_sum(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject { PyObject *return_value = NULL; static const char * const _keywords[] = {"", "start", NULL}; - static _PyArg_Parser _parser = {"O|O:sum", _keywords, 0}; + static _PyArg_Parser _parser = {NULL, _keywords, "sum", 0}; + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; PyObject *iterable; PyObject *start = NULL; - if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, - &iterable, &start)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 2, 0, argsbuf); + if (!args) { goto exit; } + iterable = args[0]; + if (!noptargs) { + goto skip_optional_pos; + } + start = args[1]; +skip_optional_pos: return_value = builtin_sum_impl(module, iterable, start); exit: @@ -755,4 +845,4 @@ builtin_issubclass(PyObject *module, PyObject *const *args, Py_ssize_t nargs) exit: return return_value; } -/*[clinic end generated code: output=00b97a48ea49eaf2 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=3f690311ac556c31 input=a9049054013a1b77]*/ diff --git a/Python/clinic/import.c.h b/Python/clinic/import.c.h index 9ee20fb..05e3106 100644 --- a/Python/clinic/import.c.h +++ b/Python/clinic/import.c.h @@ -411,12 +411,29 @@ _imp_source_hash(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyOb { PyObject *return_value = NULL; static const char * const _keywords[] = {"key", "source", NULL}; - static _PyArg_Parser _parser = {"ly*:source_hash", _keywords, 0}; + static _PyArg_Parser _parser = {NULL, _keywords, "source_hash", 0}; + PyObject *argsbuf[2]; long key; Py_buffer source = {NULL, NULL}; - if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, - &key, &source)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 2, 2, 0, argsbuf); + if (!args) { + goto exit; + } + if (PyFloat_Check(args[0])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + key = PyLong_AsLong(args[0]); + if (key == -1 && PyErr_Occurred()) { + goto exit; + } + if (PyObject_GetBuffer(args[1], &source, PyBUF_SIMPLE) != 0) { + goto exit; + } + if (!PyBuffer_IsContiguous(&source, 'C')) { + _PyArg_BadArgument("source_hash", 2, "contiguous buffer", args[1]); goto exit; } return_value = _imp_source_hash_impl(module, key, &source); @@ -437,4 +454,4 @@ exit: #ifndef _IMP_EXEC_DYNAMIC_METHODDEF #define _IMP_EXEC_DYNAMIC_METHODDEF #endif /* !defined(_IMP_EXEC_DYNAMIC_METHODDEF) */ -/*[clinic end generated code: output=2409b8feeafe7c4b input=a9049054013a1b77]*/ +/*[clinic end generated code: output=b51244770fdcf4b8 input=a9049054013a1b77]*/ diff --git a/Python/clinic/sysmodule.c.h b/Python/clinic/sysmodule.c.h index fc9794b..c70b721 100644 --- a/Python/clinic/sysmodule.c.h +++ b/Python/clinic/sysmodule.c.h @@ -410,11 +410,21 @@ sys_set_coroutine_origin_tracking_depth(PyObject *module, PyObject *const *args, { PyObject *return_value = NULL; static const char * const _keywords[] = {"depth", NULL}; - static _PyArg_Parser _parser = {"i:set_coroutine_origin_tracking_depth", _keywords, 0}; + static _PyArg_Parser _parser = {NULL, _keywords, "set_coroutine_origin_tracking_depth", 0}; + PyObject *argsbuf[1]; int depth; - if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, - &depth)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (PyFloat_Check(args[0])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + depth = _PyLong_AsInt(args[0]); + if (depth == -1 && PyErr_Occurred()) { goto exit; } return_value = sys_set_coroutine_origin_tracking_depth_impl(module, depth); @@ -1050,4 +1060,4 @@ sys_getandroidapilevel(PyObject *module, PyObject *Py_UNUSED(ignored)) #ifndef SYS_GETANDROIDAPILEVEL_METHODDEF #define SYS_GETANDROIDAPILEVEL_METHODDEF #endif /* !defined(SYS_GETANDROIDAPILEVEL_METHODDEF) */ -/*[clinic end generated code: output=109787af3401cd27 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=3ba4c194d00f1866 input=a9049054013a1b77]*/ diff --git a/Python/clinic/traceback.c.h b/Python/clinic/traceback.c.h index d9daccb..2815f65 100644 --- a/Python/clinic/traceback.c.h +++ b/Python/clinic/traceback.c.h @@ -17,14 +17,41 @@ tb_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { PyObject *return_value = NULL; static const char * const _keywords[] = {"tb_next", "tb_frame", "tb_lasti", "tb_lineno", NULL}; - static _PyArg_Parser _parser = {"OO!ii:TracebackType", _keywords, 0}; + static _PyArg_Parser _parser = {NULL, _keywords, "TracebackType", 0}; + PyObject *argsbuf[4]; + PyObject * const *fastargs; + Py_ssize_t nargs = PyTuple_GET_SIZE(args); PyObject *tb_next; PyFrameObject *tb_frame; int tb_lasti; int tb_lineno; - if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser, - &tb_next, &PyFrame_Type, &tb_frame, &tb_lasti, &tb_lineno)) { + fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 4, 4, 0, argsbuf); + if (!fastargs) { + goto exit; + } + tb_next = fastargs[0]; + if (!PyObject_TypeCheck(fastargs[1], &PyFrame_Type)) { + _PyArg_BadArgument("TracebackType", 2, (&PyFrame_Type)->tp_name, fastargs[1]); + goto exit; + } + tb_frame = (PyFrameObject *)fastargs[1]; + if (PyFloat_Check(fastargs[2])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + tb_lasti = _PyLong_AsInt(fastargs[2]); + if (tb_lasti == -1 && PyErr_Occurred()) { + goto exit; + } + if (PyFloat_Check(fastargs[3])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + tb_lineno = _PyLong_AsInt(fastargs[3]); + if (tb_lineno == -1 && PyErr_Occurred()) { goto exit; } return_value = tb_new_impl(type, tb_next, tb_frame, tb_lasti, tb_lineno); @@ -32,4 +59,4 @@ tb_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=0133130d7d19556f input=a9049054013a1b77]*/ +/*[clinic end generated code: output=7e4c0e252d0973b0 input=a9049054013a1b77]*/ diff --git a/Python/getargs.c b/Python/getargs.c index 05ebe9c..693a29c 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -1905,24 +1905,11 @@ parser_init(struct _PyArg_Parser *parser) int i, len, min, max, nkw; PyObject *kwtuple; - assert(parser->format != NULL); assert(parser->keywords != NULL); if (parser->kwtuple != NULL) { return 1; } - /* grab the function name or custom error msg first (mutually exclusive) */ - parser->fname = strchr(parser->format, ':'); - if (parser->fname) { - parser->fname++; - parser->custom_msg = NULL; - } - else { - parser->custom_msg = strchr(parser->format,';'); - if (parser->custom_msg) - parser->custom_msg++; - } - keywords = parser->keywords; /* scan keywords and count the number of positional-only parameters */ for (i = 0; keywords[i] && !*keywords[i]; i++) { @@ -1938,60 +1925,74 @@ parser_init(struct _PyArg_Parser *parser) } len = i; - min = max = INT_MAX; format = parser->format; - for (i = 0; i < len; i++) { - if (*format == '|') { - if (min != INT_MAX) { - PyErr_SetString(PyExc_SystemError, - "Invalid format string (| specified twice)"); - return 0; + if (format) { + /* grab the function name or custom error msg first (mutually exclusive) */ + parser->fname = strchr(parser->format, ':'); + if (parser->fname) { + parser->fname++; + parser->custom_msg = NULL; + } + else { + parser->custom_msg = strchr(parser->format,';'); + if (parser->custom_msg) + parser->custom_msg++; + } + + min = max = INT_MAX; + for (i = 0; i < len; i++) { + if (*format == '|') { + if (min != INT_MAX) { + PyErr_SetString(PyExc_SystemError, + "Invalid format string (| specified twice)"); + return 0; + } + if (max != INT_MAX) { + PyErr_SetString(PyExc_SystemError, + "Invalid format string ($ before |)"); + return 0; + } + min = i; + format++; } - if (max != INT_MAX) { - PyErr_SetString(PyExc_SystemError, - "Invalid format string ($ before |)"); - return 0; + if (*format == '$') { + if (max != INT_MAX) { + PyErr_SetString(PyExc_SystemError, + "Invalid format string ($ specified twice)"); + return 0; + } + if (i < parser->pos) { + PyErr_SetString(PyExc_SystemError, + "Empty parameter name after $"); + return 0; + } + max = i; + format++; } - min = i; - format++; - } - if (*format == '$') { - if (max != INT_MAX) { - PyErr_SetString(PyExc_SystemError, - "Invalid format string ($ specified twice)"); + if (IS_END_OF_FORMAT(*format)) { + PyErr_Format(PyExc_SystemError, + "More keyword list entries (%d) than " + "format specifiers (%d)", len, i); return 0; } - if (i < parser->pos) { - PyErr_SetString(PyExc_SystemError, - "Empty parameter name after $"); + + msg = skipitem(&format, NULL, 0); + if (msg) { + PyErr_Format(PyExc_SystemError, "%s: '%s'", msg, + format); return 0; } - max = i; - format++; - } - if (IS_END_OF_FORMAT(*format)) { - PyErr_Format(PyExc_SystemError, - "More keyword list entries (%d) than " - "format specifiers (%d)", len, i); - return 0; } + parser->min = Py_MIN(min, len); + parser->max = Py_MIN(max, len); - msg = skipitem(&format, NULL, 0); - if (msg) { - PyErr_Format(PyExc_SystemError, "%s: '%s'", msg, - format); + if (!IS_END_OF_FORMAT(*format) && (*format != '|') && (*format != '$')) { + PyErr_Format(PyExc_SystemError, + "more argument specifiers than keyword list entries " + "(remaining format:'%s')", format); return 0; } } - parser->min = Py_MIN(min, len); - parser->max = Py_MIN(max, len); - - if (!IS_END_OF_FORMAT(*format) && (*format != '|') && (*format != '$')) { - PyErr_Format(PyExc_SystemError, - "more argument specifiers than keyword list entries " - "(remaining format:'%s')", format); - return 0; - } nkw = len - parser->pos; kwtuple = PyTuple_New(nkw); @@ -2313,6 +2314,215 @@ vgetargskeywordsfast(PyObject *args, PyObject *keywords, } +#undef _PyArg_UnpackKeywords + +PyObject * const * +_PyArg_UnpackKeywords(PyObject *const *args, Py_ssize_t nargs, + PyObject *kwargs, PyObject *kwnames, + struct _PyArg_Parser *parser, + int minpos, int maxpos, int minkw, + PyObject **buf) +{ + PyObject *kwtuple; + PyObject *keyword; + int i, posonly, minposonly, maxargs; + int reqlimit = minkw ? maxpos + minkw : minpos; + Py_ssize_t nkwargs; + PyObject *current_arg; + PyObject * const *kwstack = NULL; + + assert(kwargs == NULL || PyDict_Check(kwargs)); + assert(kwargs == NULL || kwnames == NULL); + + if (parser == NULL) { + PyErr_BadInternalCall(); + return NULL; + } + + if (kwnames != NULL && !PyTuple_Check(kwnames)) { + PyErr_BadInternalCall(); + return NULL; + } + + if (args == NULL && nargs == 0) { + args = buf; + } + + if (!parser_init(parser)) { + return NULL; + } + + kwtuple = parser->kwtuple; + posonly = parser->pos; + minposonly = Py_MIN(posonly, minpos); + maxargs = posonly + (int)PyTuple_GET_SIZE(kwtuple); + + if (kwargs != NULL) { + nkwargs = PyDict_GET_SIZE(kwargs); + } + else if (kwnames != NULL) { + nkwargs = PyTuple_GET_SIZE(kwnames); + kwstack = args + nargs; + } + else { + nkwargs = 0; + } + if (nkwargs == 0 && minkw == 0 && minpos <= nargs && nargs <= maxpos) { + /* Fast path. */ + return args; + } + if (nargs + nkwargs > maxargs) { + /* Adding "keyword" (when nargs == 0) prevents producing wrong error + messages in some special cases (see bpo-31229). */ + PyErr_Format(PyExc_TypeError, + "%.200s%s takes at most %d %sargument%s (%zd given)", + (parser->fname == NULL) ? "function" : parser->fname, + (parser->fname == NULL) ? "" : "()", + maxargs, + (nargs == 0) ? "keyword " : "", + (maxargs == 1) ? "" : "s", + nargs + nkwargs); + return NULL; + } + if (nargs > maxpos) { + if (maxpos == 0) { + PyErr_Format(PyExc_TypeError, + "%.200s%s takes no positional arguments", + (parser->fname == NULL) ? "function" : parser->fname, + (parser->fname == NULL) ? "" : "()"); + } + else { + PyErr_Format(PyExc_TypeError, + "%.200s%s takes %s %d positional argument%s (%zd given)", + (parser->fname == NULL) ? "function" : parser->fname, + (parser->fname == NULL) ? "" : "()", + (minpos < maxpos) ? "at most" : "exactly", + maxpos, + (maxpos == 1) ? "" : "s", + nargs); + } + return NULL; + } + if (nargs < minposonly) { + PyErr_Format(PyExc_TypeError, + "%.200s%s takes %s %d positional argument%s" + " (%zd given)", + (parser->fname == NULL) ? "function" : parser->fname, + (parser->fname == NULL) ? "" : "()", + minposonly < maxpos ? "at least" : "exactly", + minposonly, + minposonly == 1 ? "" : "s", + nargs); + return NULL; + } + + /* copy tuple args */ + for (i = 0; i < nargs; i++) { + buf[i] = args[i]; + } + + /* copy keyword args using kwtuple to drive process */ + for (i = Py_MAX(nargs, posonly); i < maxargs; i++) { + if (nkwargs) { + keyword = PyTuple_GET_ITEM(kwtuple, i - posonly); + if (kwargs != NULL) { + current_arg = PyDict_GetItemWithError(kwargs, keyword); + if (!current_arg && PyErr_Occurred()) { + return NULL; + } + } + else { + current_arg = find_keyword(kwnames, kwstack, keyword); + } + } + else if (i >= reqlimit) { + break; + } + else { + current_arg = NULL; + } + + buf[i] = current_arg; + + if (current_arg) { + --nkwargs; + } + else if (i < minpos || (maxpos <= i && i < reqlimit)) { + /* Less arguments than required */ + keyword = PyTuple_GET_ITEM(kwtuple, i - posonly); + PyErr_Format(PyExc_TypeError, "%.200s%s missing required " + "argument '%U' (pos %d)", + (parser->fname == NULL) ? "function" : parser->fname, + (parser->fname == NULL) ? "" : "()", + keyword, i+1); + return NULL; + } + } + + if (nkwargs > 0) { + Py_ssize_t j; + /* make sure there are no arguments given by name and position */ + for (i = posonly; i < nargs; i++) { + keyword = PyTuple_GET_ITEM(kwtuple, i - posonly); + if (kwargs != NULL) { + current_arg = PyDict_GetItemWithError(kwargs, keyword); + if (!current_arg && PyErr_Occurred()) { + return NULL; + } + } + else { + current_arg = find_keyword(kwnames, kwstack, keyword); + } + if (current_arg) { + /* arg present in tuple and in dict */ + PyErr_Format(PyExc_TypeError, + "argument for %.200s%s given by name ('%U') " + "and position (%d)", + (parser->fname == NULL) ? "function" : parser->fname, + (parser->fname == NULL) ? "" : "()", + keyword, i+1); + return NULL; + } + } + /* make sure there are no extraneous keyword arguments */ + j = 0; + while (1) { + int match; + if (kwargs != NULL) { + if (!PyDict_Next(kwargs, &j, &keyword, NULL)) + break; + } + else { + if (j >= PyTuple_GET_SIZE(kwnames)) + break; + keyword = PyTuple_GET_ITEM(kwnames, j); + j++; + } + + if (!PyUnicode_Check(keyword)) { + PyErr_SetString(PyExc_TypeError, + "keywords must be strings"); + return NULL; + } + match = PySequence_Contains(kwtuple, keyword); + if (match <= 0) { + if (!match) { + PyErr_Format(PyExc_TypeError, + "'%U' is an invalid keyword " + "argument for %.200s%s", + keyword, + (parser->fname == NULL) ? "this function" : parser->fname, + (parser->fname == NULL) ? "" : "()"); + } + return NULL; + } + } + } + + return buf; +} + + static const char * skipitem(const char **p_format, va_list *p_va, int flags) { |