Skip to content

Commit

Permalink
pythongh-122943: Rework support of var-positional parameter in Argume…
Browse files Browse the repository at this point in the history
…nt Clinic

Move creation of a tuple for var-positional parameter out of
_PyArg_UnpackKeywordsWithVararg().
Merge _PyArg_UnpackKeywordsWithVararg() with _PyArg_UnpackKeywords().
Add a new parameter in _PyArg_UnpackKeywords().

The "parameters" and "converters" attributes of ParseArgsCodeGen no
longer contain the var-positional parameter. It is now available as the
"varpos" attribute. Optimize code generation for var-positional
parameter and reuse the same generating code for functions with and without
keyword parameters.
  • Loading branch information
serhiy-storchaka committed Aug 12, 2024
1 parent f9ba1f3 commit a7c627e
Show file tree
Hide file tree
Showing 100 changed files with 1,141 additions and 1,308 deletions.
16 changes: 5 additions & 11 deletions Include/internal/pycore_modsupport.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,20 +85,14 @@ PyAPI_FUNC(PyObject * const *) _PyArg_UnpackKeywords(
int minpos,
int maxpos,
int minkw,
int varpos,
PyObject **buf);
#define _PyArg_UnpackKeywords(args, nargs, kwargs, kwnames, parser, minpos, maxpos, minkw, buf) \
#define _PyArg_UnpackKeywords(args, nargs, kwargs, kwnames, parser, minpos, maxpos, minkw, varpos, buf) \
(((minkw) == 0 && (kwargs) == NULL && (kwnames) == NULL && \
(minpos) <= (nargs) && (nargs) <= (maxpos) && (args) != NULL) ? (args) : \
(minpos) <= (nargs) && (varpos || (nargs) <= (maxpos)) && (args) != NULL) ? \
(args) : \
_PyArg_UnpackKeywords((args), (nargs), (kwargs), (kwnames), (parser), \
(minpos), (maxpos), (minkw), (buf)))

// Export for '_testclinic' shared extension
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);
(minpos), (maxpos), (minkw), (varpos), (buf)))

#ifdef __cplusplus
}
Expand Down
2 changes: 1 addition & 1 deletion Include/internal/pycore_tuple.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ extern PyStatus _PyTuple_InitGlobalObjects(PyInterpreterState *);

#define _PyTuple_ITEMS(op) _Py_RVALUE(_PyTuple_CAST(op)->ob_item)

extern PyObject *_PyTuple_FromArray(PyObject *const *, Py_ssize_t);
PyAPI_FUNC(PyObject *)_PyTuple_FromArray(PyObject *const *, Py_ssize_t);
PyAPI_FUNC(PyObject *)_PyTuple_FromStackRefSteal(const union _PyStackRef *, Py_ssize_t);
PyAPI_FUNC(PyObject *)_PyTuple_FromArraySteal(PyObject *const *, Py_ssize_t);

Expand Down
205 changes: 112 additions & 93 deletions Lib/test/clinic.test.c

Large diffs are not rendered by default.

39 changes: 27 additions & 12 deletions Lib/test/test_clinic.py
Original file line number Diff line number Diff line change
Expand Up @@ -2694,7 +2694,7 @@ def test_cli_force(self):
# Verify by checking the checksum.
checksum = (
"/*[clinic end generated code: "
"output=0acbef4794cb933e input=9543a8d2da235301]*/\n"
"output=843576e3ffe85e2d input=9543a8d2da235301]*/\n"
)
with open(fn, encoding='utf-8') as f:
generated = f.read()
Expand Down Expand Up @@ -3393,6 +3393,15 @@ def test_posonly_varpos(self):
self.assertEqual(fn(1, 2), (1, 2, ()))
self.assertEqual(fn(1, 2, 3, 4), (1, 2, (3, 4)))

def test_posonly_req_opt_varpos(self):
# fn(a, b=False, /, *args)
fn = ac_tester.posonly_req_opt_varpos
self.assertRaises(TypeError, fn)
self.assertRaises(TypeError, fn, a=1)
self.assertEqual(fn(1), (1, False, ()))
self.assertEqual(fn(1, 2), (1, 2, ()))
self.assertEqual(fn(1, 2, 3, 4), (1, 2, (3, 4)))

def test_posonly_poskw_varpos(self):
# fn(a, /, b, *args)
fn = ac_tester.posonly_poskw_varpos
Expand All @@ -3401,23 +3410,26 @@ def test_posonly_poskw_varpos(self):
self.assertEqual(fn(1, b=2), (1, 2, ()))
self.assertEqual(fn(1, 2, 3, 4), (1, 2, (3, 4)))
self.assertRaises(TypeError, fn, b=4)
self.assertRaises(TypeError, fn, 1, 2, 3, b=4)
errmsg = re.escape("given by name ('b') and position (2)")
self.assertRaisesRegex(TypeError, errmsg, fn, 1, 2, 3, b=4)

def test_poskw_varpos(self):
# fn(a, *args)
fn = ac_tester.poskw_varpos
self.assertRaises(TypeError, fn)
self.assertRaises(TypeError, fn, 1, b=2)
self.assertEqual(fn(a=1), (1, ()))
self.assertRaises(TypeError, fn, 1, a=2)
errmsg = re.escape("given by name ('a') and position (1)")
self.assertRaisesRegex(TypeError, errmsg, fn, 1, a=2)
self.assertEqual(fn(1), (1, ()))
self.assertEqual(fn(1, 2, 3, 4), (1, (2, 3, 4)))

def test_poskw_varpos_kwonly_opt(self):
# fn(a, *args, b=False)
fn = ac_tester.poskw_varpos_kwonly_opt
self.assertRaises(TypeError, fn)
self.assertRaises(TypeError, fn, 1, a=2)
errmsg = re.escape("given by name ('a') and position (1)")
self.assertRaisesRegex(TypeError, errmsg, fn, 1, a=2)
self.assertEqual(fn(1, b=2), (1, (), True))
self.assertEqual(fn(1, 2, 3, 4), (1, (2, 3, 4), False))
self.assertEqual(fn(1, 2, 3, 4, b=5), (1, (2, 3, 4), True))
Expand All @@ -3428,7 +3440,8 @@ def test_poskw_varpos_kwonly_opt2(self):
# fn(a, *args, b=False, c=False)
fn = ac_tester.poskw_varpos_kwonly_opt2
self.assertRaises(TypeError, fn)
self.assertRaises(TypeError, fn, 1, a=2)
errmsg = re.escape("given by name ('a') and position (1)")
self.assertRaisesRegex(TypeError, errmsg, fn, 1, a=2)
self.assertEqual(fn(1, b=2), (1, (), 2, False))
self.assertEqual(fn(1, b=2, c=3), (1, (), 2, 3))
self.assertEqual(fn(1, 2, 3), (1, (2, 3), False, False))
Expand Down Expand Up @@ -3490,9 +3503,10 @@ def test_null_or_tuple_for_varargs(self):
self.assertEqual(fn(covariant=True, name='a'), ('a', (), True))

self.assertRaises(TypeError, fn, covariant=True)
self.assertRaises(TypeError, fn, 1, name='a')
self.assertRaises(TypeError, fn, 1, 2, 3, name='a', covariant=True)
self.assertRaises(TypeError, fn, 1, 2, 3, covariant=True, name='a')
errmsg = re.escape("given by name ('name') and position (1)")
self.assertRaisesRegex(TypeError, errmsg, fn, 1, name='a')
self.assertRaisesRegex(TypeError, errmsg, fn, 1, 2, 3, name='a', covariant=True)
self.assertRaisesRegex(TypeError, errmsg, fn, 1, 2, 3, covariant=True, name='a')

def test_cloned_func_exception_message(self):
incorrect_arg = -1 # f1() and f2() accept a single str
Expand Down Expand Up @@ -3568,14 +3582,15 @@ def test_defclass_posonly_varpos(self):
cls = ac_tester.TestClass
obj = cls()
fn = obj.defclass_posonly_varpos
self.assertRaises(TypeError, fn)
self.assertRaises(TypeError, fn, 1)
errmsg = 'takes at least 2 positional arguments'
self.assertRaisesRegex(TypeError, errmsg, fn)
self.assertRaisesRegex(TypeError, errmsg, fn, 1)
self.assertEqual(fn(1, 2), (cls, 1, 2, ()))
self.assertEqual(fn(1, 2, 3, 4), (cls, 1, 2, (3, 4)))
fn = cls.defclass_posonly_varpos
self.assertRaises(TypeError, fn)
self.assertRaises(TypeError, fn, obj)
self.assertRaises(TypeError, fn, obj, 1)
self.assertRaisesRegex(TypeError, errmsg, fn, obj)
self.assertRaisesRegex(TypeError, errmsg, fn, obj, 1)
self.assertEqual(fn(obj, 1, 2), (cls, 1, 2, ()))
self.assertEqual(fn(obj, 1, 2, 3, 4), (cls, 1, 2, (3, 4)))

Expand Down
4 changes: 2 additions & 2 deletions Modules/_blake2/clinic/blake2b_impl.c.h

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

4 changes: 2 additions & 2 deletions Modules/_blake2/clinic/blake2s_impl.c.h

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

24 changes: 12 additions & 12 deletions Modules/_ctypes/clinic/_ctypes.c.h

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

6 changes: 3 additions & 3 deletions Modules/_io/clinic/_iomodule.c.h

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

16 changes: 8 additions & 8 deletions Modules/_io/clinic/bufferedio.c.h

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

4 changes: 2 additions & 2 deletions Modules/_io/clinic/bytesio.c.h

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

Loading

0 comments on commit a7c627e

Please sign in to comment.