diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index 9ee8f9ce835bbd..e7039d59070597 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -3542,6 +3542,17 @@ def test_my_int_func(self): with self.assertRaises(TypeError): _testclinic_limited.my_int_func("xyz") + def test_my_int_sum(self): + with self.assertRaises(TypeError): + _testclinic_limited.my_int_sum() + with self.assertRaises(TypeError): + _testclinic_limited.my_int_sum(1) + self.assertEqual(_testclinic_limited.my_int_sum(1, 2), 3) + with self.assertRaises(TypeError): + _testclinic_limited.my_int_sum(1.0, 2) + with self.assertRaises(TypeError): + _testclinic_limited.my_int_sum(1, "str") + class PermutationTests(unittest.TestCase): diff --git a/Modules/_testclinic_limited.c b/Modules/_testclinic_limited.c index 6dd2745a7117c2..0b606c9857fc40 100644 --- a/Modules/_testclinic_limited.c +++ b/Modules/_testclinic_limited.c @@ -45,9 +45,27 @@ my_int_func_impl(PyObject *module, int arg) } +/*[clinic input] +my_int_sum -> int + + x: int + y: int + / + +[clinic start generated code]*/ + +static int +my_int_sum_impl(PyObject *module, int x, int y) +/*[clinic end generated code: output=3e52db9ab5f37e2f input=0edb6796813bf2d3]*/ +{ + return x + y; +} + + static PyMethodDef tester_methods[] = { TEST_EMPTY_FUNCTION_METHODDEF MY_INT_FUNC_METHODDEF + MY_INT_SUM_METHODDEF {NULL, NULL} }; diff --git a/Modules/clinic/_testclinic_limited.c.h b/Modules/clinic/_testclinic_limited.c.h index 730e967ad610da..9b0032528ff746 100644 --- a/Modules/clinic/_testclinic_limited.c.h +++ b/Modules/clinic/_testclinic_limited.c.h @@ -50,4 +50,36 @@ my_int_func(PyObject *module, PyObject *arg_) exit: return return_value; } -/*[clinic end generated code: output=07e2e8ed6923cd16 input=a9049054013a1b77]*/ + +PyDoc_STRVAR(my_int_sum__doc__, +"my_int_sum($module, x, y, /)\n" +"--\n" +"\n"); + +#define MY_INT_SUM_METHODDEF \ + {"my_int_sum", (PyCFunction)my_int_sum, METH_VARARGS, my_int_sum__doc__}, + +static int +my_int_sum_impl(PyObject *module, int x, int y); + +static PyObject * +my_int_sum(PyObject *module, PyObject *args) +{ + PyObject *return_value = NULL; + int x; + int y; + int _return_value; + + if (!PyArg_ParseTuple(args, "ii:my_int_sum", + &x, &y)) + goto exit; + _return_value = my_int_sum_impl(module, x, y); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyLong_FromLong((long)_return_value); + +exit: + return return_value; +} +/*[clinic end generated code: output=f9f7209255bb969e input=a9049054013a1b77]*/ diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 3d3ab4bf81a5b5..a6974bd81e2d07 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -78,6 +78,7 @@ "noptargs", "return_value", } +LIMITED_CAPI_REGEX = re.compile(r'#define +Py_LIMITED_API') class Sentinels(enum.Enum): @@ -1249,6 +1250,22 @@ def parser_body( parser_prototype = self.PARSER_PROTOTYPE_VARARGS parser_definition = parser_body(parser_prototype, ' {option_group_parsing}') + elif not requires_defining_class and pos_only == len(parameters) - pseudo_args and clinic.limited_capi: + # positional-only for the limited C API + flags = "METH_VARARGS" + + parser_prototype = self.PARSER_PROTOTYPE_VARARGS + parser_code = [normalize_snippet(""" + if (!PyArg_ParseTuple(args, "{format_units}:{name}", + {parse_arguments})) + goto exit; + """, indent=4)] + argname_fmt = 'args[%d]' + declarations = "" + + parser_definition = parser_body(parser_prototype, *parser_code, + declarations=declarations) + elif not requires_defining_class and pos_only == len(parameters) - pseudo_args: if not new_or_init: # positional-only, but no option groups @@ -2581,10 +2598,6 @@ def parse_file( ) -> None: verify = not ns.force limited_capi = ns.limited_capi - # XXX Temporary solution - if os.path.basename(filename) == '_testclinic_limited.c': - print(f"{filename} uses limited C API") - limited_capi = True if not output: output = filename @@ -2605,6 +2618,9 @@ def parse_file( if not find_start_re.search(raw): return + if LIMITED_CAPI_REGEX.search(raw): + limited_capi = True + assert isinstance(language, CLanguage) clinic = Clinic(language, verify=verify,