Skip to content

Commit cdadfa1

Browse files
committed
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.
1 parent 4eae1e5 commit cdadfa1

File tree

1 file changed

+34
-6
lines changed

1 file changed

+34
-6
lines changed

Tools/clinic/clinic.py

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -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
22952309
class 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+
33423373
type_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-
59645992
def create_cli() -> argparse.ArgumentParser:
59655993
cmdline = argparse.ArgumentParser(
59665994
prog="clinic.py",

0 commit comments

Comments
 (0)