From 830fb6488e89072f70a8d65269393d481aee1d63 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 25 Aug 2023 16:42:51 +0200 Subject: [PATCH 1/3] gh-107603: Argument Clinic can emit includes * 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. --- Tools/clinic/clinic.py | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 898347fd7120a2..f13b11ebd106f4 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -1075,6 +1075,11 @@ def output_templates( 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 @@ -2127,6 +2132,7 @@ def print_block( block: Block, *, core_includes: bool = False, + # needed if core_includes is true clinic: Clinic | None = None, ) -> None: input = block.input @@ -2169,6 +2175,13 @@ def print_block( """) + if clinic: + # 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) if output: @@ -2311,7 +2324,7 @@ def __init__(self, clinic: Clinic) -> None: ... def parse(self, block: Block) -> None: ... -clinic = None +clinic : Clinic | None = None class Clinic: presets_text = """ @@ -2379,6 +2392,9 @@ def __init__( 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 +2453,12 @@ def __init__( 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 +3088,9 @@ class CConverter(metaclass=CConverterAutoRegister): # Only set by self_converter. signature_name: str | None = None + # Optional #include "name" // reason + include: tuple[str, str] | None = None + # keep in sync with self_converter.__init__! def __init__(self, # Positional args: @@ -3370,6 +3395,11 @@ def parser_name(self) -> str: else: return self.name + def add_include(self, name: str, reason: str) -> None: + if self.include: + 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 +6019,6 @@ def do_post_block_processing_cleanup(self, lineno: int) -> None: } -clinic = None - - def create_cli() -> argparse.ArgumentParser: cmdline = argparse.ArgumentParser( prog="clinic.py", From 68d499e2a0462db8af18895f72e03fed872cc97f Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 25 Aug 2023 23:14:45 +0200 Subject: [PATCH 2/3] Address AA-Turner's coding style review --- Tools/clinic/clinic.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index f13b11ebd106f4..fbf6664f20b429 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -2175,7 +2175,7 @@ def print_block( """) - if clinic: + if clinic is not None: # Emit optional includes for include, reason in sorted(clinic.includes.items()): line = f'#include "{include}"' @@ -2324,7 +2324,7 @@ def __init__(self, clinic: Clinic) -> None: ... def parse(self, block: Block) -> None: ... -clinic : Clinic | None = None +clinic: Clinic | None = None class Clinic: presets_text = """ @@ -3088,7 +3088,8 @@ class CConverter(metaclass=CConverterAutoRegister): # Only set by self_converter. signature_name: str | None = None - # Optional #include "name" // reason + # 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__! @@ -3396,7 +3397,7 @@ def parser_name(self) -> str: return self.name def add_include(self, name: str, reason: str) -> None: - if self.include: + if self.include is not None: raise ValueError("a converter only supports a single include") self.include = (name, reason) From e07d07c45e92ce50a8f364ffdd1baa3e6a443ce0 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 25 Aug 2023 23:27:01 +0200 Subject: [PATCH 3/3] Simplify print_block() Always require clinic. --- Tools/clinic/clinic.py | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index fbf6664f20b429..3d3ab4bf81a5b5 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -2131,9 +2131,8 @@ def print_block( self, block: Block, *, + clinic: Clinic, core_includes: bool = False, - # needed if core_includes is true - clinic: Clinic | None = None, ) -> None: input = block.input output = block.output @@ -2162,18 +2161,15 @@ def print_block( 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