https://github.com/python/cpython/commit/a2ae84726b8b46e6970ae862244dad1a82cf5d19
commit: a2ae84726b8b46e6970ae862244dad1a82cf5d19
branch: main
author: Victor Stinner <[email protected]>
committer: vstinner <[email protected]>
date: 2024-04-11T12:15:48+02:00
summary:
gh-113317: Add Codegen class to Argument Clinic (#117626)
* Move ifndef_symbols, includes and add_include() from Clinic to
Codegen. Add a 'codegen' (Codegen) attribute to Clinic.
* Remove libclinic.crenderdata module: move code to libclinic.codegen.
* BlockPrinter.print_block(): remove unused 'limited_capi' argument.
Remove also 'core_includes' parameter.
* Add get_includes() methods.
* Make Codegen.ifndef_symbols private.
* Make Codegen.includes private.
* Make CConverter.includes private.
files:
D Tools/clinic/libclinic/crenderdata.py
M Lib/test/test_clinic.py
M Tools/clinic/libclinic/app.py
M Tools/clinic/libclinic/clanguage.py
M Tools/clinic/libclinic/codegen.py
M Tools/clinic/libclinic/converter.py
M Tools/clinic/libclinic/converters.py
M Tools/clinic/libclinic/return_converters.py
diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py
index e3ba3d943216de..e8c638ea610782 100644
--- a/Lib/test/test_clinic.py
+++ b/Lib/test/test_clinic.py
@@ -877,9 +877,8 @@ def _test(self, input, output):
blocks = list(BlockParser(input, language))
writer = BlockPrinter(language)
- c = _make_clinic()
for block in blocks:
- writer.print_block(block, limited_capi=c.limited_capi,
header_includes=c.includes)
+ writer.print_block(block)
output = writer.f.getvalue()
assert output == input, "output != input!\n\noutput " + repr(output) +
"\n\n input " + repr(input)
diff --git a/Tools/clinic/libclinic/app.py b/Tools/clinic/libclinic/app.py
index 47a897712d053e..62e9892eb95a2b 100644
--- a/Tools/clinic/libclinic/app.py
+++ b/Tools/clinic/libclinic/app.py
@@ -9,8 +9,7 @@
from libclinic import fail, warn
from libclinic.function import Class
from libclinic.block_parser import Block, BlockParser
-from libclinic.crenderdata import Include
-from libclinic.codegen import BlockPrinter, Destination
+from libclinic.codegen import BlockPrinter, Destination, Codegen
from libclinic.parser import Parser, PythonParser
from libclinic.dsl_parser import DSLParser
if TYPE_CHECKING:
@@ -102,8 +101,7 @@ def __init__(
self.modules: ModuleDict = {}
self.classes: ClassDict = {}
self.functions: list[Function] = []
- # dict: include name => Include instance
- self.includes: dict[str, Include] = {}
+ self.codegen = Codegen(self.limited_capi)
self.line_prefix = self.line_suffix = ''
@@ -132,7 +130,6 @@ def __init__(
DestBufferList = list[DestBufferType]
self.destination_buffers_stack: DestBufferList = []
- self.ifndef_symbols: set[str] = set()
self.presets: dict[str, dict[Any, Any]] = {}
preset = None
@@ -159,24 +156,6 @@ def __init__(
assert name in self.destination_buffers
preset[name] = buffer
- def add_include(self, name: str, reason: str,
- *, condition: str | None = None) -> None:
- try:
- existing = self.includes[name]
- except KeyError:
- pass
- else:
- if existing.condition and not condition:
- # If the previous include has a condition and the new one is
- # unconditional, override the include.
- pass
- else:
- # Already included, do nothing. Only mention a single reason,
- # no need to list all of them.
- return
-
- self.includes[name] = Include(name, reason, condition)
-
def add_destination(
self,
name: str,
@@ -212,9 +191,7 @@ def parse(self, input: str) -> str:
self.parsers[dsl_name] = parsers[dsl_name](self)
parser = self.parsers[dsl_name]
parser.parse(block)
- printer.print_block(block,
- limited_capi=self.limited_capi,
- header_includes=self.includes)
+ printer.print_block(block)
# these are destinations not buffers
for name, destination in self.destinations.items():
@@ -229,9 +206,7 @@ def parse(self, input: str) -> str:
block.input = "dump " + name + "\n"
warn("Destination buffer " + repr(name) + " not empty at
end of file, emptying.")
printer.write("\n")
- printer.print_block(block,
- limited_capi=self.limited_capi,
- header_includes=self.includes)
+ printer.print_block(block)
continue
if destination.type == 'file':
@@ -255,11 +230,10 @@ def parse(self, input: str) -> str:
pass
block.input = 'preserve\n'
+ includes = self.codegen.get_includes()
+
printer_2 = BlockPrinter(self.language)
- printer_2.print_block(block,
- core_includes=True,
- limited_capi=self.limited_capi,
- header_includes=self.includes)
+ printer_2.print_block(block, header_includes=includes)
libclinic.write_file(destination.filename,
printer_2.f.getvalue())
continue
diff --git a/Tools/clinic/libclinic/clanguage.py
b/Tools/clinic/libclinic/clanguage.py
index ed08d12d8bfb29..5d1a273312dec5 100644
--- a/Tools/clinic/libclinic/clanguage.py
+++ b/Tools/clinic/libclinic/clanguage.py
@@ -11,7 +11,7 @@
unspecified, fail, warn, Sentinels, VersionTuple)
from libclinic.function import (
GETTER, SETTER, METHOD_INIT, METHOD_NEW)
-from libclinic.crenderdata import CRenderData, TemplateDict
+from libclinic.codegen import CRenderData, TemplateDict, Codegen
from libclinic.language import Language
from libclinic.function import (
Module, Class, Function, Parameter,
@@ -26,8 +26,7 @@ def declare_parser(
f: Function,
*,
hasformat: bool = False,
- clinic: Clinic,
- limited_capi: bool,
+ codegen: Codegen,
) -> str:
"""
Generates the code template for a static local PyArg_Parser variable,
@@ -35,6 +34,7 @@ def declare_parser(
kwtuple field is also statically initialized. Otherwise
it is initialized at runtime.
"""
+ limited_capi = codegen.limited_capi
if hasformat:
fname = ''
format_ = '.format = "{format_units}:{name}",'
@@ -80,8 +80,8 @@ def declare_parser(
""" % num_keywords
condition = '#if defined(Py_BUILD_CORE) &&
!defined(Py_BUILD_CORE_MODULE)'
- clinic.add_include('pycore_gc.h', 'PyGC_Head', condition=condition)
- clinic.add_include('pycore_runtime.h', '_Py_ID()', condition=condition)
+ codegen.add_include('pycore_gc.h', 'PyGC_Head', condition=condition)
+ codegen.add_include('pycore_runtime.h', '_Py_ID()',
condition=condition)
declarations += """
static const char * const _keywords[] = {{{keywords_c} NULL}};
@@ -317,14 +317,14 @@ def deprecate_keyword_use(
self,
func: Function,
params: dict[int, Parameter],
- argname_fmt: str | None,
+ argname_fmt: str | None = None,
*,
fastcall: bool,
- limited_capi: bool,
- clinic: Clinic,
+ codegen: Codegen,
) -> str:
assert len(params) > 0
last_param = next(reversed(params.values()))
+ limited_capi = codegen.limited_capi
# Format the deprecation message.
containscheck = ""
@@ -336,11 +336,11 @@ def deprecate_keyword_use(
elif fastcall:
conditions.append(f"nargs < {i+1} &&
PySequence_Contains(kwnames, &_Py_ID({p.name}))")
containscheck = "PySequence_Contains"
- clinic.add_include('pycore_runtime.h', '_Py_ID()')
+ codegen.add_include('pycore_runtime.h', '_Py_ID()')
else:
conditions.append(f"nargs < {i+1} &&
PyDict_Contains(kwargs, &_Py_ID({p.name}))")
containscheck = "PyDict_Contains"
- clinic.add_include('pycore_runtime.h', '_Py_ID()')
+ codegen.add_include('pycore_runtime.h', '_Py_ID()')
else:
conditions = [f"nargs < {i+1}"]
condition = ") || (".join(conditions)
@@ -399,7 +399,7 @@ def deprecate_keyword_use(
def output_templates(
self,
f: Function,
- clinic: Clinic
+ codegen: Codegen,
) -> dict[str, str]:
parameters = list(f.parameters.values())
assert parameters
@@ -412,7 +412,7 @@ def output_templates(
converters = [p.converter for p in parameters]
if f.critical_section:
- clinic.add_include('pycore_critical_section.h',
'Py_BEGIN_CRITICAL_SECTION()')
+ codegen.add_include('pycore_critical_section.h',
'Py_BEGIN_CRITICAL_SECTION()')
has_option_groups = parameters and (parameters[0].group or
parameters[-1].group)
simple_return = (f.return_converter.type == 'PyObject *'
and not f.critical_section)
@@ -517,7 +517,7 @@ def parser_body(
parser_declarations=declarations)
fastcall = not new_or_init
- limited_capi = clinic.limited_capi
+ limited_capi = codegen.limited_capi
if limited_capi and (pseudo_args or
(any(p.is_optional() for p in parameters) and
any(p.is_keyword_only() and not p.is_optional() for p in
parameters)) or
@@ -673,8 +673,8 @@ def parser_body(
""",
indent=4))
else:
- clinic.add_include('pycore_modsupport.h',
- '_PyArg_CheckPositional()')
+ codegen.add_include('pycore_modsupport.h',
+ '_PyArg_CheckPositional()')
parser_code = [libclinic.normalize_snippet(f"""
if (!_PyArg_CheckPositional("{{name}}", {nargs},
{min_pos}, {max_args})) {{{{
goto exit;
@@ -735,8 +735,8 @@ def parser_body(
if limited_capi:
fastcall = False
if fastcall:
- clinic.add_include('pycore_modsupport.h',
- '_PyArg_ParseStack()')
+ codegen.add_include('pycore_modsupport.h',
+ '_PyArg_ParseStack()')
parser_code = [libclinic.normalize_snippet("""
if (!_PyArg_ParseStack(args, nargs,
"{format_units}:{name}",
{parse_arguments})) {{
@@ -773,8 +773,8 @@ def parser_body(
fastcall = False
else:
if vararg == self.NO_VARARG:
- clinic.add_include('pycore_modsupport.h',
- '_PyArg_UnpackKeywords()')
+ codegen.add_include('pycore_modsupport.h',
+ '_PyArg_UnpackKeywords()')
args_declaration = "_PyArg_UnpackKeywords", "%s, %s, %s" %
(
min_pos,
max_pos,
@@ -782,8 +782,8 @@ def parser_body(
)
nargs = "nargs"
else:
- clinic.add_include('pycore_modsupport.h',
- '_PyArg_UnpackKeywordsWithVararg()')
+ codegen.add_include('pycore_modsupport.h',
+ '_PyArg_UnpackKeywordsWithVararg()')
args_declaration = "_PyArg_UnpackKeywordsWithVararg", "%s,
%s, %s, %s" % (
min_pos,
max_pos,
@@ -796,8 +796,7 @@ def parser_body(
flags = "METH_FASTCALL|METH_KEYWORDS"
parser_prototype = self.PARSER_PROTOTYPE_FASTCALL_KEYWORDS
argname_fmt = 'args[%d]'
- declarations = declare_parser(f, clinic=clinic,
-
limited_capi=clinic.limited_capi)
+ declarations = declare_parser(f, codegen=codegen)
declarations += "\nPyObject *argsbuf[%s];" %
len(converters)
if has_optional_kw:
declarations += "\nPy_ssize_t noptargs = %s + (kwnames
? PyTuple_GET_SIZE(kwnames) : 0) - %d;" % (nargs, min_pos + min_kw_only)
@@ -812,8 +811,7 @@ def parser_body(
flags = "METH_VARARGS|METH_KEYWORDS"
parser_prototype = self.PARSER_PROTOTYPE_KEYWORD
argname_fmt = 'fastargs[%d]'
- declarations = declare_parser(f, clinic=clinic,
-
limited_capi=clinic.limited_capi)
+ declarations = declare_parser(f, codegen=codegen)
declarations += "\nPyObject *argsbuf[%s];" %
len(converters)
declarations += "\nPyObject * const *fastargs;"
declarations += "\nPy_ssize_t nargs =
PyTuple_GET_SIZE(args);"
@@ -832,10 +830,10 @@ def parser_body(
if parser_code is not None:
if deprecated_keywords:
- code = self.deprecate_keyword_use(f, deprecated_keywords,
argname_fmt,
- clinic=clinic,
- fastcall=fastcall,
-
limited_capi=limited_capi)
+ code = self.deprecate_keyword_use(f, deprecated_keywords,
+ argname_fmt,
+ codegen=codegen,
+ fastcall=fastcall)
parser_code.append(code)
add_label: str | None = None
@@ -903,9 +901,8 @@ def parser_body(
for parameter in parameters:
parameter.converter.use_converter()
- declarations = declare_parser(f, clinic=clinic,
- hasformat=True,
- limited_capi=limited_capi)
+ declarations = declare_parser(f, codegen=codegen,
+ hasformat=True)
if limited_capi:
# positional-or-keyword arguments
assert not fastcall
@@ -921,8 +918,8 @@ def parser_body(
declarations += "\nPy_ssize_t nargs =
PyTuple_Size(args);"
elif fastcall:
- clinic.add_include('pycore_modsupport.h',
- '_PyArg_ParseStackAndKeywords()')
+ codegen.add_include('pycore_modsupport.h',
+ '_PyArg_ParseStackAndKeywords()')
parser_code = [libclinic.normalize_snippet("""
if (!_PyArg_ParseStackAndKeywords(args, nargs,
kwnames, &_parser{parse_arguments_comma}
{parse_arguments})) {{
@@ -930,8 +927,8 @@ def parser_body(
}}
""", indent=4)]
else:
- clinic.add_include('pycore_modsupport.h',
- '_PyArg_ParseTupleAndKeywordsFast()')
+ codegen.add_include('pycore_modsupport.h',
+ '_PyArg_ParseTupleAndKeywordsFast()')
parser_code = [libclinic.normalize_snippet("""
if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs,
&_parser,
{parse_arguments})) {{
@@ -941,10 +938,9 @@ def parser_body(
if deprecated_positionals or deprecated_keywords:
declarations += "\nPy_ssize_t nargs =
PyTuple_GET_SIZE(args);"
if deprecated_keywords:
- code = self.deprecate_keyword_use(f, deprecated_keywords,
None,
- clinic=clinic,
- fastcall=fastcall,
-
limited_capi=limited_capi)
+ code = self.deprecate_keyword_use(f, deprecated_keywords,
+ codegen=codegen,
+ fastcall=fastcall)
parser_code.append(code)
if deprecated_positionals:
@@ -960,9 +956,9 @@ def parser_body(
# Copy includes from parameters to Clinic after parse_arg() has been
# called above.
for converter in converters:
- for include in converter.includes:
- clinic.add_include(include.filename, include.reason,
- condition=include.condition)
+ for include in converter.get_includes():
+ codegen.add_include(include.filename, include.reason,
+ condition=include.condition)
if new_or_init:
methoddef_define = ''
@@ -984,16 +980,16 @@ def parser_body(
if not parses_keywords:
declarations = '{base_type_ptr}'
- clinic.add_include('pycore_modsupport.h',
- '_PyArg_NoKeywords()')
+ codegen.add_include('pycore_modsupport.h',
+ '_PyArg_NoKeywords()')
fields.insert(0, libclinic.normalize_snippet("""
if ({self_type_check}!_PyArg_NoKeywords("{name}", kwargs))
{{
goto exit;
}}
""", indent=4))
if not parses_positional:
- clinic.add_include('pycore_modsupport.h',
- '_PyArg_NoPositional()')
+ codegen.add_include('pycore_modsupport.h',
+ '_PyArg_NoPositional()')
fields.insert(0, libclinic.normalize_snippet("""
if ({self_type_check}!_PyArg_NoPositional("{name}",
args)) {{
goto exit;
@@ -1030,8 +1026,7 @@ def parser_body(
cpp_if = "#if " + conditional
cpp_endif = "#endif /* " + conditional + " */"
- if methoddef_define and f.full_name not in clinic.ifndef_symbols:
- clinic.ifndef_symbols.add(f.full_name)
+ if methoddef_define and codegen.add_ifndef_symbol(f.full_name):
methoddef_ifndef = self.METHODDEF_PROTOTYPE_IFNDEF
# add ';' to the end of parser_prototype and impl_prototype
@@ -1190,16 +1185,17 @@ def render_function(
clinic: Clinic,
f: Function | None
) -> str:
- if f is None or clinic is None:
+ if f is None:
return ""
+ codegen = clinic.codegen
data = CRenderData()
assert f.parameters, "We should always have a 'self' at this point!"
parameters = f.render_parameters
converters = [p.converter for p in parameters]
- templates = self.output_templates(f, clinic)
+ templates = self.output_templates(f, codegen)
f_self = parameters[0]
selfless = parameters[1:]
@@ -1323,7 +1319,7 @@ def render_function(
if has_option_groups:
self.render_option_group_parsing(f, template_dict,
- limited_capi=clinic.limited_capi)
+ limited_capi=codegen.limited_capi)
# buffers, not destination
for name, destination in clinic.destination_buffers.items():
diff --git a/Tools/clinic/libclinic/codegen.py
b/Tools/clinic/libclinic/codegen.py
index ad08e22e2e1c2c..83f345124a67cb 100644
--- a/Tools/clinic/libclinic/codegen.py
+++ b/Tools/clinic/libclinic/codegen.py
@@ -6,13 +6,92 @@
import libclinic
from libclinic import fail
-from libclinic.crenderdata import Include
from libclinic.language import Language
from libclinic.block_parser import Block
if TYPE_CHECKING:
from libclinic.app import Clinic
+TemplateDict = dict[str, str]
+
+
+class CRenderData:
+ def __init__(self) -> None:
+
+ # The C statements to declare variables.
+ # Should be full lines with \n eol characters.
+ self.declarations: list[str] = []
+
+ # The C statements required to initialize the variables before the
parse call.
+ # Should be full lines with \n eol characters.
+ self.initializers: list[str] = []
+
+ # The C statements needed to dynamically modify the values
+ # parsed by the parse call, before calling the impl.
+ self.modifications: list[str] = []
+
+ # The entries for the "keywords" array for PyArg_ParseTuple.
+ # Should be individual strings representing the names.
+ self.keywords: list[str] = []
+
+ # The "format units" for PyArg_ParseTuple.
+ # Should be individual strings that will get
+ self.format_units: list[str] = []
+
+ # The varargs arguments for PyArg_ParseTuple.
+ self.parse_arguments: list[str] = []
+
+ # The parameter declarations for the impl function.
+ self.impl_parameters: list[str] = []
+
+ # The arguments to the impl function at the time it's called.
+ self.impl_arguments: list[str] = []
+
+ # For return converters: the name of the variable that
+ # should receive the value returned by the impl.
+ self.return_value = "return_value"
+
+ # For return converters: the code to convert the return
+ # value from the parse function. This is also where
+ # you should check the _return_value for errors, and
+ # "goto exit" if there are any.
+ self.return_conversion: list[str] = []
+ self.converter_retval = "_return_value"
+
+ # The C statements required to do some operations
+ # after the end of parsing but before cleaning up.
+ # These operations may be, for example, memory deallocations which
+ # can only be done without any error happening during argument parsing.
+ self.post_parsing: list[str] = []
+
+ # The C statements required to clean up after the impl call.
+ self.cleanup: list[str] = []
+
+ # The C statements to generate critical sections (per-object locking).
+ self.lock: list[str] = []
+ self.unlock: list[str] = []
+
+
[email protected](slots=True, frozen=True)
+class Include:
+ """
+ An include like: #include "pycore_long.h" // _Py_ID()
+ """
+ # Example: "pycore_long.h".
+ filename: str
+
+ # Example: "_Py_ID()".
+ reason: str
+
+ # None means unconditional include.
+ # Example: "#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)".
+ condition: str | None
+
+ def sort_key(self) -> tuple[str, str]:
+ # order: '#if' comes before 'NO_CONDITION'
+ return (self.condition or 'NO_CONDITION', self.filename)
+
+
@dc.dataclass(slots=True)
class BlockPrinter:
language: Language
@@ -25,9 +104,7 @@ def print_block(
self,
block: Block,
*,
- core_includes: bool = False,
- limited_capi: bool,
- header_includes: dict[str, Include],
+ header_includes: list[Include] | None = None,
) -> None:
input = block.input
output = block.output
@@ -56,13 +133,12 @@ def print_block(
write("\n")
output = ''
- if core_includes and header_includes:
+ if header_includes:
# Emit optional "#include" directives for C headers
output += '\n'
current_condition: str | None = None
- includes = sorted(header_includes.values(), key=Include.sort_key)
- for include in includes:
+ for include in header_includes:
if include.condition != current_condition:
if current_condition:
output += '#endif\n'
@@ -188,3 +264,39 @@ def dump(self) -> str:
DestinationDict = dict[str, Destination]
+
+
+class Codegen:
+ def __init__(self, limited_capi: bool) -> None:
+ self.limited_capi = limited_capi
+ self._ifndef_symbols: set[str] = set()
+ # dict: include name => Include instance
+ self._includes: dict[str, Include] = {}
+
+ def add_ifndef_symbol(self, name: str) -> bool:
+ if name in self._ifndef_symbols:
+ return False
+ self._ifndef_symbols.add(name)
+ return True
+
+ def add_include(self, name: str, reason: str,
+ *, condition: str | None = None) -> None:
+ try:
+ existing = self._includes[name]
+ except KeyError:
+ pass
+ else:
+ if existing.condition and not condition:
+ # If the previous include has a condition and the new one is
+ # unconditional, override the include.
+ pass
+ else:
+ # Already included, do nothing. Only mention a single reason,
+ # no need to list all of them.
+ return
+
+ self._includes[name] = Include(name, reason, condition)
+
+ def get_includes(self) -> list[Include]:
+ return sorted(self._includes.values(),
+ key=Include.sort_key)
diff --git a/Tools/clinic/libclinic/converter.py
b/Tools/clinic/libclinic/converter.py
index ac78be3f7958da..86853bb4fba253 100644
--- a/Tools/clinic/libclinic/converter.py
+++ b/Tools/clinic/libclinic/converter.py
@@ -7,7 +7,7 @@
import libclinic
from libclinic import fail
from libclinic import Sentinels, unspecified, unknown
-from libclinic.crenderdata import CRenderData, Include, TemplateDict
+from libclinic.codegen import CRenderData, Include, TemplateDict
from libclinic.function import Function, Parameter
@@ -180,7 +180,7 @@ def __init__(self,
self.name = libclinic.ensure_legal_c_identifier(name)
self.py_name = py_name
self.unused = unused
- self.includes: list[Include] = []
+ self._includes: list[Include] = []
if default is not unspecified:
if (self.default_type
@@ -513,7 +513,10 @@ def parser_name(self) -> str:
def add_include(self, name: str, reason: str,
*, condition: str | None = None) -> None:
include = Include(name, reason, condition)
- self.includes.append(include)
+ self._includes.append(include)
+
+ def get_includes(self) -> list[Include]:
+ return self._includes
ConverterType = Callable[..., CConverter]
diff --git a/Tools/clinic/libclinic/converters.py
b/Tools/clinic/libclinic/converters.py
index 7fc16f17450aaa..0778961f5b5875 100644
--- a/Tools/clinic/libclinic/converters.py
+++ b/Tools/clinic/libclinic/converters.py
@@ -9,7 +9,7 @@
Function, Parameter,
CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW,
GETTER, SETTER)
-from libclinic.crenderdata import CRenderData, TemplateDict
+from libclinic.codegen import CRenderData, TemplateDict
from libclinic.converter import (
CConverter, legacy_converters, add_legacy_c_converter)
diff --git a/Tools/clinic/libclinic/crenderdata.py
b/Tools/clinic/libclinic/crenderdata.py
deleted file mode 100644
index 58976b8185ebae..00000000000000
--- a/Tools/clinic/libclinic/crenderdata.py
+++ /dev/null
@@ -1,81 +0,0 @@
-import dataclasses as dc
-
-
-TemplateDict = dict[str, str]
-
-
-class CRenderData:
- def __init__(self) -> None:
-
- # The C statements to declare variables.
- # Should be full lines with \n eol characters.
- self.declarations: list[str] = []
-
- # The C statements required to initialize the variables before the
parse call.
- # Should be full lines with \n eol characters.
- self.initializers: list[str] = []
-
- # The C statements needed to dynamically modify the values
- # parsed by the parse call, before calling the impl.
- self.modifications: list[str] = []
-
- # The entries for the "keywords" array for PyArg_ParseTuple.
- # Should be individual strings representing the names.
- self.keywords: list[str] = []
-
- # The "format units" for PyArg_ParseTuple.
- # Should be individual strings that will get
- self.format_units: list[str] = []
-
- # The varargs arguments for PyArg_ParseTuple.
- self.parse_arguments: list[str] = []
-
- # The parameter declarations for the impl function.
- self.impl_parameters: list[str] = []
-
- # The arguments to the impl function at the time it's called.
- self.impl_arguments: list[str] = []
-
- # For return converters: the name of the variable that
- # should receive the value returned by the impl.
- self.return_value = "return_value"
-
- # For return converters: the code to convert the return
- # value from the parse function. This is also where
- # you should check the _return_value for errors, and
- # "goto exit" if there are any.
- self.return_conversion: list[str] = []
- self.converter_retval = "_return_value"
-
- # The C statements required to do some operations
- # after the end of parsing but before cleaning up.
- # These operations may be, for example, memory deallocations which
- # can only be done without any error happening during argument parsing.
- self.post_parsing: list[str] = []
-
- # The C statements required to clean up after the impl call.
- self.cleanup: list[str] = []
-
- # The C statements to generate critical sections (per-object locking).
- self.lock: list[str] = []
- self.unlock: list[str] = []
-
-
[email protected](slots=True, frozen=True)
-class Include:
- """
- An include like: #include "pycore_long.h" // _Py_ID()
- """
- # Example: "pycore_long.h".
- filename: str
-
- # Example: "_Py_ID()".
- reason: str
-
- # None means unconditional include.
- # Example: "#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)".
- condition: str | None
-
- def sort_key(self) -> tuple[str, str]:
- # order: '#if' comes before 'NO_CONDITION'
- return (self.condition or 'NO_CONDITION', self.filename)
diff --git a/Tools/clinic/libclinic/return_converters.py
b/Tools/clinic/libclinic/return_converters.py
index 7bdd257cfa3443..b41e053bae5f3a 100644
--- a/Tools/clinic/libclinic/return_converters.py
+++ b/Tools/clinic/libclinic/return_converters.py
@@ -1,6 +1,6 @@
import sys
from collections.abc import Callable
-from libclinic.crenderdata import CRenderData
+from libclinic.codegen import CRenderData
from libclinic.function import Function
from typing import Any
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]