From 391cf7529bd4dfa38e1c50a5faca755e6fcfb4f4 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 4 Mar 2024 13:51:28 +0100 Subject: [PATCH] gh-114258: Argument Clinic: refactor getset implementation (#116170) * Move param guard to param state machine * Override return converter during parsing * Don't use a custom type slot return converter; instead special case type slot functions during generation. --- Lib/test/clinic.test.c | 13 ++++++------- Lib/test/test_clinic.py | 5 ++--- Tools/clinic/clinic.py | 35 ++++++++++------------------------- 3 files changed, 18 insertions(+), 35 deletions(-) diff --git a/Lib/test/clinic.test.c b/Lib/test/clinic.test.c index e4dbb70d44ced99..58ffc0ad4ab88b3 100644 --- a/Lib/test/clinic.test.c +++ b/Lib/test/clinic.test.c @@ -5004,12 +5004,16 @@ Test_property_set_impl(TestObj *self, PyObject *value); static int Test_property_set(TestObj *self, PyObject *value, void *Py_UNUSED(context)) { - return Test_property_set_impl(self, value); + int return_value; + + return_value = Test_property_set_impl(self, value); + + return return_value; } static int Test_property_set_impl(TestObj *self, PyObject *value) -/*[clinic end generated code: output=9797cd03c5204ddb input=3bc3f46a23c83a88]*/ +/*[clinic end generated code: output=d51023f17c4ac3a1 input=3bc3f46a23c83a88]*/ /*[clinic input] output push @@ -5327,11 +5331,6 @@ Test__pyarg_parsestackandkeywords_impl(TestObj *self, PyTypeObject *cls, /*[clinic end generated code: output=4fda8a7f2547137c input=fc72ef4b4cfafabc]*/ -static long -Test___init___impl(TestObj *self) -/*[clinic end generated code: output=daf6ee12c4e443fb input=311af0dc7f17e8e9]*/ - - /*[clinic input] fn_with_default_binop_expr arg: object(c_default='CONST_A + CONST_B') = a+b diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index 0a16f98a5a1f996..02a293e04b21822 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -2175,7 +2175,7 @@ class Foo "" "" obj: int / """ - expected_error = f"{annotation} method cannot define parameters" + expected_error = f"{annotation} methods cannot define parameters" self.expect_failure(block, expected_error) def test_setter_docstring(self): @@ -2655,7 +2655,6 @@ def test_cli_converters(self): bool() double() float() - init() int() long() Py_ssize_t() @@ -3945,7 +3944,7 @@ def test_Function_and_Parameter_reprs(self): cls=None, c_basename=None, full_name='foofoo', - return_converter=clinic.init_return_converter(), + return_converter=clinic.int_return_converter(), kind=clinic.FunctionKind.METHOD_INIT, coexist=False ) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 80da035131b8177..0a8546247cc3265 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -859,9 +859,6 @@ def parser_body( limited_capi = False parsearg: str | None - if f.kind in {GETTER, SETTER} and parameters: - fail(f"@{f.kind.name.lower()} method cannot define parameters") - if not parameters: parser_code: list[str] | None if f.kind is GETTER: @@ -1615,12 +1612,9 @@ def render_function( for converter in converters: converter.set_template_dict(template_dict) - f.return_converter.render(f, data) - if f.kind is SETTER: - # All setters return an int. - template_dict['impl_return_type'] = 'int' - else: - template_dict['impl_return_type'] = f.return_converter.type + if f.kind not in {SETTER, METHOD_INIT}: + f.return_converter.render(f, data) + template_dict['impl_return_type'] = f.return_converter.type template_dict['declarations'] = libclinic.format_escape("\n".join(data.declarations)) template_dict['initializers'] = "\n\n".join(data.initializers) @@ -4565,20 +4559,6 @@ class int_return_converter(long_return_converter): cast = '(long)' -class init_return_converter(long_return_converter): - """ - Special return converter for __init__ functions. - """ - type = 'int' - cast = '(long)' - - def render( - self, - function: Function, - data: CRenderData - ) -> None: ... - - class unsigned_long_return_converter(long_return_converter): type = 'unsigned long' conversion_fn = 'PyLong_FromUnsignedLong' @@ -5111,8 +5091,8 @@ def resolve_return_converter( except ValueError: fail(f"Badly formed annotation for {full_name!r}: {forced_converter!r}") - if self.kind is METHOD_INIT: - return init_return_converter() + if self.kind in {METHOD_INIT, SETTER}: + return int_return_converter() return CReturnConverter() def parse_cloned_function(self, names: FunctionNames, existing: str) -> None: @@ -5294,6 +5274,11 @@ def state_parameters_start(self, line: str) -> None: if not self.indent.infer(line): return self.next(self.state_function_docstring, line) + assert self.function is not None + if self.function.kind in {GETTER, SETTER}: + getset = self.function.kind.name.lower() + fail(f"@{getset} methods cannot define parameters") + self.parameter_continuation = '' return self.next(self.state_parameter, line)