Skip to content
Closed
3 changes: 3 additions & 0 deletions Include/internal/pycore_global_objects_fini_generated.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Include/internal/pycore_global_strings.h
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,9 @@ struct _Py_global_strings {
STRUCT_FOR_ID(attribute)
STRUCT_FOR_ID(authorizer_callback)
STRUCT_FOR_ID(autocommit)
STRUCT_FOR_ID(b1)
STRUCT_FOR_ID(b2)
STRUCT_FOR_ID(b3)
STRUCT_FOR_ID(backtick)
STRUCT_FOR_ID(base)
STRUCT_FOR_ID(before)
Expand Down
3 changes: 3 additions & 0 deletions Include/internal/pycore_runtime_init_generated.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions Include/internal/pycore_unicodeobject_generated.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions Lib/test/test_clinic.py
Original file line number Diff line number Diff line change
Expand Up @@ -3339,6 +3339,18 @@ def test_vararg_with_default(self):
self.assertEqual(ac_tester.vararg_with_default(1, b=False), (1, (), False))
self.assertEqual(ac_tester.vararg_with_default(1, 2, 3, 4), (1, (2, 3, 4), False))
self.assertEqual(ac_tester.vararg_with_default(1, 2, 3, 4, b=True), (1, (2, 3, 4), True))
self.assertEqual(ac_tester.vararg_with_default(a=1, b=False), (1, (), False))
self.assertEqual(ac_tester.vararg_with_default(b=False, a=1), (1, (), False))

def test_vararg_with_multiple_defaults(self):
func = ac_tester.vararg_with_multiple_defaults
with self.assertRaises(TypeError):
func()
self.assertEqual(func(1, b1=True), (1, (), True, False, False))
self.assertEqual(func(1, 2, 3, 4), (1, (2, 3, 4), False, False, False))
self.assertEqual(func(1, 2, 3, 4, b1=True), (1, (2, 3, 4), True, False, False))
self.assertEqual(func(a=1, b1=True), (1, (), True, False, False))
self.assertEqual(func(b1=True, a=1), (1, (), True, False, False))

def test_vararg_with_only_defaults(self):
self.assertEqual(ac_tester.vararg_with_only_defaults(), ((), None))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fix argument parsing by ``_PyArg_UnpackKeywordsWithVararg`` when passing
positional as keyword arguments before variadic arguments. Patch by Bénédikt
Tran.
24 changes: 24 additions & 0 deletions Modules/_testclinic.c
Original file line number Diff line number Diff line change
Expand Up @@ -1033,6 +1033,29 @@ vararg_with_default_impl(PyObject *module, PyObject *a, PyObject *args,
}


/*[clinic input]
vararg_with_multiple_defaults

a: object
*args: object
b1: bool = False
b2: bool = False
b3: bool = False

[clinic start generated code]*/

static PyObject *
vararg_with_multiple_defaults_impl(PyObject *module, PyObject *a,
PyObject *args, int b1, int b2, int b3)
/*[clinic end generated code: output=66087a6689e6bee5 input=66e4b2858ad13769]*/
{
PyObject *obj_b1 = b1 ? Py_True : Py_False;
PyObject *obj_b2 = b2 ? Py_True : Py_False;
PyObject *obj_b3 = b3 ? Py_True : Py_False;
return pack_arguments_newref(5, a, args, obj_b1, obj_b2, obj_b3);
}


/*[clinic input]
vararg_with_only_defaults

Expand Down Expand Up @@ -1907,6 +1930,7 @@ static PyMethodDef tester_methods[] = {
VARARG_AND_POSONLY_METHODDEF
VARARG_METHODDEF
VARARG_WITH_DEFAULT_METHODDEF
VARARG_WITH_MULTIPLE_DEFAULTS_METHODDEF
VARARG_WITH_ONLY_DEFAULTS_METHODDEF
GH_32092_OOB_METHODDEF
GH_32092_KW_PASS_METHODDEF
Expand Down
91 changes: 90 additions & 1 deletion Modules/clinic/_testclinic.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion Python/getargs.c
Original file line number Diff line number Diff line change
Expand Up @@ -2589,7 +2589,13 @@ _PyArg_UnpackKeywordsWithVararg(PyObject *const *args, Py_ssize_t nargs,
* Otherwise, we leave a place at `buf[vararg]` for vararg tuple
* so the index is `i + 1`. */
if (nargs < vararg && i != vararg) {
buf[i] = current_arg;
if (current_arg != NULL) {
Copy link
Member

@serhiy-storchaka serhiy-storchaka Aug 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This leaves buf[i] not initialized, isn't?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Urgh... yes. I should probably change the way it's being checked... like a boolean checking whether I replaced something before or not. But depending on whether you want to change the logic of this function, I may delay the commit.

// It might happen that in the previous iteration,
// we did "buf[i + 1] = current_arg" and that in
// this current loop iteration, current_arg == NULL.
// We do not want to put a NULL on a previously valid value.
buf[i] = current_arg;
}
}
else {
buf[i + 1] = current_arg;
Expand Down