summaryrefslogtreecommitdiffstats
path: root/Tools/clinic
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2023-08-25 22:01:10 (GMT)
committerGitHub <noreply@github.com>2023-08-25 22:01:10 (GMT)
commit73d33c1a3078c5f2588c89d61e1a17a1b2a26c34 (patch)
tree24154a2a97eb94e99971095d510dfb160be0c22a /Tools/clinic
parent1dd951097728d735d46a602fc43285d35b7b32cb (diff)
downloadcpython-73d33c1a3078c5f2588c89d61e1a17a1b2a26c34.zip
cpython-73d33c1a3078c5f2588c89d61e1a17a1b2a26c34.tar.gz
cpython-73d33c1a3078c5f2588c89d61e1a17a1b2a26c34.tar.bz2
gh-107603: Argument Clinic can emit includes (#108486)
* Add Clinic.add_include() method * Add CConverter.include and CConverter.add_include() * Printer.print_block() gets a second parameter: clinic. * Remove duplicated declaration of "clinic" global variable.
Diffstat (limited to 'Tools/clinic')
-rwxr-xr-xTools/clinic/clinic.py58
1 files changed, 41 insertions, 17 deletions
diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py
index 898347f..3d3ab4b 100755
--- a/Tools/clinic/clinic.py
+++ b/Tools/clinic/clinic.py
@@ -1075,6 +1075,11 @@ class CLanguage(Language):
del parameters[0]
converters = [p.converter for p in parameters]
+ # Copy includes from parameters to Clinic
+ for converter in converters:
+ if converter.include:
+ clinic.add_include(*converter.include)
+
has_option_groups = parameters and (parameters[0].group or parameters[-1].group)
default_return_converter = f.return_converter.type == 'PyObject *'
new_or_init = f.kind.new_or_init
@@ -2126,8 +2131,8 @@ class BlockPrinter:
self,
block: Block,
*,
+ clinic: Clinic,
core_includes: bool = False,
- clinic: Clinic | None = None,
) -> None:
input = block.input
output = block.output
@@ -2156,18 +2161,22 @@ class BlockPrinter:
write("\n")
output = ''
- 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
- # include "pycore_runtime.h" // _Py_ID()
- #endif
-
- """)
+ if core_includes:
+ if not clinic.limited_capi:
+ output += textwrap.dedent("""
+ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+ # include "pycore_gc.h" // PyGC_Head
+ # include "pycore_runtime.h" // _Py_ID()
+ #endif
+
+ """)
+
+ if clinic is not None:
+ # Emit optional includes
+ for include, reason in sorted(clinic.includes.items()):
+ line = f'#include "{include}"'
+ line = line.ljust(35) + f'// {reason}\n'
+ output += line
input = ''.join(block.input)
output += ''.join(block.output)
@@ -2311,7 +2320,7 @@ class Parser(Protocol):
def parse(self, block: Block) -> None: ...
-clinic = None
+clinic: Clinic | None = None
class Clinic:
presets_text = """
@@ -2379,6 +2388,9 @@ impl_definition block
self.modules: ModuleDict = {}
self.classes: ClassDict = {}
self.functions: list[Function] = []
+ # dict: include name => reason
+ # Example: 'pycore_long.h' => '_PyLong_UnsignedShort_Converter()'
+ self.includes: dict[str, str] = {}
self.line_prefix = self.line_suffix = ''
@@ -2437,6 +2449,12 @@ impl_definition block
global clinic
clinic = self
+ def add_include(self, name: str, reason: str) -> None:
+ if name in self.includes:
+ # Mention a single reason is enough, no need to list all of them
+ return
+ self.includes[name] = reason
+
def add_destination(
self,
name: str,
@@ -3066,6 +3084,10 @@ class CConverter(metaclass=CConverterAutoRegister):
# Only set by self_converter.
signature_name: str | None = None
+ # Optional (name, reason) include which generate a line like:
+ # "#include "name" // reason"
+ include: tuple[str, str] | None = None
+
# keep in sync with self_converter.__init__!
def __init__(self,
# Positional args:
@@ -3370,6 +3392,11 @@ class CConverter(metaclass=CConverterAutoRegister):
else:
return self.name
+ def add_include(self, name: str, reason: str) -> None:
+ if self.include is not None:
+ raise ValueError("a converter only supports a single include")
+ self.include = (name, reason)
+
type_checks = {
'&PyLong_Type': ('PyLong_Check', 'int'),
'&PyTuple_Type': ('PyTuple_Check', 'tuple'),
@@ -5989,9 +6016,6 @@ parsers: dict[str, Callable[[Clinic], Parser]] = {
}
-clinic = None
-
-
def create_cli() -> argparse.ArgumentParser:
cmdline = argparse.ArgumentParser(
prog="clinic.py",