@@ -1074,6 +1074,11 @@ def output_templates(
10741074 del parameters [0 ]
10751075 converters = [p .converter for p in parameters ]
10761076
1077+ # Copy includes from parameters to Clinic
1078+ for converter in converters :
1079+ if converter .include :
1080+ clinic .add_include (* converter .include )
1081+
10771082 has_option_groups = parameters and (parameters [0 ].group or parameters [- 1 ].group )
10781083 default_return_converter = f .return_converter .type == 'PyObject *'
10791084 new_or_init = f .kind .new_or_init
@@ -2111,7 +2116,9 @@ def print_block(
21112116 self ,
21122117 block : Block ,
21132118 * ,
2114- core_includes : bool = False
2119+ core_includes : bool = False ,
2120+ # needed if core_includes is true
2121+ clinic : Clinic | None = None ,
21152122 ) -> None :
21162123 input = block .input
21172124 output = block .output
@@ -2149,6 +2156,13 @@ def print_block(
21492156
21502157 """ )
21512158
2159+ if clinic :
2160+ # Emit optional includes
2161+ for include , reason in sorted (clinic .includes .items ()):
2162+ line = f'#include "{ include } "'
2163+ line = line .ljust (35 ) + f'// { reason } \n '
2164+ output += line
2165+
21522166 input = '' .join (block .input )
21532167 output += '' .join (block .output )
21542168 if output :
@@ -2291,7 +2305,7 @@ def __init__(self, clinic: Clinic) -> None: ...
22912305 def parse (self , block : Block ) -> None : ...
22922306
22932307
2294- clinic = None
2308+ clinic : Clinic | None = None
22952309class Clinic :
22962310
22972311 presets_text = """
@@ -2357,6 +2371,9 @@ def __init__(
23572371 self .modules : ModuleDict = {}
23582372 self .classes : ClassDict = {}
23592373 self .functions : list [Function ] = []
2374+ # dict: include name => reason
2375+ # Example: 'pycore_long.h' => '_PyLong_UnsignedShort_Converter()'
2376+ self .includes : dict [str , str ] = {}
23602377
23612378 self .line_prefix = self .line_suffix = ''
23622379
@@ -2415,6 +2432,12 @@ def __init__(
24152432 global clinic
24162433 clinic = self
24172434
2435+ def add_include (self , name : str , reason : str ) -> None :
2436+ if name in self .includes :
2437+ # Mention a single reason is enough, no need to list all of them
2438+ return
2439+ self .includes [name ] = reason
2440+
24182441 def add_destination (
24192442 self ,
24202443 name : str ,
@@ -2490,7 +2513,7 @@ def parse(self, input: str) -> str:
24902513
24912514 block .input = 'preserve\n '
24922515 printer_2 = BlockPrinter (self .language )
2493- printer_2 .print_block (block , core_includes = True )
2516+ printer_2 .print_block (block , core_includes = True , clinic = self )
24942517 write_file (destination .filename , printer_2 .f .getvalue ())
24952518 continue
24962519
@@ -3035,6 +3058,9 @@ class CConverter(metaclass=CConverterAutoRegister):
30353058 # Only set by self_converter.
30363059 signature_name : str | None = None
30373060
3061+ # Optional #include "name" // reason
3062+ include : tuple [str , str ] | None = None
3063+
30383064 # keep in sync with self_converter.__init__!
30393065 def __init__ (self ,
30403066 # Positional args:
@@ -3339,6 +3365,11 @@ def parser_name(self) -> str:
33393365 else :
33403366 return self .name
33413367
3368+ def add_include (self , name : str , reason : str ) -> None :
3369+ if self .include :
3370+ raise ValueError ("a converter only supports a single include" )
3371+ self .include = (name , reason )
3372+
33423373type_checks = {
33433374 '&PyLong_Type' : ('PyLong_Check' , 'int' ),
33443375 '&PyTuple_Type' : ('PyTuple_Check' , 'tuple' ),
@@ -5958,9 +5989,6 @@ def do_post_block_processing_cleanup(self, lineno: int) -> None:
59585989}
59595990
59605991
5961- clinic = None
5962-
5963-
59645992def create_cli () -> argparse .ArgumentParser :
59655993 cmdline = argparse .ArgumentParser (
59665994 prog = "clinic.py" ,
0 commit comments