@@ -1074,6 +1074,11 @@ def output_templates(
1074
1074
del parameters [0 ]
1075
1075
converters = [p .converter for p in parameters ]
1076
1076
1077
+ # Copy includes from parameters to Clinic
1078
+ for converter in converters :
1079
+ if converter .include :
1080
+ clinic .add_include (* converter .include )
1081
+
1077
1082
has_option_groups = parameters and (parameters [0 ].group or parameters [- 1 ].group )
1078
1083
default_return_converter = f .return_converter .type == 'PyObject *'
1079
1084
new_or_init = f .kind .new_or_init
@@ -2111,7 +2116,9 @@ def print_block(
2111
2116
self ,
2112
2117
block : Block ,
2113
2118
* ,
2114
- core_includes : bool = False
2119
+ core_includes : bool = False ,
2120
+ # needed if core_includes is true
2121
+ clinic : Clinic | None = None ,
2115
2122
) -> None :
2116
2123
input = block .input
2117
2124
output = block .output
@@ -2149,6 +2156,13 @@ def print_block(
2149
2156
2150
2157
""" )
2151
2158
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
+
2152
2166
input = '' .join (block .input )
2153
2167
output += '' .join (block .output )
2154
2168
if output :
@@ -2291,7 +2305,7 @@ def __init__(self, clinic: Clinic) -> None: ...
2291
2305
def parse (self , block : Block ) -> None : ...
2292
2306
2293
2307
2294
- clinic = None
2308
+ clinic : Clinic | None = None
2295
2309
class Clinic :
2296
2310
2297
2311
presets_text = """
@@ -2357,6 +2371,9 @@ def __init__(
2357
2371
self .modules : ModuleDict = {}
2358
2372
self .classes : ClassDict = {}
2359
2373
self .functions : list [Function ] = []
2374
+ # dict: include name => reason
2375
+ # Example: 'pycore_long.h' => '_PyLong_UnsignedShort_Converter()'
2376
+ self .includes : dict [str , str ] = {}
2360
2377
2361
2378
self .line_prefix = self .line_suffix = ''
2362
2379
@@ -2415,6 +2432,12 @@ def __init__(
2415
2432
global clinic
2416
2433
clinic = self
2417
2434
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
+
2418
2441
def add_destination (
2419
2442
self ,
2420
2443
name : str ,
@@ -2490,7 +2513,7 @@ def parse(self, input: str) -> str:
2490
2513
2491
2514
block .input = 'preserve\n '
2492
2515
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 )
2494
2517
write_file (destination .filename , printer_2 .f .getvalue ())
2495
2518
continue
2496
2519
@@ -3035,6 +3058,9 @@ class CConverter(metaclass=CConverterAutoRegister):
3035
3058
# Only set by self_converter.
3036
3059
signature_name : str | None = None
3037
3060
3061
+ # Optional #include "name" // reason
3062
+ include : tuple [str , str ] | None = None
3063
+
3038
3064
# keep in sync with self_converter.__init__!
3039
3065
def __init__ (self ,
3040
3066
# Positional args:
@@ -3339,6 +3365,11 @@ def parser_name(self) -> str:
3339
3365
else :
3340
3366
return self .name
3341
3367
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
+
3342
3373
type_checks = {
3343
3374
'&PyLong_Type' : ('PyLong_Check' , 'int' ),
3344
3375
'&PyTuple_Type' : ('PyTuple_Check' , 'tuple' ),
@@ -5958,9 +5989,6 @@ def do_post_block_processing_cleanup(self, lineno: int) -> None:
5958
5989
}
5959
5990
5960
5991
5961
- clinic = None
5962
-
5963
-
5964
5992
def create_cli () -> argparse .ArgumentParser :
5965
5993
cmdline = argparse .ArgumentParser (
5966
5994
prog = "clinic.py" ,
0 commit comments