summaryrefslogtreecommitdiffstats
path: root/Tools
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2023-08-25 21:22:08 (GMT)
committerGitHub <noreply@github.com>2023-08-25 21:22:08 (GMT)
commit1dd951097728d735d46a602fc43285d35b7b32cb (patch)
tree5becd43c129047a61de332ffb60994a4a2b20fbe /Tools
parent4eae1e53425d3a816a26760f28d128a4f05c1da4 (diff)
downloadcpython-1dd951097728d735d46a602fc43285d35b7b32cb.zip
cpython-1dd951097728d735d46a602fc43285d35b7b32cb.tar.gz
cpython-1dd951097728d735d46a602fc43285d35b7b32cb.tar.bz2
gh-108494: Argument Clinic partial supports of Limited C API (#108495)
Argument Clinic now has a partial support of the Limited API: * Add --limited option to clinic.c. * Add '_testclinic_limited' extension which is built with the limited C API version 3.13. * For now, hardcode in clinic.py that "_testclinic_limited.c" targets the limited C API.
Diffstat (limited to 'Tools')
-rw-r--r--Tools/build/generate_stdlib_module_names.py1
-rwxr-xr-xTools/clinic/clinic.py55
2 files changed, 45 insertions, 11 deletions
diff --git a/Tools/build/generate_stdlib_module_names.py b/Tools/build/generate_stdlib_module_names.py
index 72f6923..766a85d 100644
--- a/Tools/build/generate_stdlib_module_names.py
+++ b/Tools/build/generate_stdlib_module_names.py
@@ -28,6 +28,7 @@ IGNORE = {
'_testbuffer',
'_testcapi',
'_testclinic',
+ '_testclinic_limited',
'_testconsole',
'_testimportmultiple',
'_testinternalcapi',
diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py
index a541c9f..898347f 100755
--- a/Tools/clinic/clinic.py
+++ b/Tools/clinic/clinic.py
@@ -63,6 +63,7 @@ from typing import (
version = '1'
+DEFAULT_LIMITED_CAPI = False
NO_VARARG = "PY_SSIZE_T_MAX"
CLINIC_PREFIX = "__clinic_"
CLINIC_PREFIXED_ARGS = {
@@ -1360,7 +1361,21 @@ class CLanguage(Language):
vararg
)
nargs = f"Py_MIN(nargs, {max_pos})" if max_pos else "0"
- if not new_or_init:
+
+ if clinic.limited_capi:
+ # positional-or-keyword arguments
+ flags = "METH_VARARGS|METH_KEYWORDS"
+
+ parser_prototype = self.PARSER_PROTOTYPE_KEYWORD
+ parser_code = [normalize_snippet("""
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "{format_units}:{name}", _keywords,
+ {parse_arguments}))
+ goto exit;
+ """, indent=4)]
+ argname_fmt = 'args[%d]'
+ declarations = ""
+
+ elif not new_or_init:
flags = "METH_FASTCALL|METH_KEYWORDS"
parser_prototype = self.PARSER_PROTOTYPE_FASTCALL_KEYWORDS
argname_fmt = 'args[%d]'
@@ -2111,7 +2126,8 @@ class BlockPrinter:
self,
block: Block,
*,
- core_includes: bool = False
+ core_includes: bool = False,
+ clinic: Clinic | None = None,
) -> None:
input = block.input
output = block.output
@@ -2140,7 +2156,11 @@ class BlockPrinter:
write("\n")
output = ''
- if core_includes:
+ if clinic:
+ limited_capi = clinic.limited_capi
+ else:
+ limited_capi = DEFAULT_LIMITED_CAPI
+ if core_includes and not limited_capi:
output += textwrap.dedent("""
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
# include "pycore_gc.h" // PyGC_Head
@@ -2344,6 +2364,7 @@ impl_definition block
*,
filename: str,
verify: bool = True,
+ limited_capi: bool = False,
) -> None:
# maps strings to Parser objects.
# (instantiated from the "parsers" global.)
@@ -2353,6 +2374,7 @@ impl_definition block
fail("Custom printers are broken right now")
self.printer = printer or BlockPrinter(language)
self.verify = verify
+ self.limited_capi = limited_capi
self.filename = filename
self.modules: ModuleDict = {}
self.classes: ClassDict = {}
@@ -2450,7 +2472,7 @@ impl_definition block
self.parsers[dsl_name] = parsers[dsl_name](self)
parser = self.parsers[dsl_name]
parser.parse(block)
- printer.print_block(block)
+ printer.print_block(block, clinic=self)
# these are destinations not buffers
for name, destination in self.destinations.items():
@@ -2465,7 +2487,7 @@ impl_definition block
block.input = "dump " + name + "\n"
warn("Destination buffer " + repr(name) + " not empty at end of file, emptying.")
printer.write("\n")
- printer.print_block(block)
+ printer.print_block(block, clinic=self)
continue
if destination.type == 'file':
@@ -2490,7 +2512,7 @@ impl_definition block
block.input = 'preserve\n'
printer_2 = BlockPrinter(self.language)
- printer_2.print_block(block, core_includes=True)
+ printer_2.print_block(block, core_includes=True, clinic=self)
write_file(destination.filename, printer_2.f.getvalue())
continue
@@ -2536,9 +2558,15 @@ impl_definition block
def parse_file(
filename: str,
*,
- verify: bool = True,
- output: str | None = None
+ ns: argparse.Namespace,
+ output: str | None = None,
) -> 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
@@ -2560,7 +2588,10 @@ def parse_file(
return
assert isinstance(language, CLanguage)
- clinic = Clinic(language, verify=verify, filename=filename)
+ clinic = Clinic(language,
+ verify=verify,
+ filename=filename,
+ limited_capi=limited_capi)
cooked = clinic.parse(raw)
write_file(output, cooked)
@@ -5987,6 +6018,8 @@ For more information see https://docs.python.org/3/howto/clinic.html""")
cmdline.add_argument("--exclude", type=str, action="append",
help=("a file to exclude in --make mode; "
"can be given multiple times"))
+ cmdline.add_argument("--limited", dest="limited_capi", action='store_true',
+ help="use the Limited C API")
cmdline.add_argument("filename", metavar="FILE", type=str, nargs="*",
help="the list of files to process")
return cmdline
@@ -6077,7 +6110,7 @@ def run_clinic(parser: argparse.ArgumentParser, ns: argparse.Namespace) -> None:
continue
if ns.verbose:
print(path)
- parse_file(path, verify=not ns.force)
+ parse_file(path, ns=ns)
return
if not ns.filename:
@@ -6089,7 +6122,7 @@ def run_clinic(parser: argparse.ArgumentParser, ns: argparse.Namespace) -> None:
for filename in ns.filename:
if ns.verbose:
print(filename)
- parse_file(filename, output=ns.output, verify=not ns.force)
+ parse_file(filename, output=ns.output, ns=ns)
def main(argv: list[str] | None = None) -> NoReturn: