Skip to content

Commit 60942cc

Browse files
gh-95065, gh-107704: Argument Clinic: support multiple '/ [from ...]' and '* [from ...]' markers (GH-108132)
1 parent 13104f3 commit 60942cc

8 files changed

+565
-104
lines changed

Include/internal/pycore_global_objects_fini_generated.h

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_global_strings.h

+3
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,7 @@ struct _Py_global_strings {
412412
STRUCT_FOR_ID(exp)
413413
STRUCT_FOR_ID(extend)
414414
STRUCT_FOR_ID(extra_tokens)
415+
STRUCT_FOR_ID(f)
415416
STRUCT_FOR_ID(facility)
416417
STRUCT_FOR_ID(factory)
417418
STRUCT_FOR_ID(false)
@@ -443,6 +444,7 @@ struct _Py_global_strings {
443444
STRUCT_FOR_ID(fset)
444445
STRUCT_FOR_ID(func)
445446
STRUCT_FOR_ID(future)
447+
STRUCT_FOR_ID(g)
446448
STRUCT_FOR_ID(generation)
447449
STRUCT_FOR_ID(genexpr)
448450
STRUCT_FOR_ID(get)
@@ -456,6 +458,7 @@ struct _Py_global_strings {
456458
STRUCT_FOR_ID(globals)
457459
STRUCT_FOR_ID(groupindex)
458460
STRUCT_FOR_ID(groups)
461+
STRUCT_FOR_ID(h)
459462
STRUCT_FOR_ID(handle)
460463
STRUCT_FOR_ID(hash_name)
461464
STRUCT_FOR_ID(header)

Include/internal/pycore_runtime_init_generated.h

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_unicodeobject_generated.h

+9
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/test/test_clinic.py

+75-21
Original file line numberDiff line numberDiff line change
@@ -1751,7 +1751,7 @@ def test_depr_star_must_come_before_star(self):
17511751
* [from 3.14]
17521752
Docstring.
17531753
"""
1754-
err = "Function 'bar': '* [from ...]' must come before '*'"
1754+
err = "Function 'bar': '* [from ...]' must precede '*'"
17551755
self.expect_failure(block, err, lineno=4)
17561756

17571757
def test_depr_star_duplicate(self):
@@ -1765,7 +1765,7 @@ def test_depr_star_duplicate(self):
17651765
c: int
17661766
Docstring.
17671767
"""
1768-
err = "Function 'bar' uses '* [from ...]' more than once."
1768+
err = "Function 'bar' uses '* [from 3.14]' more than once."
17691769
self.expect_failure(block, err, lineno=5)
17701770

17711771
def test_depr_star_duplicate2(self):
@@ -1779,7 +1779,7 @@ def test_depr_star_duplicate2(self):
17791779
c: int
17801780
Docstring.
17811781
"""
1782-
err = "Function 'bar' uses '* [from ...]' more than once."
1782+
err = "Function 'bar': '* [from 3.15]' must precede '* [from 3.14]'"
17831783
self.expect_failure(block, err, lineno=5)
17841784

17851785
def test_depr_slash_duplicate(self):
@@ -1793,21 +1793,21 @@ def test_depr_slash_duplicate(self):
17931793
c: int
17941794
Docstring.
17951795
"""
1796-
err = "Function 'bar' uses '/ [from ...]' more than once."
1796+
err = "Function 'bar' uses '/ [from 3.14]' more than once."
17971797
self.expect_failure(block, err, lineno=5)
17981798

17991799
def test_depr_slash_duplicate2(self):
18001800
block = """
18011801
module foo
18021802
foo.bar
18031803
a: int
1804-
/ [from 3.14]
1805-
b: int
18061804
/ [from 3.15]
1805+
b: int
1806+
/ [from 3.14]
18071807
c: int
18081808
Docstring.
18091809
"""
1810-
err = "Function 'bar' uses '/ [from ...]' more than once."
1810+
err = "Function 'bar': '/ [from 3.14]' must precede '/ [from 3.15]'"
18111811
self.expect_failure(block, err, lineno=5)
18121812

18131813
def test_single_slash(self):
@@ -2724,7 +2724,15 @@ class ClinicFunctionalTest(unittest.TestCase):
27242724
locals().update((name, getattr(ac_tester, name))
27252725
for name in dir(ac_tester) if name.startswith('test_'))
27262726

2727-
def check_depr_star(self, pnames, fn, *args, name=None, **kwds):
2727+
def check_depr(self, regex, fn, /, *args, **kwds):
2728+
with self.assertWarnsRegex(DeprecationWarning, regex) as cm:
2729+
# Record the line number, so we're sure we've got the correct stack
2730+
# level on the deprecation warning.
2731+
_, lineno = fn(*args, **kwds), sys._getframe().f_lineno
2732+
self.assertEqual(cm.filename, __file__)
2733+
self.assertEqual(cm.lineno, lineno)
2734+
2735+
def check_depr_star(self, pnames, fn, /, *args, name=None, **kwds):
27282736
if name is None:
27292737
name = fn.__qualname__
27302738
if isinstance(fn, type):
@@ -2734,12 +2742,7 @@ def check_depr_star(self, pnames, fn, *args, name=None, **kwds):
27342742
fr"{re.escape(name)}\(\) is deprecated. Parameters? {pnames} will "
27352743
fr"become( a)? keyword-only parameters? in Python 3\.14"
27362744
)
2737-
with self.assertWarnsRegex(DeprecationWarning, regex) as cm:
2738-
# Record the line number, so we're sure we've got the correct stack
2739-
# level on the deprecation warning.
2740-
_, lineno = fn(*args, **kwds), sys._getframe().f_lineno
2741-
self.assertEqual(cm.filename, __file__)
2742-
self.assertEqual(cm.lineno, lineno)
2745+
self.check_depr(regex, fn, *args, **kwds)
27432746

27442747
def check_depr_kwd(self, pnames, fn, *args, name=None, **kwds):
27452748
if name is None:
@@ -2749,15 +2752,10 @@ def check_depr_kwd(self, pnames, fn, *args, name=None, **kwds):
27492752
pl = 's' if ' ' in pnames else ''
27502753
regex = (
27512754
fr"Passing keyword argument{pl} {pnames} to "
2752-
fr"{re.escape(name)}\(\) is deprecated. Corresponding parameter{pl} "
2755+
fr"{re.escape(name)}\(\) is deprecated. Parameter{pl} {pnames} "
27532756
fr"will become positional-only in Python 3\.14."
27542757
)
2755-
with self.assertWarnsRegex(DeprecationWarning, regex) as cm:
2756-
# Record the line number, so we're sure we've got the correct stack
2757-
# level on the deprecation warning.
2758-
_, lineno = fn(*args, **kwds), sys._getframe().f_lineno
2759-
self.assertEqual(cm.filename, __file__)
2760-
self.assertEqual(cm.lineno, lineno)
2758+
self.check_depr(regex, fn, *args, **kwds)
27612759

27622760
def test_objects_converter(self):
27632761
with self.assertRaises(TypeError):
@@ -3368,6 +3366,24 @@ def test_depr_star_noinline(self):
33683366
check("a", "b", c="c")
33693367
self.assertRaises(TypeError, fn, "a", "b", "c", "d")
33703368

3369+
def test_depr_star_multi(self):
3370+
fn = ac_tester.depr_star_multi
3371+
self.assertRaises(TypeError, fn, "a")
3372+
fn("a", b="b", c="c", d="d", e="e", f="f", g="g", h="h")
3373+
errmsg = (
3374+
"Passing more than 1 positional argument to depr_star_multi() is deprecated. "
3375+
"Parameter 'b' will become a keyword-only parameter in Python 3.16. "
3376+
"Parameters 'c' and 'd' will become keyword-only parameters in Python 3.15. "
3377+
"Parameters 'e', 'f' and 'g' will become keyword-only parameters in Python 3.14.")
3378+
check = partial(self.check_depr, re.escape(errmsg), fn)
3379+
check("a", "b", c="c", d="d", e="e", f="f", g="g", h="h")
3380+
check("a", "b", "c", d="d", e="e", f="f", g="g", h="h")
3381+
check("a", "b", "c", "d", e="e", f="f", g="g", h="h")
3382+
check("a", "b", "c", "d", "e", f="f", g="g", h="h")
3383+
check("a", "b", "c", "d", "e", "f", g="g", h="h")
3384+
check("a", "b", "c", "d", "e", "f", "g", h="h")
3385+
self.assertRaises(TypeError, fn, "a", "b", "c", "d", "e", "f", "g", "h")
3386+
33713387
def test_depr_kwd_required_1(self):
33723388
fn = ac_tester.depr_kwd_required_1
33733389
fn("a", "b")
@@ -3452,6 +3468,44 @@ def test_depr_kwd_noinline(self):
34523468
self.assertRaises(TypeError, fn, "a", c="c")
34533469
self.assertRaises(TypeError, fn, a="a", b="b", c="c")
34543470

3471+
def test_depr_kwd_multi(self):
3472+
fn = ac_tester.depr_kwd_multi
3473+
fn("a", "b", "c", "d", "e", "f", "g", h="h")
3474+
errmsg = (
3475+
"Passing keyword arguments 'b', 'c', 'd', 'e', 'f' and 'g' to depr_kwd_multi() is deprecated. "
3476+
"Parameter 'b' will become positional-only in Python 3.14. "
3477+
"Parameters 'c' and 'd' will become positional-only in Python 3.15. "
3478+
"Parameters 'e', 'f' and 'g' will become positional-only in Python 3.16.")
3479+
check = partial(self.check_depr, re.escape(errmsg), fn)
3480+
check("a", "b", "c", "d", "e", "f", g="g", h="h")
3481+
check("a", "b", "c", "d", "e", f="f", g="g", h="h")
3482+
check("a", "b", "c", "d", e="e", f="f", g="g", h="h")
3483+
check("a", "b", "c", d="d", e="e", f="f", g="g", h="h")
3484+
check("a", "b", c="c", d="d", e="e", f="f", g="g", h="h")
3485+
check("a", b="b", c="c", d="d", e="e", f="f", g="g", h="h")
3486+
self.assertRaises(TypeError, fn, a="a", b="b", c="c", d="d", e="e", f="f", g="g", h="h")
3487+
3488+
def test_depr_multi(self):
3489+
fn = ac_tester.depr_multi
3490+
self.assertRaises(TypeError, fn, "a", "b", "c", "d", "e", "f", "g")
3491+
errmsg = (
3492+
"Passing more than 4 positional arguments to depr_multi() is deprecated. "
3493+
"Parameter 'e' will become a keyword-only parameter in Python 3.15. "
3494+
"Parameter 'f' will become a keyword-only parameter in Python 3.14.")
3495+
check = partial(self.check_depr, re.escape(errmsg), fn)
3496+
check("a", "b", "c", "d", "e", "f", g="g")
3497+
check("a", "b", "c", "d", "e", f="f", g="g")
3498+
fn("a", "b", "c", "d", e="e", f="f", g="g")
3499+
fn("a", "b", "c", d="d", e="e", f="f", g="g")
3500+
errmsg = (
3501+
"Passing keyword arguments 'b' and 'c' to depr_multi() is deprecated. "
3502+
"Parameter 'b' will become positional-only in Python 3.14. "
3503+
"Parameter 'c' will become positional-only in Python 3.15.")
3504+
check = partial(self.check_depr, re.escape(errmsg), fn)
3505+
check("a", "b", c="c", d="d", e="e", f="f", g="g")
3506+
check("a", b="b", c="c", d="d", e="e", f="f", g="g")
3507+
self.assertRaises(TypeError, fn, a="a", b="b", c="c", d="d", e="e", f="f", g="g")
3508+
34553509

34563510
class PermutationTests(unittest.TestCase):
34573511
"""Test permutation support functions."""

Modules/_testclinic.c

+82
Original file line numberDiff line numberDiff line change
@@ -1580,6 +1580,32 @@ depr_star_noinline_impl(PyObject *module, PyObject *a, PyObject *b,
15801580
}
15811581

15821582

1583+
/*[clinic input]
1584+
depr_star_multi
1585+
a: object
1586+
* [from 3.16]
1587+
b: object
1588+
* [from 3.15]
1589+
c: object
1590+
d: object
1591+
* [from 3.14]
1592+
e: object
1593+
f: object
1594+
g: object
1595+
*
1596+
h: object
1597+
[clinic start generated code]*/
1598+
1599+
static PyObject *
1600+
depr_star_multi_impl(PyObject *module, PyObject *a, PyObject *b, PyObject *c,
1601+
PyObject *d, PyObject *e, PyObject *f, PyObject *g,
1602+
PyObject *h)
1603+
/*[clinic end generated code: output=77681653f4202068 input=3ebd05d888a957ea]*/
1604+
{
1605+
Py_RETURN_NONE;
1606+
}
1607+
1608+
15831609
/*[clinic input]
15841610
depr_kwd_required_1
15851611
a: object
@@ -1702,6 +1728,59 @@ depr_kwd_noinline_impl(PyObject *module, PyObject *a, PyObject *b,
17021728
Py_RETURN_NONE;
17031729
}
17041730

1731+
1732+
/*[clinic input]
1733+
depr_kwd_multi
1734+
a: object
1735+
/
1736+
b: object
1737+
/ [from 3.14]
1738+
c: object
1739+
d: object
1740+
/ [from 3.15]
1741+
e: object
1742+
f: object
1743+
g: object
1744+
/ [from 3.16]
1745+
h: object
1746+
[clinic start generated code]*/
1747+
1748+
static PyObject *
1749+
depr_kwd_multi_impl(PyObject *module, PyObject *a, PyObject *b, PyObject *c,
1750+
PyObject *d, PyObject *e, PyObject *f, PyObject *g,
1751+
PyObject *h)
1752+
/*[clinic end generated code: output=ddfbde80fe1942e1 input=7a074e621c79efd7]*/
1753+
{
1754+
Py_RETURN_NONE;
1755+
}
1756+
1757+
1758+
/*[clinic input]
1759+
depr_multi
1760+
a: object
1761+
/
1762+
b: object
1763+
/ [from 3.14]
1764+
c: object
1765+
/ [from 3.15]
1766+
d: object
1767+
* [from 3.15]
1768+
e: object
1769+
* [from 3.14]
1770+
f: object
1771+
*
1772+
g: object
1773+
[clinic start generated code]*/
1774+
1775+
static PyObject *
1776+
depr_multi_impl(PyObject *module, PyObject *a, PyObject *b, PyObject *c,
1777+
PyObject *d, PyObject *e, PyObject *f, PyObject *g)
1778+
/*[clinic end generated code: output=f81c92852ca2d4ee input=5b847c5e44bedd02]*/
1779+
{
1780+
Py_RETURN_NONE;
1781+
}
1782+
1783+
17051784
// Reset PY_VERSION_HEX
17061785
#undef PY_VERSION_HEX
17071786
#define PY_VERSION_HEX _SAVED_PY_VERSION
@@ -1779,13 +1858,16 @@ static PyMethodDef tester_methods[] = {
17791858
DEPR_STAR_POS2_LEN2_METHODDEF
17801859
DEPR_STAR_POS2_LEN2_WITH_KWD_METHODDEF
17811860
DEPR_STAR_NOINLINE_METHODDEF
1861+
DEPR_STAR_MULTI_METHODDEF
17821862
DEPR_KWD_REQUIRED_1_METHODDEF
17831863
DEPR_KWD_REQUIRED_2_METHODDEF
17841864
DEPR_KWD_OPTIONAL_1_METHODDEF
17851865
DEPR_KWD_OPTIONAL_2_METHODDEF
17861866
DEPR_KWD_OPTIONAL_3_METHODDEF
17871867
DEPR_KWD_REQUIRED_OPTIONAL_METHODDEF
17881868
DEPR_KWD_NOINLINE_METHODDEF
1869+
DEPR_KWD_MULTI_METHODDEF
1870+
DEPR_MULTI_METHODDEF
17891871
{NULL, NULL}
17901872
};
17911873

0 commit comments

Comments
 (0)