Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gh-64490: varargs support for argument clinic and refactor print with AC #18609

Merged
merged 1 commit into from
Jul 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion Include/modsupport.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ PyAPI_FUNC(PyObject *) Py_BuildValue(const char *, ...);
PyAPI_FUNC(PyObject *) _Py_BuildValue_SizeT(const char *, ...);


#define ANY_VARARGS(n) (n == PY_SSIZE_T_MAX)
#ifndef Py_LIMITED_API
PyAPI_FUNC(int) _PyArg_UnpackStack(
PyObject *const *args,
Expand All @@ -73,7 +74,7 @@ PyAPI_FUNC(void) _PyArg_BadArgument(const char *, const char *, const char *, Py
PyAPI_FUNC(int) _PyArg_CheckPositional(const char *, Py_ssize_t,
Py_ssize_t, Py_ssize_t);
#define _PyArg_CheckPositional(funcname, nargs, min, max) \
(((min) <= (nargs) && (nargs) <= (max)) \
((!ANY_VARARGS(max) && (min) <= (nargs) && (nargs) <= (max)) \
|| _PyArg_CheckPositional((funcname), (nargs), (min), (max)))

#endif
Expand Down Expand Up @@ -127,6 +128,14 @@ PyAPI_FUNC(PyObject * const *) _PyArg_UnpackKeywords(
struct _PyArg_Parser *parser,
int minpos, int maxpos, int minkw,
PyObject **buf);

PyAPI_FUNC(PyObject * const *) _PyArg_UnpackKeywordsWithVararg(
PyObject *const *args, Py_ssize_t nargs,
PyObject *kwargs, PyObject *kwnames,
struct _PyArg_Parser *parser,
int minpos, int maxpos, int minkw,
int vararg, PyObject **buf);

#define _PyArg_UnpackKeywords(args, nargs, kwargs, kwnames, parser, minpos, maxpos, minkw, buf) \
(((minkw) == 0 && (kwargs) == NULL && (kwnames) == NULL && \
(minpos) <= (nargs) && (nargs) <= (maxpos) && args != NULL) ? (args) : \
Expand Down
220 changes: 220 additions & 0 deletions Lib/test/clinic.test
Original file line number Diff line number Diff line change
Expand Up @@ -3304,3 +3304,223 @@ test_preprocessor_guarded_else(PyObject *module, PyObject *Py_UNUSED(ignored))
#define TEST_PREPROCESSOR_GUARDED_ELSE_METHODDEF
#endif /* !defined(TEST_PREPROCESSOR_GUARDED_ELSE_METHODDEF) */
/*[clinic end generated code: output=3804bb18d454038c input=3fc80c9989d2f2e1]*/

/*[clinic input]
test_vararg_and_posonly


a: object
*args: object
/

[clinic start generated code]*/

PyDoc_STRVAR(test_vararg_and_posonly__doc__,
"test_vararg_and_posonly($module, a, /, *args)\n"
"--\n"
"\n");

#define TEST_VARARG_AND_POSONLY_METHODDEF \
{"test_vararg_and_posonly", (PyCFunction)(void(*)(void))test_vararg_and_posonly, METH_FASTCALL, test_vararg_and_posonly__doc__},

static PyObject *
test_vararg_and_posonly_impl(PyObject *module, PyObject *a, PyObject *args);

static PyObject *
test_vararg_and_posonly(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
{
PyObject *return_value = NULL;
PyObject *a;
PyObject *__clinic_args = NULL;

if (!_PyArg_CheckPositional("test_vararg_and_posonly", nargs, 1, PY_SSIZE_T_MAX)) {
goto exit;
}
a = args[0];
__clinic_args = PyTuple_New(nargs - 1);
for (Py_ssize_t i = 0; i < nargs - 1; ++i) {
PyTuple_SET_ITEM(__clinic_args, i, args[1 + i]);
}
return_value = test_vararg_and_posonly_impl(module, a, __clinic_args);

exit:
Py_XDECREF(__clinic_args);
return return_value;
}

static PyObject *
test_vararg_and_posonly_impl(PyObject *module, PyObject *a, PyObject *args)
/*[clinic end generated code: output=ada613d2d87c9341 input=08dc2bf7afbf1613]*/

/*[clinic input]
test_vararg


a: object
*args: object

[clinic start generated code]*/

PyDoc_STRVAR(test_vararg__doc__,
"test_vararg($module, /, a, *args)\n"
"--\n"
"\n");

#define TEST_VARARG_METHODDEF \
{"test_vararg", (PyCFunction)(void(*)(void))test_vararg, METH_FASTCALL|METH_KEYWORDS, test_vararg__doc__},

static PyObject *
test_vararg_impl(PyObject *module, PyObject *a, PyObject *args);

static PyObject *
test_vararg(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
static const char * const _keywords[] = {"a", NULL};
static _PyArg_Parser _parser = {NULL, _keywords, "test_vararg", 0};
PyObject *argsbuf[2];
Py_ssize_t noptargs = 0 + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
PyObject *a;
PyObject *__clinic_args = NULL;

args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, 1, argsbuf);
if (!args) {
goto exit;
}
a = args[0];
__clinic_args = args[1];
return_value = test_vararg_impl(module, a, __clinic_args);

exit:
Py_XDECREF(__clinic_args);
return return_value;
}

static PyObject *
test_vararg_impl(PyObject *module, PyObject *a, PyObject *args)
/*[clinic end generated code: output=f721025731c3bfe8 input=81d33815ad1bae6e]*/

/*[clinic input]
test_vararg_with_default


a: object
*args: object
b: bool = False

[clinic start generated code]*/

PyDoc_STRVAR(test_vararg_with_default__doc__,
"test_vararg_with_default($module, /, a, *args, b=False)\n"
"--\n"
"\n");

#define TEST_VARARG_WITH_DEFAULT_METHODDEF \
{"test_vararg_with_default", (PyCFunction)(void(*)(void))test_vararg_with_default, METH_FASTCALL|METH_KEYWORDS, test_vararg_with_default__doc__},

static PyObject *
test_vararg_with_default_impl(PyObject *module, PyObject *a, PyObject *args,
int b);

static PyObject *
test_vararg_with_default(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
static const char * const _keywords[] = {"a", "b", NULL};
static _PyArg_Parser _parser = {NULL, _keywords, "test_vararg_with_default", 0};
PyObject *argsbuf[3];
Py_ssize_t noptargs = 0 + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
PyObject *a;
PyObject *__clinic_args = NULL;
int b = 0;

args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, 1, argsbuf);
if (!args) {
goto exit;
}
a = args[0];
__clinic_args = args[1];
if (!noptargs) {
goto skip_optional_kwonly;
}
b = PyObject_IsTrue(args[2]);
if (b < 0) {
goto exit;
}
skip_optional_kwonly:
return_value = test_vararg_with_default_impl(module, a, __clinic_args, b);

exit:
Py_XDECREF(__clinic_args);
return return_value;
}

static PyObject *
test_vararg_with_default_impl(PyObject *module, PyObject *a, PyObject *args,
int b)
/*[clinic end generated code: output=63b34d3241c52fda input=6e110b54acd9b22d]*/

/*[clinic input]
test_vararg_with_only_defaults


*args: object
b: bool = False
c: object = ' '

[clinic start generated code]*/

PyDoc_STRVAR(test_vararg_with_only_defaults__doc__,
"test_vararg_with_only_defaults($module, /, *args, b=False, c=\' \')\n"
"--\n"
"\n");

#define TEST_VARARG_WITH_ONLY_DEFAULTS_METHODDEF \
{"test_vararg_with_only_defaults", (PyCFunction)(void(*)(void))test_vararg_with_only_defaults, METH_FASTCALL|METH_KEYWORDS, test_vararg_with_only_defaults__doc__},

static PyObject *
test_vararg_with_only_defaults_impl(PyObject *module, PyObject *args, int b,
PyObject *c);

static PyObject *
test_vararg_with_only_defaults(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
static const char * const _keywords[] = {"b", "c", NULL};
static _PyArg_Parser _parser = {NULL, _keywords, "test_vararg_with_only_defaults", 0};
PyObject *argsbuf[3];
Py_ssize_t noptargs = 0 + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0;
PyObject *__clinic_args = NULL;
int b = 0;
PyObject *c = " ";

args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, 0, argsbuf);
if (!args) {
goto exit;
}
__clinic_args = args[0];
if (!noptargs) {
goto skip_optional_kwonly;
}
if (args[1]) {
b = PyObject_IsTrue(args[1]);
if (b < 0) {
goto exit;
}
if (!--noptargs) {
goto skip_optional_kwonly;
}
}
c = args[2];
skip_optional_kwonly:
return_value = test_vararg_with_only_defaults_impl(module, __clinic_args, b, c);

exit:
Py_XDECREF(__clinic_args);
return return_value;
}

static PyObject *
test_vararg_with_only_defaults_impl(PyObject *module, PyObject *args, int b,
PyObject *c)
/*[clinic end generated code: output=dc29ce6ebc2ec10c input=fa56a709a035666e]*/
2 changes: 1 addition & 1 deletion Lib/test/test_call.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ def test_varargs16_kw(self):
min, 0, default=1, key=2, foo=3)

def test_varargs17_kw(self):
msg = r"^print\(\) takes at most 4 keyword arguments \(5 given\)$"
msg = r"'foo' is an invalid keyword argument for print\(\)$"
self.assertRaisesRegex(TypeError, msg,
print, 0, sep=1, end=2, file=3, flush=4, foo=5)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added support for variadic positional parameters in Argument Clinic.
Loading