diff options
author | Victor Stinner <vstinner@python.org> | 2023-08-25 21:22:08 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-08-25 21:22:08 (GMT) |
commit | 1dd951097728d735d46a602fc43285d35b7b32cb (patch) | |
tree | 5becd43c129047a61de332ffb60994a4a2b20fbe /Tools | |
parent | 4eae1e53425d3a816a26760f28d128a4f05c1da4 (diff) | |
download | cpython-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.py | 1 | ||||
-rwxr-xr-x | Tools/clinic/clinic.py | 55 |
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: |