Skip to content

Commit

Permalink
[3.9] pythongh-91583: AC: Fix regression for functions with defining_…
Browse files Browse the repository at this point in the history
…class (pythonGH-91739)

Argument Clinic now generates the same efficient code as before
adding the defining_class parameter..
(cherry picked from commit a055dac)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
  • Loading branch information
serhiy-storchaka committed Apr 30, 2022
1 parent 3d0a5f7 commit 01ca7b2
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 57 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix regression in the code generated by Argument Clinic for functions with
the ``defining_class`` parameter.
66 changes: 40 additions & 26 deletions Modules/clinic/_testmultiphase.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

56 changes: 42 additions & 14 deletions Modules/clinic/posixmodule.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

53 changes: 36 additions & 17 deletions Tools/clinic/clinic.py
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,10 @@ def output_templates(self, f):
assert parameters
assert isinstance(parameters[0].converter, self_converter)
del parameters[0]
requires_defining_class = False
if parameters and isinstance(parameters[0].converter, defining_class_converter):
requires_defining_class = True
del parameters[0]
converters = [p.converter for p in parameters]

has_option_groups = parameters and (parameters[0].group or parameters[-1].group)
Expand All @@ -657,10 +661,6 @@ def output_templates(self, f):
if not p.is_optional():
min_pos = i

requires_defining_class = any(
isinstance(p.converter, defining_class_converter)
for p in parameters)

meth_o = (len(parameters) == 1 and
parameters[0].is_positional_only() and
not converters[0].is_optional() and
Expand Down Expand Up @@ -763,24 +763,40 @@ def parser_body(prototype, *fields, declarations=''):
return linear_format(output(), parser_declarations=declarations)

if not parameters:
# no parameters, METH_NOARGS
if not requires_defining_class:
# no parameters, METH_NOARGS
flags = "METH_NOARGS"

flags = "METH_NOARGS"
parser_prototype = normalize_snippet("""
static PyObject *
{c_basename}({self_type}{self_name}, PyObject *Py_UNUSED(ignored))
""")
parser_code = []

parser_prototype = normalize_snippet("""
static PyObject *
{c_basename}({self_type}{self_name}, PyObject *Py_UNUSED(ignored))
""")
parser_definition = parser_prototype
else:
assert not new_or_init

if default_return_converter:
parser_definition = parser_prototype + '\n' + normalize_snippet("""
{{
return {c_basename}_impl({impl_arguments});
flags = "METH_METHOD|METH_FASTCALL|METH_KEYWORDS"

parser_prototype = parser_prototype_def_class
return_error = ('return NULL;' if default_return_converter
else 'goto exit;')
parser_code = [normalize_snippet("""
if (nargs) {{
PyErr_SetString(PyExc_TypeError, "{name}() takes no arguments");
%s
}}
""")
""" % return_error, indent=4)]

if default_return_converter:
parser_definition = '\n'.join([
parser_prototype,
'{{',
*parser_code,
' return {c_basename}_impl({impl_arguments});',
'}}'])
else:
parser_definition = parser_body(parser_prototype)
parser_definition = parser_body(parser_prototype, *parser_code)

elif meth_o:
flags = "METH_O"
Expand Down Expand Up @@ -939,6 +955,9 @@ def parser_body(prototype, *fields, declarations=''):

add_label = None
for i, p in enumerate(parameters):
if isinstance(p.converter, defining_class_converter):
raise ValueError("defining_class should be the first "
"parameter (after self)")
displayname = p.get_displayname(i+1)
parsearg = p.converter.parse_arg(argname_fmt % i, displayname)
if parsearg is None:
Expand Down

0 comments on commit 01ca7b2

Please sign in to comment.