Skip to content

Commit a317ccd

Browse files
serhiy-storchakablhsing
authored andcommitted
pythongh-122688: Fix support of var-positional parameter in Argument Clinic (pythonGH-122689)
* Parameters after the var-positional parameter are now keyword-only instead of positional-or-keyword. * Correctly calculate min_kw_only. * Raise errors for invalid combinations of the var-positional parameter with "*", "/" and deprecation markers.
1 parent 1ec4e47 commit a317ccd

File tree

7 files changed

+203
-96
lines changed

7 files changed

+203
-96
lines changed

Lib/test/clinic.test.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4134,8 +4134,8 @@ test_vararg_and_posonly
41344134
41354135
41364136
a: object
4137-
*args: object
41384137
/
4138+
*args: object
41394139
41404140
[clinic start generated code]*/
41414141

@@ -4177,7 +4177,7 @@ test_vararg_and_posonly(PyObject *module, PyObject *const *args, Py_ssize_t narg
41774177

41784178
static PyObject *
41794179
test_vararg_and_posonly_impl(PyObject *module, PyObject *a, PyObject *args)
4180-
/*[clinic end generated code: output=79b75dc07decc8d6 input=08dc2bf7afbf1613]*/
4180+
/*[clinic end generated code: output=79b75dc07decc8d6 input=9cfa748bbff09877]*/
41814181

41824182
/*[clinic input]
41834183
test_vararg
@@ -4920,7 +4920,7 @@ Test_an_metho_arg_named_arg_impl(TestObj *self, int arg)
49204920
/*[clinic input]
49214921
Test.__init__
49224922
*args: object
4923-
/
4923+
49244924
Varargs init method. For example, nargs is translated to PyTuple_GET_SIZE.
49254925
[clinic start generated code]*/
49264926

@@ -4958,14 +4958,14 @@ Test___init__(PyObject *self, PyObject *args, PyObject *kwargs)
49584958

49594959
static int
49604960
Test___init___impl(TestObj *self, PyObject *args)
4961-
/*[clinic end generated code: output=0ed1009fe0dcf98d input=96c3ddc0cd38fc0c]*/
4961+
/*[clinic end generated code: output=0ed1009fe0dcf98d input=2a8bd0033c9ac772]*/
49624962

49634963

49644964
/*[clinic input]
49654965
@classmethod
49664966
Test.__new__
49674967
*args: object
4968-
/
4968+
49694969
Varargs new method. For example, nargs is translated to PyTuple_GET_SIZE.
49704970
[clinic start generated code]*/
49714971

@@ -5002,7 +5002,7 @@ Test(PyTypeObject *type, PyObject *args, PyObject *kwargs)
50025002

50035003
static PyObject *
50045004
Test_impl(PyTypeObject *type, PyObject *args)
5005-
/*[clinic end generated code: output=8b219f6633e2a2e9 input=26a672e2e9750120]*/
5005+
/*[clinic end generated code: output=8b219f6633e2a2e9 input=70ad829df3dd9b84]*/
50065006

50075007

50085008
/*[clinic input]

Lib/test/test_clinic.py

Lines changed: 85 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ def __init__(self):
322322
"""
323323
self.expect_failure(block, err, lineno=8)
324324

325-
def test_multiple_star_in_args(self):
325+
def test_star_after_vararg(self):
326326
err = "'my_test_func' uses '*' more than once."
327327
block = """
328328
/*[clinic input]
@@ -336,6 +336,20 @@ def test_multiple_star_in_args(self):
336336
"""
337337
self.expect_failure(block, err, lineno=6)
338338

339+
def test_vararg_after_star(self):
340+
err = "'my_test_func' uses '*' more than once."
341+
block = """
342+
/*[clinic input]
343+
my_test_func
344+
345+
pos_arg: object
346+
*
347+
*args: object
348+
kw_arg: object
349+
[clinic start generated code]*/
350+
"""
351+
self.expect_failure(block, err, lineno=6)
352+
339353
def test_module_already_got_one(self):
340354
err = "Already defined module 'm'!"
341355
block = """
@@ -1787,13 +1801,43 @@ def test_parameters_required_after_depr_star2(self):
17871801
)
17881802
self.expect_failure(block, err, lineno=4)
17891803

1804+
def test_parameters_required_after_depr_star3(self):
1805+
block = """
1806+
module foo
1807+
foo.bar
1808+
a: int
1809+
* [from 3.14]
1810+
*args: object
1811+
b: int
1812+
Docstring.
1813+
"""
1814+
err = (
1815+
"Function 'bar' specifies '* [from ...]' without "
1816+
"following parameters."
1817+
)
1818+
self.expect_failure(block, err, lineno=4)
1819+
17901820
def test_depr_star_must_come_before_star(self):
17911821
block = """
17921822
module foo
17931823
foo.bar
1794-
this: int
1824+
a: int
17951825
*
17961826
* [from 3.14]
1827+
b: int
1828+
Docstring.
1829+
"""
1830+
err = "Function 'bar': '* [from ...]' must precede '*'"
1831+
self.expect_failure(block, err, lineno=4)
1832+
1833+
def test_depr_star_must_come_before_vararg(self):
1834+
block = """
1835+
module foo
1836+
foo.bar
1837+
a: int
1838+
*args: object
1839+
* [from 3.14]
1840+
b: int
17971841
Docstring.
17981842
"""
17991843
err = "Function 'bar': '* [from ...]' must precede '*'"
@@ -1908,7 +1952,7 @@ def test_double_slash(self):
19081952
err = "Function 'bar' uses '/' more than once."
19091953
self.expect_failure(block, err)
19101954

1911-
def test_mix_star_and_slash(self):
1955+
def test_slash_after_star(self):
19121956
block = """
19131957
module foo
19141958
foo.bar
@@ -1921,6 +1965,19 @@ def test_mix_star_and_slash(self):
19211965
err = "Function 'bar': '/' must precede '*'"
19221966
self.expect_failure(block, err)
19231967

1968+
def test_slash_after_vararg(self):
1969+
block = """
1970+
module foo
1971+
foo.bar
1972+
x: int
1973+
y: int
1974+
*args: object
1975+
z: int
1976+
/
1977+
"""
1978+
err = "Function 'bar': '/' must precede '*'"
1979+
self.expect_failure(block, err)
1980+
19241981
def test_depr_star_must_come_after_slash(self):
19251982
block = """
19261983
module foo
@@ -1960,6 +2017,19 @@ def test_star_must_come_after_depr_slash(self):
19602017
err = "Function 'bar': '/ [from ...]' must precede '*'"
19612018
self.expect_failure(block, err, lineno=4)
19622019

2020+
def test_vararg_must_come_after_depr_slash(self):
2021+
block = """
2022+
module foo
2023+
foo.bar
2024+
a: int
2025+
*args: object
2026+
/ [from 3.14]
2027+
b: int
2028+
Docstring.
2029+
"""
2030+
err = "Function 'bar': '/ [from ...]' must precede '*'"
2031+
self.expect_failure(block, err, lineno=4)
2032+
19632033
def test_depr_slash_must_come_after_slash(self):
19642034
block = """
19652035
module foo
@@ -1987,7 +2057,7 @@ def test_parameters_not_permitted_after_slash_for_now(self):
19872057
self.expect_failure(block, err)
19882058

19892059
def test_parameters_no_more_than_one_vararg(self):
1990-
err = "Too many var args"
2060+
err = "Function 'bar' uses '*' more than once."
19912061
block = """
19922062
module foo
19932063
foo.bar
@@ -3319,13 +3389,6 @@ def test_posonly_vararg(self):
33193389
with self.assertRaises(TypeError):
33203390
ac_tester.posonly_vararg(1, 2, 3, b=4)
33213391

3322-
def test_vararg_and_posonly(self):
3323-
with self.assertRaises(TypeError):
3324-
ac_tester.vararg_and_posonly()
3325-
with self.assertRaises(TypeError):
3326-
ac_tester.vararg_and_posonly(1, b=2)
3327-
self.assertEqual(ac_tester.vararg_and_posonly(1, 2, 3, 4), (1, (2, 3, 4)))
3328-
33293392
def test_vararg(self):
33303393
with self.assertRaises(TypeError):
33313394
ac_tester.vararg()
@@ -3363,6 +3426,17 @@ def test_vararg_with_only_defaults(self):
33633426
self.assertEqual(ac_tester.vararg_with_only_defaults(1, 2, 3, 4), ((1, 2, 3, 4), None))
33643427
self.assertEqual(ac_tester.vararg_with_only_defaults(1, 2, 3, 4, b=5), ((1, 2, 3, 4), 5))
33653428

3429+
def test_vararg_kwonly_req_opt(self):
3430+
fn = ac_tester.vararg_kwonly_req_opt
3431+
self.assertRaises(TypeError, fn)
3432+
self.assertEqual(fn(a=1), ((), 1, None, None))
3433+
self.assertEqual(fn(a=1, b=2), ((), 1, 2, None))
3434+
self.assertEqual(fn(a=1, b=2, c=3), ((), 1, 2, 3))
3435+
self.assertRaises(TypeError, fn, 1)
3436+
self.assertEqual(fn(1, a=2), ((1,), 2, None, None))
3437+
self.assertEqual(fn(1, a=2, b=3), ((1,), 2, 3, None))
3438+
self.assertEqual(fn(1, a=2, b=3, c=4), ((1,), 2, 3, 4))
3439+
33663440
def test_gh_32092_oob(self):
33673441
ac_tester.gh_32092_oob(1, 2, 3, 4, kw1=5, kw2=6)
33683442

Modules/_testclinic.c

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -981,23 +981,6 @@ posonly_vararg_impl(PyObject *module, PyObject *a, PyObject *b,
981981
}
982982

983983

984-
/*[clinic input]
985-
vararg_and_posonly
986-
987-
a: object
988-
*args: object
989-
/
990-
991-
[clinic start generated code]*/
992-
993-
static PyObject *
994-
vararg_and_posonly_impl(PyObject *module, PyObject *a, PyObject *args)
995-
/*[clinic end generated code: output=42792f799465a14d input=defe017b19ba52e8]*/
996-
{
997-
return pack_arguments_newref(2, a, args);
998-
}
999-
1000-
1001984
/*[clinic input]
1002985
vararg
1003986
@@ -1068,6 +1051,25 @@ vararg_with_only_defaults_impl(PyObject *module, PyObject *args, PyObject *b)
10681051
}
10691052

10701053

1054+
/*[clinic input]
1055+
vararg_kwonly_req_opt
1056+
1057+
*args: object
1058+
a: object
1059+
b: object = None
1060+
c: object = None
1061+
1062+
[clinic start generated code]*/
1063+
1064+
static PyObject *
1065+
vararg_kwonly_req_opt_impl(PyObject *module, PyObject *args, PyObject *a,
1066+
PyObject *b, PyObject *c)
1067+
/*[clinic end generated code: output=54694a99c3da370a input=b0d8bf09e540d400]*/
1068+
{
1069+
return pack_arguments_newref(4, args, a, b, c);
1070+
}
1071+
1072+
10711073

10721074
/*[clinic input]
10731075
gh_32092_oob
@@ -1115,15 +1117,14 @@ gh_32092_kw_pass_impl(PyObject *module, PyObject *pos, PyObject *args,
11151117
gh_99233_refcount
11161118
11171119
*args: object
1118-
/
11191120
11201121
Proof-of-concept of GH-99233 refcount error bug.
11211122
11221123
[clinic start generated code]*/
11231124

11241125
static PyObject *
11251126
gh_99233_refcount_impl(PyObject *module, PyObject *args)
1126-
/*[clinic end generated code: output=585855abfbca9a7f input=85f5fb47ac91a626]*/
1127+
/*[clinic end generated code: output=585855abfbca9a7f input=eecfdc2092d90dc3]*/
11271128
{
11281129
Py_RETURN_NONE;
11291130
}
@@ -1923,11 +1924,11 @@ static PyMethodDef tester_methods[] = {
19231924
POSONLY_OPT_KEYWORDS_OPT_KWONLY_OPT_METHODDEF
19241925
KEYWORD_ONLY_PARAMETER_METHODDEF
19251926
POSONLY_VARARG_METHODDEF
1926-
VARARG_AND_POSONLY_METHODDEF
19271927
VARARG_METHODDEF
19281928
VARARG_WITH_DEFAULT_METHODDEF
19291929
VARARG_WITH_DEFAULT2_METHODDEF
19301930
VARARG_WITH_ONLY_DEFAULTS_METHODDEF
1931+
VARARG_KWONLY_REQ_OPT_METHODDEF
19311932
GH_32092_OOB_METHODDEF
19321933
GH_32092_KW_PASS_METHODDEF
19331934
GH_99233_REFCOUNT_METHODDEF

0 commit comments

Comments
 (0)