mirror of
https://github.com/python/cpython.git
synced 2025-10-17 04:08:28 +00:00
bpo-36127: Argument Clinic: inline parsing code for keyword parameters. (GH-12058)
This commit is contained in:
parent
2c0d3f4547
commit
3191391515
65 changed files with 7466 additions and 868 deletions
44
Python/clinic/_warnings.c.h
generated
44
Python/clinic/_warnings.c.h
generated
|
@ -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]*/
|
||||
|
|
110
Python/clinic/bltinmodule.c.h
generated
110
Python/clinic/bltinmodule.c.h
generated
|
@ -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]*/
|
||||
|
|
25
Python/clinic/import.c.h
generated
25
Python/clinic/import.c.h
generated
|
@ -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]*/
|
||||
|
|
18
Python/clinic/sysmodule.c.h
generated
18
Python/clinic/sysmodule.c.h
generated
|
@ -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]*/
|
||||
|
|
35
Python/clinic/traceback.c.h
generated
35
Python/clinic/traceback.c.h
generated
|
@ -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]*/
|
||||
|
|
330
Python/getargs.c
330
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,59 +1925,73 @@ 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 (max != INT_MAX) {
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
"Invalid format string ($ before |)");
|
||||
return 0;
|
||||
}
|
||||
min = i;
|
||||
format++;
|
||||
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;
|
||||
}
|
||||
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++;
|
||||
else {
|
||||
parser->custom_msg = strchr(parser->format,';');
|
||||
if (parser->custom_msg)
|
||||
parser->custom_msg++;
|
||||
}
|
||||
if (IS_END_OF_FORMAT(*format)) {
|
||||
|
||||
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 (*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++;
|
||||
}
|
||||
if (IS_END_OF_FORMAT(*format)) {
|
||||
PyErr_Format(PyExc_SystemError,
|
||||
"More keyword list entries (%d) than "
|
||||
"format specifiers (%d)", len, i);
|
||||
return 0;
|
||||
}
|
||||
|
||||
msg = skipitem(&format, NULL, 0);
|
||||
if (msg) {
|
||||
PyErr_Format(PyExc_SystemError, "%s: '%s'", msg,
|
||||
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 keyword list entries (%d) than "
|
||||
"format specifiers (%d)", len, i);
|
||||
"more argument specifiers than keyword list entries "
|
||||
"(remaining format:'%s')", format);
|
||||
return 0;
|
||||
}
|
||||
|
||||
msg = skipitem(&format, NULL, 0);
|
||||
if (msg) {
|
||||
PyErr_Format(PyExc_SystemError, "%s: '%s'", msg,
|
||||
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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue