mirror of
https://github.com/python/cpython
synced 2026-09-29 12:10:30 +03:00
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.
This commit is contained in:
parent
4eae1e5342
commit
1dd9510977
7 changed files with 208 additions and 13 deletions
|
|
@ -28,6 +28,7 @@ IGNORE = {
|
|||
'_testbuffer',
|
||||
'_testcapi',
|
||||
'_testclinic',
|
||||
'_testclinic_limited',
|
||||
'_testconsole',
|
||||
'_testimportmultiple',
|
||||
'_testinternalcapi',
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue