Skip to content

Commit 830fb64

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 1dd9510 commit 830fb64

File tree

1 file changed

+31
-4
lines changed

1 file changed

+31
-4
lines changed

Tools/clinic/clinic.py

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,6 +1075,11 @@ def output_templates(
10751075
del parameters[0]
10761076
converters = [p.converter for p in parameters]
10771077

1078+
# Copy includes from parameters to Clinic
1079+
for converter in converters:
1080+
if converter.include:
1081+
clinic.add_include(*converter.include)
1082+
10781083
has_option_groups = parameters and (parameters[0].group or parameters[-1].group)
10791084
default_return_converter = f.return_converter.type == 'PyObject *'
10801085
new_or_init = f.kind.new_or_init
@@ -2127,6 +2132,7 @@ def print_block(
21272132
block: Block,
21282133
*,
21292134
core_includes: bool = False,
2135+
# needed if core_includes is true
21302136
clinic: Clinic | None = None,
21312137
) -> None:
21322138
input = block.input
@@ -2169,6 +2175,13 @@ def print_block(
21692175
21702176
""")
21712177

2178+
if clinic:
2179+
# Emit optional includes
2180+
for include, reason in sorted(clinic.includes.items()):
2181+
line = f'#include "{include}"'
2182+
line = line.ljust(35) + f'// {reason}\n'
2183+
output += line
2184+
21722185
input = ''.join(block.input)
21732186
output += ''.join(block.output)
21742187
if output:
@@ -2311,7 +2324,7 @@ def __init__(self, clinic: Clinic) -> None: ...
23112324
def parse(self, block: Block) -> None: ...
23122325

23132326

2314-
clinic = None
2327+
clinic : Clinic | None = None
23152328
class Clinic:
23162329

23172330
presets_text = """
@@ -2379,6 +2392,9 @@ def __init__(
23792392
self.modules: ModuleDict = {}
23802393
self.classes: ClassDict = {}
23812394
self.functions: list[Function] = []
2395+
# dict: include name => reason
2396+
# Example: 'pycore_long.h' => '_PyLong_UnsignedShort_Converter()'
2397+
self.includes: dict[str, str] = {}
23822398

23832399
self.line_prefix = self.line_suffix = ''
23842400

@@ -2437,6 +2453,12 @@ def __init__(
24372453
global clinic
24382454
clinic = self
24392455

2456+
def add_include(self, name: str, reason: str) -> None:
2457+
if name in self.includes:
2458+
# Mention a single reason is enough, no need to list all of them
2459+
return
2460+
self.includes[name] = reason
2461+
24402462
def add_destination(
24412463
self,
24422464
name: str,
@@ -3066,6 +3088,9 @@ class CConverter(metaclass=CConverterAutoRegister):
30663088
# Only set by self_converter.
30673089
signature_name: str | None = None
30683090

3091+
# Optional #include "name" // reason
3092+
include: tuple[str, str] | None = None
3093+
30693094
# keep in sync with self_converter.__init__!
30703095
def __init__(self,
30713096
# Positional args:
@@ -3370,6 +3395,11 @@ def parser_name(self) -> str:
33703395
else:
33713396
return self.name
33723397

3398+
def add_include(self, name: str, reason: str) -> None:
3399+
if self.include:
3400+
raise ValueError("a converter only supports a single include")
3401+
self.include = (name, reason)
3402+
33733403
type_checks = {
33743404
'&PyLong_Type': ('PyLong_Check', 'int'),
33753405
'&PyTuple_Type': ('PyTuple_Check', 'tuple'),
@@ -5989,9 +6019,6 @@ def do_post_block_processing_cleanup(self, lineno: int) -> None:
59896019
}
59906020

59916021

5992-
clinic = None
5993-
5994-
59956022
def create_cli() -> argparse.ArgumentParser:
59966023
cmdline = argparse.ArgumentParser(
59976024
prog="clinic.py",

0 commit comments

Comments
 (0)