Skip to content

Commit 86bc9e3

Browse files
authored
gh-108494: AC supports pos-only args in limited C API (#108498)
AC now checks for "#define Py_LIMITED_API" pattern to use the limited C API.
1 parent 73d33c1 commit 86bc9e3

File tree

4 files changed

+82
-5
lines changed

4 files changed

+82
-5
lines changed

Lib/test/test_clinic.py

+11
Original file line numberDiff line numberDiff line change
@@ -3542,6 +3542,17 @@ def test_my_int_func(self):
35423542
with self.assertRaises(TypeError):
35433543
_testclinic_limited.my_int_func("xyz")
35443544

3545+
def test_my_int_sum(self):
3546+
with self.assertRaises(TypeError):
3547+
_testclinic_limited.my_int_sum()
3548+
with self.assertRaises(TypeError):
3549+
_testclinic_limited.my_int_sum(1)
3550+
self.assertEqual(_testclinic_limited.my_int_sum(1, 2), 3)
3551+
with self.assertRaises(TypeError):
3552+
_testclinic_limited.my_int_sum(1.0, 2)
3553+
with self.assertRaises(TypeError):
3554+
_testclinic_limited.my_int_sum(1, "str")
3555+
35453556

35463557

35473558
class PermutationTests(unittest.TestCase):

Modules/_testclinic_limited.c

+18
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,27 @@ my_int_func_impl(PyObject *module, int arg)
4545
}
4646

4747

48+
/*[clinic input]
49+
my_int_sum -> int
50+
51+
x: int
52+
y: int
53+
/
54+
55+
[clinic start generated code]*/
56+
57+
static int
58+
my_int_sum_impl(PyObject *module, int x, int y)
59+
/*[clinic end generated code: output=3e52db9ab5f37e2f input=0edb6796813bf2d3]*/
60+
{
61+
return x + y;
62+
}
63+
64+
4865
static PyMethodDef tester_methods[] = {
4966
TEST_EMPTY_FUNCTION_METHODDEF
5067
MY_INT_FUNC_METHODDEF
68+
MY_INT_SUM_METHODDEF
5169
{NULL, NULL}
5270
};
5371

Modules/clinic/_testclinic_limited.c.h

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

Tools/clinic/clinic.py

+20-4
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
"noptargs",
7979
"return_value",
8080
}
81+
LIMITED_CAPI_REGEX = re.compile(r'#define +Py_LIMITED_API')
8182

8283

8384
class Sentinels(enum.Enum):
@@ -1249,6 +1250,22 @@ def parser_body(
12491250
parser_prototype = self.PARSER_PROTOTYPE_VARARGS
12501251
parser_definition = parser_body(parser_prototype, ' {option_group_parsing}')
12511252

1253+
elif not requires_defining_class and pos_only == len(parameters) - pseudo_args and clinic.limited_capi:
1254+
# positional-only for the limited C API
1255+
flags = "METH_VARARGS"
1256+
1257+
parser_prototype = self.PARSER_PROTOTYPE_VARARGS
1258+
parser_code = [normalize_snippet("""
1259+
if (!PyArg_ParseTuple(args, "{format_units}:{name}",
1260+
{parse_arguments}))
1261+
goto exit;
1262+
""", indent=4)]
1263+
argname_fmt = 'args[%d]'
1264+
declarations = ""
1265+
1266+
parser_definition = parser_body(parser_prototype, *parser_code,
1267+
declarations=declarations)
1268+
12521269
elif not requires_defining_class and pos_only == len(parameters) - pseudo_args:
12531270
if not new_or_init:
12541271
# positional-only, but no option groups
@@ -2581,10 +2598,6 @@ def parse_file(
25812598
) -> None:
25822599
verify = not ns.force
25832600
limited_capi = ns.limited_capi
2584-
# XXX Temporary solution
2585-
if os.path.basename(filename) == '_testclinic_limited.c':
2586-
print(f"{filename} uses limited C API")
2587-
limited_capi = True
25882601
if not output:
25892602
output = filename
25902603

@@ -2605,6 +2618,9 @@ def parse_file(
26052618
if not find_start_re.search(raw):
26062619
return
26072620

2621+
if LIMITED_CAPI_REGEX.search(raw):
2622+
limited_capi = True
2623+
26082624
assert isinstance(language, CLanguage)
26092625
clinic = Clinic(language,
26102626
verify=verify,

0 commit comments

Comments
 (0)