Skip to content

Commit

Permalink
pythongh-107603: Argument Clinic can emit includes (python#108486)
Browse files Browse the repository at this point in the history
* 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.
  • Loading branch information
vstinner committed Aug 25, 2023
1 parent 1dd9510 commit 73d33c1
Showing 1 changed file with 41 additions and 17 deletions.
58 changes: 41 additions & 17 deletions Tools/clinic/clinic.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -2126,8 +2131,8 @@ def print_block(
self,
block: Block,
*,
clinic: Clinic,
core_includes: bool = False,
clinic: Clinic | None = None,
) -> None:
input = block.input
output = block.output
Expand Down Expand Up @@ -2156,18 +2161,22 @@ 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
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)
Expand Down Expand Up @@ -2311,7 +2320,7 @@ def __init__(self, clinic: Clinic) -> None: ...
def parse(self, block: Block) -> None: ...


clinic = None
clinic: Clinic | None = None
class Clinic:

presets_text = """
Expand Down Expand Up @@ -2379,6 +2388,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 = ''

Expand Down Expand Up @@ -2437,6 +2449,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,
Expand Down Expand Up @@ -3066,6 +3084,10 @@ class CConverter(metaclass=CConverterAutoRegister):
# Only set by self_converter.
signature_name: str | None = None

# 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__!
def __init__(self,
# Positional args:
Expand Down Expand Up @@ -3370,6 +3392,11 @@ def parser_name(self) -> str:
else:
return self.name

def add_include(self, name: str, reason: str) -> None:
if self.include is not None:
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'),
Expand Down Expand Up @@ -5989,9 +6016,6 @@ def do_post_block_processing_cleanup(self, lineno: int) -> None:
}


clinic = None


def create_cli() -> argparse.ArgumentParser:
cmdline = argparse.ArgumentParser(
prog="clinic.py",
Expand Down

0 comments on commit 73d33c1

Please sign in to comment.