]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-108494: AC supports pos-only args in limited C API (#108498)
authorVictor Stinner <vstinner@python.org>
Fri, 25 Aug 2023 22:39:24 +0000 (00:39 +0200)
committerGitHub <noreply@github.com>
Fri, 25 Aug 2023 22:39:24 +0000 (00:39 +0200)
AC now checks for "#define Py_LIMITED_API" pattern to use the limited
C API.

Lib/test/test_clinic.py
Modules/_testclinic_limited.c
Modules/clinic/_testclinic_limited.c.h
Tools/clinic/clinic.py

index 9ee8f9ce835bbd3ae2f0fd64a2cfe2b4c4c0b971..e7039d59070597191b8c3d4fd22235e322897984 100644 (file)
@@ -3542,6 +3542,17 @@ class LimitedCAPIFunctionalTest(unittest.TestCase):
         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):
index 6dd2745a7117c2d32e64363010b734ee6c458ec4..0b606c9857fc408305661cb778356732f04d9a2d 100644 (file)
@@ -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}
 };
 
index 730e967ad610dad083025465b97e2154ed63b0ae..9b0032528ff746c9114dda660836aa784a218b16 100644 (file)
@@ -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]*/
index 3d3ab4bf81a5b508e13353d847e98166db1a0477..a6974bd81e2d07f785ef639f333c31c51d69c1ad 100755 (executable)
@@ -78,6 +78,7 @@ CLINIC_PREFIXED_ARGS = {
     "noptargs",
     "return_value",
 }
+LIMITED_CAPI_REGEX = re.compile(r'#define +Py_LIMITED_API')
 
 
 class Sentinels(enum.Enum):
@@ -1249,6 +1250,22 @@ class CLanguage(Language):
             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,