Skip to content

Commit 61ada45

Browse files
committed
Add a test class where all args are keyword allowed to increase coverage of generated cases
1 parent 7f56bb0 commit 61ada45

5 files changed

Lines changed: 145 additions & 4 deletions

File tree

Lib/test/test_clinic.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4444,6 +4444,21 @@ def test_vc_new_exact_subclass(self):
44444444
self.assertIsInstance(obj, Sub)
44454445
self.assertIsInstance(obj, ac_tester.VcNewExact)
44464446

4447+
def test_vc_kwonly(self):
4448+
# keyword-only 'b': vectorcall has no kwnames==NULL fast path,
4449+
# so every call goes through the helper.
4450+
self.assertIsInstance(ac_tester.VcKwOnly(1), ac_tester.VcKwOnly)
4451+
self.assertIsInstance(ac_tester.VcKwOnly(1, b=2), ac_tester.VcKwOnly)
4452+
self.assertIsInstance(ac_tester.VcKwOnly(a=1, b=2), ac_tester.VcKwOnly)
4453+
4454+
def test_vc_kwonly_b_as_positional(self):
4455+
with self.assertRaises(TypeError):
4456+
ac_tester.VcKwOnly(1, 2)
4457+
4458+
def test_vc_kwonly_missing_required(self):
4459+
with self.assertRaises(TypeError):
4460+
ac_tester.VcKwOnly()
4461+
44474462

44484463
class LimitedCAPIOutputTests(unittest.TestCase):
44494464

Modules/_testclinic.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ custom_converter(PyObject *obj, custom_t *val)
2626
static PyTypeObject VcNew_Type;
2727
static PyTypeObject VcInit_Type;
2828
static PyTypeObject VcNewExact_Type;
29+
static PyTypeObject VcKwOnly_Type;
2930
#include "clinic/_testclinic.c.h"
3031

3132

@@ -2407,6 +2408,38 @@ static PyTypeObject VcNewExact_Type = {
24072408
};
24082409

24092410

2411+
/* VcKwOnly: @vectorcall + keyword-only arg.
2412+
* Exercises the no-kwnames==NULL-fast-path branch of the vectorcall codegen:
2413+
* the vectorcall function delegates unconditionally to the helper because the
2414+
* keyword-only parameter rules out the positional-only fast path. */
2415+
2416+
/*[clinic input]
2417+
class _testclinic.VcKwOnly "PyObject *" "&VcKwOnly_Type"
2418+
@classmethod
2419+
@vectorcall
2420+
_testclinic.VcKwOnly.__new__ as vc_kwonly_new
2421+
a: object
2422+
*
2423+
b: object = None
2424+
[clinic start generated code]*/
2425+
2426+
static PyObject *
2427+
vc_kwonly_new_impl(PyTypeObject *type, PyObject *a, PyObject *b)
2428+
/*[clinic end generated code: output=00417079caa234dc input=68c863b55575a9e1]*/
2429+
{
2430+
return type->tp_alloc(type, 0);
2431+
}
2432+
2433+
static PyTypeObject VcKwOnly_Type = {
2434+
PyVarObject_HEAD_INIT(NULL, 0)
2435+
.tp_name = "_testclinic.VcKwOnly",
2436+
.tp_basicsize = sizeof(PyObject),
2437+
.tp_flags = Py_TPFLAGS_DEFAULT,
2438+
.tp_new = vc_kwonly_new,
2439+
.tp_vectorcall = vc_kwonly_vectorcall,
2440+
};
2441+
2442+
24102443

24112444
/*[clinic input]
24122445
output push
@@ -2636,6 +2669,9 @@ PyInit__testclinic(void)
26362669
if (PyModule_AddType(m, &VcNewExact_Type) < 0) {
26372670
goto error;
26382671
}
2672+
if (PyModule_AddType(m, &VcKwOnly_Type) < 0) {
2673+
goto error;
2674+
}
26392675
return m;
26402676

26412677
error:

Modules/clinic/_testclinic.c.h

Lines changed: 83 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Tools/c-analyzer/cpython/globals-to-fix.tsv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@ Modules/_testclinic.c - DeprKwdInitNoInline -
354354
Modules/_testclinic.c - DeprKwdNew -
355355
Modules/_testclinic.c - TestClass -
356356
Modules/_testclinic.c - VcInit_Type -
357+
Modules/_testclinic.c - VcKwOnly_Type -
357358
Modules/_testclinic.c - VcNew_Type -
358359
Modules/_testclinic.c - VcNewExact_Type -
359360

Tools/clinic/libclinic/parse_args.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1206,7 +1206,14 @@ def _vc_prototype(self) -> str:
12061206
size_t nargsf, PyObject *kwnames)
12071207
""")
12081208

1209-
def _vc_preamble(self) -> str:
1209+
def _vc_preamble(self, needs_finale: bool) -> str:
1210+
if not needs_finale:
1211+
# No fast path, no impl call: return_value and the per-arg
1212+
# locals are unused — emit only what the helper call needs.
1213+
return libclinic.normalize_snippet("""
1214+
{{
1215+
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
1216+
""") + "\n"
12101217
return libclinic.normalize_snippet("""
12111218
{{
12121219
PyObject *return_value = NULL;
@@ -1275,7 +1282,7 @@ def generate_vectorcall(self) -> str:
12751282
"""Generate a vectorcall function for __init__ or __new__."""
12761283
parsing_code, needs_finale = self._generate_vc_parsing_code()
12771284

1278-
lines = [self._vc_prototype(), self._vc_preamble()]
1285+
lines = [self._vc_prototype(), self._vc_preamble(needs_finale)]
12791286

12801287
exact_check = self._vc_exact_check()
12811288
if exact_check:
@@ -1288,7 +1295,7 @@ def generate_vectorcall(self) -> str:
12881295
# Slow path already returned via the helper call; close the
12891296
# function so the impl-call finale would not be emitted as
12901297
# dead code.
1291-
lines.append("}")
1298+
lines.append("}}")
12921299

12931300
code = libclinic.linear_format(
12941301
"\n".join(lines),

0 commit comments

Comments
 (0)