From 488a1272bdd00d4a6bc7985e342e08d934f52e16 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Sun, 10 Dec 2023 16:05:31 +0900 Subject: [PATCH 01/18] gh-112205: Support `@setter` annotation from AC --- Lib/test/clinic.test.c | 34 +++++++++++++++++-- Modules/_io/bufferedio.c | 18 +++++----- Modules/_io/clinic/bufferedio.c.h | 26 ++++++++++---- Modules/_io/clinic/stringio.c.h | 26 ++++++++++---- Modules/_io/clinic/textio.c.h | 46 ++++++++++++++++++++++++- Modules/_io/stringio.c | 6 ++-- Modules/_io/textio.c | 45 +++++++++++-------------- Tools/clinic/clinic.py | 56 +++++++++++++++++++++++++++---- 8 files changed, 194 insertions(+), 63 deletions(-) diff --git a/Lib/test/clinic.test.c b/Lib/test/clinic.test.c index ee4a4228fd28be..173ed8c9fd83fc 100644 --- a/Lib/test/clinic.test.c +++ b/Lib/test/clinic.test.c @@ -4956,8 +4956,12 @@ Test_meth_coexist_impl(TestObj *self) Test.property [clinic start generated code]*/ -#define TEST_PROPERTY_GETTERDEF \ - {"property", (getter)Test_property_get, NULL, NULL}, +#if defined(TEST_PROPERTY_GETSETTERDEF) +# undef TEST_PROPERTY_GETSETTERDEF +# define TEST_PROPERTY_GETSETTERDEF {"property", (getter)Test_property_get, (setter)Test_property_set, NULL}, +#else +# define TEST_PROPERTY_GETSETTERDEF {"property", (getter)Test_property_get, NULL, NULL}, +#endif static PyObject * Test_property_get_impl(TestObj *self); @@ -4970,8 +4974,32 @@ Test_property_get(TestObj *self, void *Py_UNUSED(context)) static PyObject * Test_property_get_impl(TestObj *self) -/*[clinic end generated code: output=892b6fb351ff85fd input=2d92b3449fbc7d2b]*/ +/*[clinic end generated code: output=606a5f21c27ff5dd input=2d92b3449fbc7d2b]*/ + +/*[clinic input] +@setter +Test.property +[clinic start generated code]*/ + +#if defined(TEST_PROPERTY_GETSETTERDEF) +# undef TEST_PROPERTY_GETSETTERDEF +# define TEST_PROPERTY_GETSETTERDEF {"property", (getter)Test_property_get, (setter)Test_property_set, NULL}, +#else +# define TEST_PROPERTY_GETSETTERDEF {"property", NULL, (setter)Test_property_set, NULL}, +#endif + +static PyObject * +Test_property_set_impl(TestObj *self, PyObject *value); + +static PyObject * +Test_property_set(TestObj *self, PyObject *value, void *Py_UNUSED(context)) +{ + return Test_property_set_impl(self, value); +} +static PyObject * +Test_property_set_impl(TestObj *self, PyObject *value) +/*[clinic end generated code: output=2ba2d4de6020e191 input=3bc3f46a23c83a88]*/ /*[clinic input] output push diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 679626863c385c..b7a6252b96ee69 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -2526,9 +2526,9 @@ static PyMemberDef bufferedreader_members[] = { }; static PyGetSetDef bufferedreader_getset[] = { - _IO__BUFFERED_CLOSED_GETTERDEF - _IO__BUFFERED_NAME_GETTERDEF - _IO__BUFFERED_MODE_GETTERDEF + _IO__BUFFERED_CLOSED_GETSETTERDEF + _IO__BUFFERED_NAME_GETSETTERDEF + _IO__BUFFERED_MODE_GETSETTERDEF {NULL} }; @@ -2586,9 +2586,9 @@ static PyMemberDef bufferedwriter_members[] = { }; static PyGetSetDef bufferedwriter_getset[] = { - _IO__BUFFERED_CLOSED_GETTERDEF - _IO__BUFFERED_NAME_GETTERDEF - _IO__BUFFERED_MODE_GETTERDEF + _IO__BUFFERED_CLOSED_GETSETTERDEF + _IO__BUFFERED_NAME_GETSETTERDEF + _IO__BUFFERED_MODE_GETSETTERDEF {NULL} }; @@ -2704,9 +2704,9 @@ static PyMemberDef bufferedrandom_members[] = { }; static PyGetSetDef bufferedrandom_getset[] = { - _IO__BUFFERED_CLOSED_GETTERDEF - _IO__BUFFERED_NAME_GETTERDEF - _IO__BUFFERED_MODE_GETTERDEF + _IO__BUFFERED_CLOSED_GETSETTERDEF + _IO__BUFFERED_NAME_GETSETTERDEF + _IO__BUFFERED_MODE_GETSETTERDEF {NULL} }; diff --git a/Modules/_io/clinic/bufferedio.c.h b/Modules/_io/clinic/bufferedio.c.h index 69d28ad00c2ad5..b85c56287acacb 100644 --- a/Modules/_io/clinic/bufferedio.c.h +++ b/Modules/_io/clinic/bufferedio.c.h @@ -327,8 +327,12 @@ _io__Buffered_simple_flush(buffered *self, PyObject *Py_UNUSED(ignored)) return return_value; } -#define _IO__BUFFERED_CLOSED_GETTERDEF \ - {"closed", (getter)_io__Buffered_closed_get, NULL, NULL}, +#if defined(_IO__BUFFERED_CLOSED_GETSETTERDEF) +# undef _IO__BUFFERED_CLOSED_GETSETTERDEF +# define _IO__BUFFERED_CLOSED_GETSETTERDEF {"closed", (getter)_io__Buffered_closed_get, (setter)_io__Buffered_closed_set, NULL}, +#else +# define _IO__BUFFERED_CLOSED_GETSETTERDEF {"closed", (getter)_io__Buffered_closed_get, NULL, NULL}, +#endif static PyObject * _io__Buffered_closed_get_impl(buffered *self); @@ -460,8 +464,12 @@ _io__Buffered_writable(buffered *self, PyObject *Py_UNUSED(ignored)) return return_value; } -#define _IO__BUFFERED_NAME_GETTERDEF \ - {"name", (getter)_io__Buffered_name_get, NULL, NULL}, +#if defined(_IO__BUFFERED_NAME_GETSETTERDEF) +# undef _IO__BUFFERED_NAME_GETSETTERDEF +# define _IO__BUFFERED_NAME_GETSETTERDEF {"name", (getter)_io__Buffered_name_get, (setter)_io__Buffered_name_set, NULL}, +#else +# define _IO__BUFFERED_NAME_GETSETTERDEF {"name", (getter)_io__Buffered_name_get, NULL, NULL}, +#endif static PyObject * _io__Buffered_name_get_impl(buffered *self); @@ -478,8 +486,12 @@ _io__Buffered_name_get(buffered *self, void *Py_UNUSED(context)) return return_value; } -#define _IO__BUFFERED_MODE_GETTERDEF \ - {"mode", (getter)_io__Buffered_mode_get, NULL, NULL}, +#if defined(_IO__BUFFERED_MODE_GETSETTERDEF) +# undef _IO__BUFFERED_MODE_GETSETTERDEF +# define _IO__BUFFERED_MODE_GETSETTERDEF {"mode", (getter)_io__Buffered_mode_get, (setter)_io__Buffered_mode_set, NULL}, +#else +# define _IO__BUFFERED_MODE_GETSETTERDEF {"mode", (getter)_io__Buffered_mode_get, NULL, NULL}, +#endif static PyObject * _io__Buffered_mode_get_impl(buffered *self); @@ -1218,4 +1230,4 @@ _io_BufferedRandom___init__(PyObject *self, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=f21ed03255032b43 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=1513f2e86f8b8995 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/stringio.c.h b/Modules/_io/clinic/stringio.c.h index ed505ae67589a8..78968a376804e8 100644 --- a/Modules/_io/clinic/stringio.c.h +++ b/Modules/_io/clinic/stringio.c.h @@ -475,8 +475,12 @@ _io_StringIO___setstate__(stringio *self, PyObject *state) return return_value; } -#define _IO_STRINGIO_CLOSED_GETTERDEF \ - {"closed", (getter)_io_StringIO_closed_get, NULL, NULL}, +#if defined(_IO_STRINGIO_CLOSED_GETSETTERDEF) +# undef _IO_STRINGIO_CLOSED_GETSETTERDEF +# define _IO_STRINGIO_CLOSED_GETSETTERDEF {"closed", (getter)_io_StringIO_closed_get, (setter)_io_StringIO_closed_set, NULL}, +#else +# define _IO_STRINGIO_CLOSED_GETSETTERDEF {"closed", (getter)_io_StringIO_closed_get, NULL, NULL}, +#endif static PyObject * _io_StringIO_closed_get_impl(stringio *self); @@ -493,8 +497,12 @@ _io_StringIO_closed_get(stringio *self, void *Py_UNUSED(context)) return return_value; } -#define _IO_STRINGIO_LINE_BUFFERING_GETTERDEF \ - {"line_buffering", (getter)_io_StringIO_line_buffering_get, NULL, NULL}, +#if defined(_IO_STRINGIO_LINE_BUFFERING_GETSETTERDEF) +# undef _IO_STRINGIO_LINE_BUFFERING_GETSETTERDEF +# define _IO_STRINGIO_LINE_BUFFERING_GETSETTERDEF {"line_buffering", (getter)_io_StringIO_line_buffering_get, (setter)_io_StringIO_line_buffering_set, NULL}, +#else +# define _IO_STRINGIO_LINE_BUFFERING_GETSETTERDEF {"line_buffering", (getter)_io_StringIO_line_buffering_get, NULL, NULL}, +#endif static PyObject * _io_StringIO_line_buffering_get_impl(stringio *self); @@ -511,8 +519,12 @@ _io_StringIO_line_buffering_get(stringio *self, void *Py_UNUSED(context)) return return_value; } -#define _IO_STRINGIO_NEWLINES_GETTERDEF \ - {"newlines", (getter)_io_StringIO_newlines_get, NULL, NULL}, +#if defined(_IO_STRINGIO_NEWLINES_GETSETTERDEF) +# undef _IO_STRINGIO_NEWLINES_GETSETTERDEF +# define _IO_STRINGIO_NEWLINES_GETSETTERDEF {"newlines", (getter)_io_StringIO_newlines_get, (setter)_io_StringIO_newlines_set, NULL}, +#else +# define _IO_STRINGIO_NEWLINES_GETSETTERDEF {"newlines", (getter)_io_StringIO_newlines_get, NULL, NULL}, +#endif static PyObject * _io_StringIO_newlines_get_impl(stringio *self); @@ -528,4 +540,4 @@ _io_StringIO_newlines_get(stringio *self, void *Py_UNUSED(context)) return return_value; } -/*[clinic end generated code: output=3a92e8b6c322f61b input=a9049054013a1b77]*/ +/*[clinic end generated code: output=db35b529122b2cfc input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/textio.c.h b/Modules/_io/clinic/textio.c.h index 675e0ed2eab75e..528063d48e9ec5 100644 --- a/Modules/_io/clinic/textio.c.h +++ b/Modules/_io/clinic/textio.c.h @@ -1047,4 +1047,48 @@ _io_TextIOWrapper_close(textio *self, PyObject *Py_UNUSED(ignored)) return return_value; } -/*[clinic end generated code: output=8781a91be6d99e2c input=a9049054013a1b77]*/ + +#if defined(_IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETTERDEF) +# undef _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETTERDEF +# define _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETTERDEF {"_CHUNK_SIZE", (getter)_io_TextIOWrapper__CHUNK_SIZE_get, (setter)_io_TextIOWrapper__CHUNK_SIZE_set, NULL}, +#else +# define _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETTERDEF {"_CHUNK_SIZE", (getter)_io_TextIOWrapper__CHUNK_SIZE_get, NULL, NULL}, +#endif + +static PyObject * +_io_TextIOWrapper__CHUNK_SIZE_get_impl(textio *self); + +static PyObject * +_io_TextIOWrapper__CHUNK_SIZE_get(textio *self, void *Py_UNUSED(context)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _io_TextIOWrapper__CHUNK_SIZE_get_impl(self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +#if defined(_IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETTERDEF) +# undef _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETTERDEF +# define _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETTERDEF {"_CHUNK_SIZE", (getter)_io_TextIOWrapper__CHUNK_SIZE_get, (setter)_io_TextIOWrapper__CHUNK_SIZE_set, NULL}, +#else +# define _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETTERDEF {"_CHUNK_SIZE", NULL, (setter)_io_TextIOWrapper__CHUNK_SIZE_set, NULL}, +#endif + +static PyObject * +_io_TextIOWrapper__CHUNK_SIZE_set_impl(textio *self, PyObject *value); + +static PyObject * +_io_TextIOWrapper__CHUNK_SIZE_set(textio *self, PyObject *value, void *Py_UNUSED(context)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _io_TextIOWrapper__CHUNK_SIZE_set_impl(self, value); + Py_END_CRITICAL_SECTION(); + + return return_value; +} +/*[clinic end generated code: output=29b1d97275d1a575 input=a9049054013a1b77]*/ diff --git a/Modules/_io/stringio.c b/Modules/_io/stringio.c index 74dcee23730306..f78e78af7f7ee7 100644 --- a/Modules/_io/stringio.c +++ b/Modules/_io/stringio.c @@ -1037,15 +1037,15 @@ static struct PyMethodDef stringio_methods[] = { }; static PyGetSetDef stringio_getset[] = { - _IO_STRINGIO_CLOSED_GETTERDEF - _IO_STRINGIO_NEWLINES_GETTERDEF + _IO_STRINGIO_CLOSED_GETSETTERDEF + _IO_STRINGIO_NEWLINES_GETSETTERDEF /* (following comments straight off of the original Python wrapper:) XXX Cruft to support the TextIOWrapper API. This would only be meaningful if StringIO supported the buffer attribute. Hopefully, a better solution, than adding these pseudo-attributes, will be found. */ - _IO_STRINGIO_LINE_BUFFERING_GETTERDEF + _IO_STRINGIO_LINE_BUFFERING_GETSETTERDEF {NULL} }; diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index 545f467b7f0257..fd2396f0f5d5ad 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -3238,33 +3238,37 @@ textiowrapper_errors_get(textio *self, void *context) return result; } +/*[clinic input] +@critical_section +@getter +_io.TextIOWrapper._CHUNK_SIZE +[clinic start generated code]*/ + static PyObject * -textiowrapper_chunk_size_get_impl(textio *self, void *context) +_io_TextIOWrapper__CHUNK_SIZE_get_impl(textio *self) +/*[clinic end generated code: output=039925cd2df375bc input=e9715b0e06ff0fa6]*/ { CHECK_ATTACHED(self); return PyLong_FromSsize_t(self->chunk_size); } -static PyObject * -textiowrapper_chunk_size_get(textio *self, void *context) -{ - PyObject *result = NULL; - Py_BEGIN_CRITICAL_SECTION(self); - result = textiowrapper_chunk_size_get_impl(self, context); - Py_END_CRITICAL_SECTION(); - return result; -} +/*[clinic input] +@critical_section +@setter +_io.TextIOWrapper._CHUNK_SIZE +[clinic start generated code]*/ -static int -textiowrapper_chunk_size_set_impl(textio *self, PyObject *arg, void *context) +static PyObject * +_io_TextIOWrapper__CHUNK_SIZE_set_impl(textio *self, PyObject *value) +/*[clinic end generated code: output=0d4fc49ae6b8eb87 input=32fc99861db02a0a]*/ { Py_ssize_t n; CHECK_ATTACHED_INT(self); - if (arg == NULL) { + if (value == NULL) { PyErr_SetString(PyExc_AttributeError, "cannot delete attribute"); return -1; } - n = PyNumber_AsSsize_t(arg, PyExc_ValueError); + n = PyNumber_AsSsize_t(value, PyExc_ValueError); if (n == -1 && PyErr_Occurred()) return -1; if (n <= 0) { @@ -3276,16 +3280,6 @@ textiowrapper_chunk_size_set_impl(textio *self, PyObject *arg, void *context) return 0; } -static int -textiowrapper_chunk_size_set(textio *self, PyObject *arg, void *context) -{ - int result = 0; - Py_BEGIN_CRITICAL_SECTION(self); - result = textiowrapper_chunk_size_set_impl(self, arg, context); - Py_END_CRITICAL_SECTION(); - return result; -} - static PyMethodDef incrementalnewlinedecoder_methods[] = { _IO_INCREMENTALNEWLINEDECODER_DECODE_METHODDEF _IO_INCREMENTALNEWLINEDECODER_GETSTATE_METHODDEF @@ -3361,8 +3355,7 @@ static PyGetSetDef textiowrapper_getset[] = { */ {"newlines", (getter)textiowrapper_newlines_get, NULL, NULL}, {"errors", (getter)textiowrapper_errors_get, NULL, NULL}, - {"_CHUNK_SIZE", (getter)textiowrapper_chunk_size_get, - (setter)textiowrapper_chunk_size_set, NULL}, + _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETTERDEF {NULL} }; diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 6c76f66a81abd4..dcb0efd6714682 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -850,6 +850,10 @@ class CLanguage(Language): static PyObject * {c_basename}({self_type}{self_name}, void *Py_UNUSED(context)) """) + PARSER_PROTOTYPE_SETTER: Final[str] = normalize_snippet(""" + static PyObject * + {c_basename}({self_type}{self_name}, PyObject *value, void *Py_UNUSED(context)) + """) METH_O_PROTOTYPE: Final[str] = normalize_snippet(""" static PyObject * {c_basename}({impl_parameters}) @@ -870,8 +874,20 @@ class CLanguage(Language): {{"{name}", {methoddef_cast}{c_basename}{methoddef_cast_end}, {methoddef_flags}, {c_basename}__doc__}}, """) GETTERDEF_PROTOTYPE_DEFINE: Final[str] = normalize_snippet(r""" - #define {getter_name} \ - {{"{name}", (getter){c_basename}, NULL, NULL}}, + #if defined({getsetter_name}_GETSETTERDEF) + # undef {getsetter_name}_GETSETTERDEF + # define {getsetter_name}_GETSETTERDEF {{"{name}", (getter){getset_basename}_get, (setter){getset_basename}_set, NULL}}, + #else + # define {getsetter_name}_GETSETTERDEF {{"{name}", (getter){getset_basename}_get, NULL, NULL}}, + #endif + """) + SETTERDEF_PROTOTYPE_DEFINE: Final[str] = normalize_snippet(r""" + #if defined({getsetter_name}_GETSETTERDEF) + # undef {getsetter_name}_GETSETTERDEF + # define {getsetter_name}_GETSETTERDEF {{"{name}", (getter){getset_basename}_get, (setter){getset_basename}_set, NULL}}, + #else + # define {getsetter_name}_GETSETTERDEF {{"{name}", NULL, (setter){getset_basename}_set, NULL}}, + #endif """) METHODDEF_PROTOTYPE_IFNDEF: Final[str] = normalize_snippet(""" #ifndef {methoddef_name} @@ -1172,6 +1188,9 @@ def output_templates( elif f.kind is GETTER: methoddef_define = self.GETTERDEF_PROTOTYPE_DEFINE docstring_prototype = docstring_definition = '' + elif f.kind is SETTER: + methoddef_define = self.SETTERDEF_PROTOTYPE_DEFINE + docstring_prototype = docstring_prototype = docstring_definition = '' else: docstring_prototype = self.DOCSTRING_PROTOTYPE_VAR docstring_definition = self.DOCSTRING_PROTOTYPE_STRVAR @@ -1226,12 +1245,19 @@ def parser_body( limited_capi = False parsearg: str | None + if f.kind in {GETTER, SETTER} and len(parameters) > 0: + raise RuntimeError("@getter, @setter should not define paramters") + if not parameters: parser_code: list[str] | None if f.kind is GETTER: flags = "" # This should end up unused parser_prototype = self.PARSER_PROTOTYPE_GETTER parser_code = [] + elif f.kind is SETTER: + flags = "" + parser_prototype = self.PARSER_PROTOTYPE_SETTER + parser_code = [] elif not requires_defining_class: # no parameters, METH_NOARGS flags = "METH_NOARGS" @@ -1944,9 +1970,16 @@ def render_function( full_name = f.full_name template_dict = {'full_name': full_name} template_dict['name'] = f.displayname - if f.kind is GETTER: - template_dict['getter_name'] = f.c_basename.upper() + "_GETTERDEF" - template_dict['c_basename'] = f.c_basename + "_get" + if f.kind in (GETTER, SETTER): + template_dict['getsetter_name'] = f.c_basename.upper() + template_dict['getset_basename'] = f.c_basename + if f.kind is GETTER: + template_dict['c_basename'] = f.c_basename + "_get" + elif f.kind is SETTER: + template_dict['c_basename'] = f.c_basename + "_set" + # TODO: Improve handling pararms better way. + data.impl_parameters.append("PyObject *value") + data.impl_arguments.append("value") else: template_dict['methoddef_name'] = f.c_basename.upper() + "_METHODDEF" template_dict['c_basename'] = f.c_basename @@ -2954,6 +2987,7 @@ class FunctionKind(enum.Enum): METHOD_INIT = enum.auto() METHOD_NEW = enum.auto() GETTER = enum.auto() + SETTER = enum.auto() @functools.cached_property def new_or_init(self) -> bool: @@ -2970,6 +3004,7 @@ def __repr__(self) -> str: METHOD_INIT: Final = FunctionKind.METHOD_INIT METHOD_NEW: Final = FunctionKind.METHOD_NEW GETTER: Final = FunctionKind.GETTER +SETTER: Final = FunctionKind.SETTER ParamDict = dict[str, "Parameter"] ReturnConverterType = Callable[..., "CReturnConverter"] @@ -3056,7 +3091,7 @@ def methoddef_flags(self) -> str | None: case FunctionKind.STATIC_METHOD: flags.append('METH_STATIC') case _ as kind: - acceptable_kinds = {FunctionKind.CALLABLE, FunctionKind.GETTER} + acceptable_kinds = {FunctionKind.CALLABLE, FunctionKind.GETTER, FunctionKind.SETTER} assert kind in acceptable_kinds, f"unknown kind: {kind!r}" if self.coexist: flags.append('METH_COEXIST') @@ -4702,7 +4737,7 @@ def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> st def correct_name_for_self( f: Function ) -> tuple[str, str]: - if f.kind in {CALLABLE, METHOD_INIT, GETTER}: + if f.kind in {CALLABLE, METHOD_INIT, GETTER, SETTER}: if f.cls: return "PyObject *", "self" return "PyObject *", "module" @@ -5335,8 +5370,15 @@ def at_critical_section(self, *args: str) -> None: self.critical_section = True def at_getter(self) -> None: + if self.kind in (GETTER, SETTER): + fail("@getter and @setter can not be declared at once") self.kind = GETTER + def at_setter(self) -> None: + if self.kind in (GETTER, SETTER): + fail("@getter and @setter can not be declared at once") + self.kind = SETTER + def at_staticmethod(self) -> None: if self.kind is not CALLABLE: fail("Can't set @staticmethod, function is not a normal callable") From 384d6c1fe7e24d1c88f85c3f443e5420e54ca935 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Sun, 10 Dec 2023 16:29:32 +0900 Subject: [PATCH 02/18] Update --- Lib/test/clinic.test.c | 8 ++++---- Modules/_io/clinic/textio.c.h | 8 ++++---- Modules/_io/textio.c | 4 ++-- Tools/clinic/clinic.py | 8 ++++++-- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/Lib/test/clinic.test.c b/Lib/test/clinic.test.c index 173ed8c9fd83fc..3aee572f213343 100644 --- a/Lib/test/clinic.test.c +++ b/Lib/test/clinic.test.c @@ -4988,18 +4988,18 @@ Test.property # define TEST_PROPERTY_GETSETTERDEF {"property", NULL, (setter)Test_property_set, NULL}, #endif -static PyObject * +static int Test_property_set_impl(TestObj *self, PyObject *value); -static PyObject * +static int Test_property_set(TestObj *self, PyObject *value, void *Py_UNUSED(context)) { return Test_property_set_impl(self, value); } -static PyObject * +static int Test_property_set_impl(TestObj *self, PyObject *value) -/*[clinic end generated code: output=2ba2d4de6020e191 input=3bc3f46a23c83a88]*/ +/*[clinic end generated code: output=e57ae784a4e3382a input=3bc3f46a23c83a88]*/ /*[clinic input] output push diff --git a/Modules/_io/clinic/textio.c.h b/Modules/_io/clinic/textio.c.h index 528063d48e9ec5..551b7af8aa477b 100644 --- a/Modules/_io/clinic/textio.c.h +++ b/Modules/_io/clinic/textio.c.h @@ -1077,13 +1077,13 @@ _io_TextIOWrapper__CHUNK_SIZE_get(textio *self, void *Py_UNUSED(context)) # define _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETTERDEF {"_CHUNK_SIZE", NULL, (setter)_io_TextIOWrapper__CHUNK_SIZE_set, NULL}, #endif -static PyObject * +static int _io_TextIOWrapper__CHUNK_SIZE_set_impl(textio *self, PyObject *value); -static PyObject * +static int _io_TextIOWrapper__CHUNK_SIZE_set(textio *self, PyObject *value, void *Py_UNUSED(context)) { - PyObject *return_value = NULL; + int return_value; Py_BEGIN_CRITICAL_SECTION(self); return_value = _io_TextIOWrapper__CHUNK_SIZE_set_impl(self, value); @@ -1091,4 +1091,4 @@ _io_TextIOWrapper__CHUNK_SIZE_set(textio *self, PyObject *value, void *Py_UNUSED return return_value; } -/*[clinic end generated code: output=29b1d97275d1a575 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=387991617d8f3911 input=a9049054013a1b77]*/ diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index fd2396f0f5d5ad..c14176339b7884 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -3258,9 +3258,9 @@ _io_TextIOWrapper__CHUNK_SIZE_get_impl(textio *self) _io.TextIOWrapper._CHUNK_SIZE [clinic start generated code]*/ -static PyObject * +static int _io_TextIOWrapper__CHUNK_SIZE_set_impl(textio *self, PyObject *value) -/*[clinic end generated code: output=0d4fc49ae6b8eb87 input=32fc99861db02a0a]*/ +/*[clinic end generated code: output=edb86d2db660a5ab input=32fc99861db02a0a]*/ { Py_ssize_t n; CHECK_ATTACHED_INT(self); diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index dcb0efd6714682..8371d610f217cc 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -851,7 +851,7 @@ class CLanguage(Language): {c_basename}({self_type}{self_name}, void *Py_UNUSED(context)) """) PARSER_PROTOTYPE_SETTER: Final[str] = normalize_snippet(""" - static PyObject * + static int {c_basename}({self_type}{self_name}, PyObject *value, void *Py_UNUSED(context)) """) METH_O_PROTOTYPE: Final[str] = normalize_snippet(""" @@ -1189,6 +1189,7 @@ def output_templates( methoddef_define = self.GETTERDEF_PROTOTYPE_DEFINE docstring_prototype = docstring_definition = '' elif f.kind is SETTER: + return_value_declaration = "int return_value;" methoddef_define = self.SETTERDEF_PROTOTYPE_DEFINE docstring_prototype = docstring_prototype = docstring_definition = '' else: @@ -1992,7 +1993,10 @@ def render_function( converter.set_template_dict(template_dict) f.return_converter.render(f, data) - template_dict['impl_return_type'] = f.return_converter.type + if f.kind is SETTER: + template_dict['impl_return_type'] = 'int' + else: + template_dict['impl_return_type'] = f.return_converter.type template_dict['declarations'] = format_escape("\n".join(data.declarations)) template_dict['initializers'] = "\n\n".join(data.initializers) From 2a8c3de295a67157b80fe27d659399175553b9ba Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Sun, 10 Dec 2023 19:20:07 +0900 Subject: [PATCH 03/18] Apply suggestions from code review Co-authored-by: Erlend E. Aasland --- Tools/clinic/clinic.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 8371d610f217cc..1a5d68025b635a 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -1247,7 +1247,7 @@ def parser_body( parsearg: str | None if f.kind in {GETTER, SETTER} and len(parameters) > 0: - raise RuntimeError("@getter, @setter should not define paramters") + fail("neither @getter nor @setter can define parameters") if not parameters: parser_code: list[str] | None @@ -1978,7 +1978,7 @@ def render_function( template_dict['c_basename'] = f.c_basename + "_get" elif f.kind is SETTER: template_dict['c_basename'] = f.c_basename + "_set" - # TODO: Improve handling pararms better way. + # Implicitly add the setter value parameter. data.impl_parameters.append("PyObject *value") data.impl_arguments.append("value") else: @@ -1994,6 +1994,7 @@ def render_function( 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 @@ -5375,7 +5376,7 @@ def at_critical_section(self, *args: str) -> None: def at_getter(self) -> None: if self.kind in (GETTER, SETTER): - fail("@getter and @setter can not be declared at once") + fail("only one of @getter or @setter can be used") self.kind = GETTER def at_setter(self) -> None: From 0ffa78b3ce14b83a4ba7f0d528f951c8f490d35e Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Sun, 10 Dec 2023 19:29:11 +0900 Subject: [PATCH 04/18] Address code review --- Lib/test/clinic.test.c | 18 +++++++++--------- Modules/_io/bufferedio.c | 18 +++++++++--------- Modules/_io/clinic/bufferedio.c.h | 26 +++++++++++++------------- Modules/_io/clinic/stringio.c.h | 26 +++++++++++++------------- Modules/_io/clinic/textio.c.h | 16 ++++++++-------- Modules/_io/stringio.c | 6 +++--- Modules/_io/textio.c | 2 +- Tools/clinic/clinic.py | 20 ++++++++++---------- 8 files changed, 66 insertions(+), 66 deletions(-) diff --git a/Lib/test/clinic.test.c b/Lib/test/clinic.test.c index 3aee572f213343..3625089ed5ae74 100644 --- a/Lib/test/clinic.test.c +++ b/Lib/test/clinic.test.c @@ -4956,11 +4956,11 @@ Test_meth_coexist_impl(TestObj *self) Test.property [clinic start generated code]*/ -#if defined(TEST_PROPERTY_GETSETTERDEF) -# undef TEST_PROPERTY_GETSETTERDEF -# define TEST_PROPERTY_GETSETTERDEF {"property", (getter)Test_property_get, (setter)Test_property_set, NULL}, +#if defined(TEST_PROPERTY_GETSETDEF) +# undef TEST_PROPERTY_GETSETTDEF +# define TEST_PROPERTY_GETSETDEF {"property", (getter)Test_property_get, (setter)Test_property_set, NULL}, #else -# define TEST_PROPERTY_GETSETTERDEF {"property", (getter)Test_property_get, NULL, NULL}, +# define TEST_PROPERTY_GETSETDEF {"property", (getter)Test_property_get, NULL, NULL}, #endif static PyObject * @@ -4974,16 +4974,16 @@ Test_property_get(TestObj *self, void *Py_UNUSED(context)) static PyObject * Test_property_get_impl(TestObj *self) -/*[clinic end generated code: output=606a5f21c27ff5dd input=2d92b3449fbc7d2b]*/ +/*[clinic end generated code: output=c957af8739d3ae67 input=2d92b3449fbc7d2b]*/ /*[clinic input] @setter Test.property [clinic start generated code]*/ -#if defined(TEST_PROPERTY_GETSETTERDEF) -# undef TEST_PROPERTY_GETSETTERDEF -# define TEST_PROPERTY_GETSETTERDEF {"property", (getter)Test_property_get, (setter)Test_property_set, NULL}, +#if defined(TEST_PROPERTY_GETSETDEF) +# undef TEST_PROPERTY_GETSETDEF +# define TEST_PROPERTY_GETSETDEF {"property", (getter)Test_property_get, (setter)Test_property_set, NULL}, #else # define TEST_PROPERTY_GETSETTERDEF {"property", NULL, (setter)Test_property_set, NULL}, #endif @@ -4999,7 +4999,7 @@ Test_property_set(TestObj *self, PyObject *value, void *Py_UNUSED(context)) static int Test_property_set_impl(TestObj *self, PyObject *value) -/*[clinic end generated code: output=e57ae784a4e3382a input=3bc3f46a23c83a88]*/ +/*[clinic end generated code: output=1b434343ddc0380d input=3bc3f46a23c83a88]*/ /*[clinic input] output push diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index b7a6252b96ee69..f02207ace9f3d2 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -2526,9 +2526,9 @@ static PyMemberDef bufferedreader_members[] = { }; static PyGetSetDef bufferedreader_getset[] = { - _IO__BUFFERED_CLOSED_GETSETTERDEF - _IO__BUFFERED_NAME_GETSETTERDEF - _IO__BUFFERED_MODE_GETSETTERDEF + _IO__BUFFERED_CLOSED_GETSETDEF + _IO__BUFFERED_NAME_GETSETDEF + _IO__BUFFERED_MODE_GETSETDEF {NULL} }; @@ -2586,9 +2586,9 @@ static PyMemberDef bufferedwriter_members[] = { }; static PyGetSetDef bufferedwriter_getset[] = { - _IO__BUFFERED_CLOSED_GETSETTERDEF - _IO__BUFFERED_NAME_GETSETTERDEF - _IO__BUFFERED_MODE_GETSETTERDEF + _IO__BUFFERED_CLOSED_GETSETDEF + _IO__BUFFERED_NAME_GETSETDEF + _IO__BUFFERED_MODE_GETSETDEF {NULL} }; @@ -2704,9 +2704,9 @@ static PyMemberDef bufferedrandom_members[] = { }; static PyGetSetDef bufferedrandom_getset[] = { - _IO__BUFFERED_CLOSED_GETSETTERDEF - _IO__BUFFERED_NAME_GETSETTERDEF - _IO__BUFFERED_MODE_GETSETTERDEF + _IO__BUFFERED_CLOSED_GETSETDEF + _IO__BUFFERED_NAME_GETSETDEF + _IO__BUFFERED_MODE_GETSETDEF {NULL} }; diff --git a/Modules/_io/clinic/bufferedio.c.h b/Modules/_io/clinic/bufferedio.c.h index b85c56287acacb..0412a208073c9a 100644 --- a/Modules/_io/clinic/bufferedio.c.h +++ b/Modules/_io/clinic/bufferedio.c.h @@ -327,11 +327,11 @@ _io__Buffered_simple_flush(buffered *self, PyObject *Py_UNUSED(ignored)) return return_value; } -#if defined(_IO__BUFFERED_CLOSED_GETSETTERDEF) -# undef _IO__BUFFERED_CLOSED_GETSETTERDEF -# define _IO__BUFFERED_CLOSED_GETSETTERDEF {"closed", (getter)_io__Buffered_closed_get, (setter)_io__Buffered_closed_set, NULL}, +#if defined(_IO__BUFFERED_CLOSED_GETSETDEF) +# undef _IO__BUFFERED_CLOSED_GETSETTDEF +# define _IO__BUFFERED_CLOSED_GETSETDEF {"closed", (getter)_io__Buffered_closed_get, (setter)_io__Buffered_closed_set, NULL}, #else -# define _IO__BUFFERED_CLOSED_GETSETTERDEF {"closed", (getter)_io__Buffered_closed_get, NULL, NULL}, +# define _IO__BUFFERED_CLOSED_GETSETDEF {"closed", (getter)_io__Buffered_closed_get, NULL, NULL}, #endif static PyObject * @@ -464,11 +464,11 @@ _io__Buffered_writable(buffered *self, PyObject *Py_UNUSED(ignored)) return return_value; } -#if defined(_IO__BUFFERED_NAME_GETSETTERDEF) -# undef _IO__BUFFERED_NAME_GETSETTERDEF -# define _IO__BUFFERED_NAME_GETSETTERDEF {"name", (getter)_io__Buffered_name_get, (setter)_io__Buffered_name_set, NULL}, +#if defined(_IO__BUFFERED_NAME_GETSETDEF) +# undef _IO__BUFFERED_NAME_GETSETTDEF +# define _IO__BUFFERED_NAME_GETSETDEF {"name", (getter)_io__Buffered_name_get, (setter)_io__Buffered_name_set, NULL}, #else -# define _IO__BUFFERED_NAME_GETSETTERDEF {"name", (getter)_io__Buffered_name_get, NULL, NULL}, +# define _IO__BUFFERED_NAME_GETSETDEF {"name", (getter)_io__Buffered_name_get, NULL, NULL}, #endif static PyObject * @@ -486,11 +486,11 @@ _io__Buffered_name_get(buffered *self, void *Py_UNUSED(context)) return return_value; } -#if defined(_IO__BUFFERED_MODE_GETSETTERDEF) -# undef _IO__BUFFERED_MODE_GETSETTERDEF -# define _IO__BUFFERED_MODE_GETSETTERDEF {"mode", (getter)_io__Buffered_mode_get, (setter)_io__Buffered_mode_set, NULL}, +#if defined(_IO__BUFFERED_MODE_GETSETDEF) +# undef _IO__BUFFERED_MODE_GETSETTDEF +# define _IO__BUFFERED_MODE_GETSETDEF {"mode", (getter)_io__Buffered_mode_get, (setter)_io__Buffered_mode_set, NULL}, #else -# define _IO__BUFFERED_MODE_GETSETTERDEF {"mode", (getter)_io__Buffered_mode_get, NULL, NULL}, +# define _IO__BUFFERED_MODE_GETSETDEF {"mode", (getter)_io__Buffered_mode_get, NULL, NULL}, #endif static PyObject * @@ -1230,4 +1230,4 @@ _io_BufferedRandom___init__(PyObject *self, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=1513f2e86f8b8995 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=d547078bfd4f6e31 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/stringio.c.h b/Modules/_io/clinic/stringio.c.h index 78968a376804e8..129de1b14786f9 100644 --- a/Modules/_io/clinic/stringio.c.h +++ b/Modules/_io/clinic/stringio.c.h @@ -475,11 +475,11 @@ _io_StringIO___setstate__(stringio *self, PyObject *state) return return_value; } -#if defined(_IO_STRINGIO_CLOSED_GETSETTERDEF) -# undef _IO_STRINGIO_CLOSED_GETSETTERDEF -# define _IO_STRINGIO_CLOSED_GETSETTERDEF {"closed", (getter)_io_StringIO_closed_get, (setter)_io_StringIO_closed_set, NULL}, +#if defined(_IO_STRINGIO_CLOSED_GETSETDEF) +# undef _IO_STRINGIO_CLOSED_GETSETTDEF +# define _IO_STRINGIO_CLOSED_GETSETDEF {"closed", (getter)_io_StringIO_closed_get, (setter)_io_StringIO_closed_set, NULL}, #else -# define _IO_STRINGIO_CLOSED_GETSETTERDEF {"closed", (getter)_io_StringIO_closed_get, NULL, NULL}, +# define _IO_STRINGIO_CLOSED_GETSETDEF {"closed", (getter)_io_StringIO_closed_get, NULL, NULL}, #endif static PyObject * @@ -497,11 +497,11 @@ _io_StringIO_closed_get(stringio *self, void *Py_UNUSED(context)) return return_value; } -#if defined(_IO_STRINGIO_LINE_BUFFERING_GETSETTERDEF) -# undef _IO_STRINGIO_LINE_BUFFERING_GETSETTERDEF -# define _IO_STRINGIO_LINE_BUFFERING_GETSETTERDEF {"line_buffering", (getter)_io_StringIO_line_buffering_get, (setter)_io_StringIO_line_buffering_set, NULL}, +#if defined(_IO_STRINGIO_LINE_BUFFERING_GETSETDEF) +# undef _IO_STRINGIO_LINE_BUFFERING_GETSETTDEF +# define _IO_STRINGIO_LINE_BUFFERING_GETSETDEF {"line_buffering", (getter)_io_StringIO_line_buffering_get, (setter)_io_StringIO_line_buffering_set, NULL}, #else -# define _IO_STRINGIO_LINE_BUFFERING_GETSETTERDEF {"line_buffering", (getter)_io_StringIO_line_buffering_get, NULL, NULL}, +# define _IO_STRINGIO_LINE_BUFFERING_GETSETDEF {"line_buffering", (getter)_io_StringIO_line_buffering_get, NULL, NULL}, #endif static PyObject * @@ -519,11 +519,11 @@ _io_StringIO_line_buffering_get(stringio *self, void *Py_UNUSED(context)) return return_value; } -#if defined(_IO_STRINGIO_NEWLINES_GETSETTERDEF) -# undef _IO_STRINGIO_NEWLINES_GETSETTERDEF -# define _IO_STRINGIO_NEWLINES_GETSETTERDEF {"newlines", (getter)_io_StringIO_newlines_get, (setter)_io_StringIO_newlines_set, NULL}, +#if defined(_IO_STRINGIO_NEWLINES_GETSETDEF) +# undef _IO_STRINGIO_NEWLINES_GETSETTDEF +# define _IO_STRINGIO_NEWLINES_GETSETDEF {"newlines", (getter)_io_StringIO_newlines_get, (setter)_io_StringIO_newlines_set, NULL}, #else -# define _IO_STRINGIO_NEWLINES_GETSETTERDEF {"newlines", (getter)_io_StringIO_newlines_get, NULL, NULL}, +# define _IO_STRINGIO_NEWLINES_GETSETDEF {"newlines", (getter)_io_StringIO_newlines_get, NULL, NULL}, #endif static PyObject * @@ -540,4 +540,4 @@ _io_StringIO_newlines_get(stringio *self, void *Py_UNUSED(context)) return return_value; } -/*[clinic end generated code: output=db35b529122b2cfc input=a9049054013a1b77]*/ +/*[clinic end generated code: output=6f1964f017d3ae05 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/textio.c.h b/Modules/_io/clinic/textio.c.h index 551b7af8aa477b..143899c7c6b938 100644 --- a/Modules/_io/clinic/textio.c.h +++ b/Modules/_io/clinic/textio.c.h @@ -1048,11 +1048,11 @@ _io_TextIOWrapper_close(textio *self, PyObject *Py_UNUSED(ignored)) return return_value; } -#if defined(_IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETTERDEF) -# undef _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETTERDEF -# define _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETTERDEF {"_CHUNK_SIZE", (getter)_io_TextIOWrapper__CHUNK_SIZE_get, (setter)_io_TextIOWrapper__CHUNK_SIZE_set, NULL}, +#if defined(_IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETDEF) +# undef _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETTDEF +# define _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETDEF {"_CHUNK_SIZE", (getter)_io_TextIOWrapper__CHUNK_SIZE_get, (setter)_io_TextIOWrapper__CHUNK_SIZE_set, NULL}, #else -# define _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETTERDEF {"_CHUNK_SIZE", (getter)_io_TextIOWrapper__CHUNK_SIZE_get, NULL, NULL}, +# define _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETDEF {"_CHUNK_SIZE", (getter)_io_TextIOWrapper__CHUNK_SIZE_get, NULL, NULL}, #endif static PyObject * @@ -1070,9 +1070,9 @@ _io_TextIOWrapper__CHUNK_SIZE_get(textio *self, void *Py_UNUSED(context)) return return_value; } -#if defined(_IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETTERDEF) -# undef _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETTERDEF -# define _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETTERDEF {"_CHUNK_SIZE", (getter)_io_TextIOWrapper__CHUNK_SIZE_get, (setter)_io_TextIOWrapper__CHUNK_SIZE_set, NULL}, +#if defined(_IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETDEF) +# undef _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETDEF +# define _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETDEF {"_CHUNK_SIZE", (getter)_io_TextIOWrapper__CHUNK_SIZE_get, (setter)_io_TextIOWrapper__CHUNK_SIZE_set, NULL}, #else # define _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETTERDEF {"_CHUNK_SIZE", NULL, (setter)_io_TextIOWrapper__CHUNK_SIZE_set, NULL}, #endif @@ -1091,4 +1091,4 @@ _io_TextIOWrapper__CHUNK_SIZE_set(textio *self, PyObject *value, void *Py_UNUSED return return_value; } -/*[clinic end generated code: output=387991617d8f3911 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=8a4bde8c47ea9fd9 input=a9049054013a1b77]*/ diff --git a/Modules/_io/stringio.c b/Modules/_io/stringio.c index f78e78af7f7ee7..06bc2679e8e227 100644 --- a/Modules/_io/stringio.c +++ b/Modules/_io/stringio.c @@ -1037,15 +1037,15 @@ static struct PyMethodDef stringio_methods[] = { }; static PyGetSetDef stringio_getset[] = { - _IO_STRINGIO_CLOSED_GETSETTERDEF - _IO_STRINGIO_NEWLINES_GETSETTERDEF + _IO_STRINGIO_CLOSED_GETSETDEF + _IO_STRINGIO_NEWLINES_GETSETDEF /* (following comments straight off of the original Python wrapper:) XXX Cruft to support the TextIOWrapper API. This would only be meaningful if StringIO supported the buffer attribute. Hopefully, a better solution, than adding these pseudo-attributes, will be found. */ - _IO_STRINGIO_LINE_BUFFERING_GETSETTERDEF + _IO_STRINGIO_LINE_BUFFERING_GETSETDEF {NULL} }; diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index c14176339b7884..c76d92cdd38b9a 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -3355,7 +3355,7 @@ static PyGetSetDef textiowrapper_getset[] = { */ {"newlines", (getter)textiowrapper_newlines_get, NULL, NULL}, {"errors", (getter)textiowrapper_errors_get, NULL, NULL}, - _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETTERDEF + _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETDEF {NULL} }; diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 1a5d68025b635a..ea696db9054856 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -874,19 +874,19 @@ class CLanguage(Language): {{"{name}", {methoddef_cast}{c_basename}{methoddef_cast_end}, {methoddef_flags}, {c_basename}__doc__}}, """) GETTERDEF_PROTOTYPE_DEFINE: Final[str] = normalize_snippet(r""" - #if defined({getsetter_name}_GETSETTERDEF) - # undef {getsetter_name}_GETSETTERDEF - # define {getsetter_name}_GETSETTERDEF {{"{name}", (getter){getset_basename}_get, (setter){getset_basename}_set, NULL}}, + #if defined({getset_name}_GETSETDEF) + # undef {getset_name}_GETSETTDEF + # define {getset_name}_GETSETDEF {{"{name}", (getter){getset_basename}_get, (setter){getset_basename}_set, NULL}}, #else - # define {getsetter_name}_GETSETTERDEF {{"{name}", (getter){getset_basename}_get, NULL, NULL}}, + # define {getset_name}_GETSETDEF {{"{name}", (getter){getset_basename}_get, NULL, NULL}}, #endif """) SETTERDEF_PROTOTYPE_DEFINE: Final[str] = normalize_snippet(r""" - #if defined({getsetter_name}_GETSETTERDEF) - # undef {getsetter_name}_GETSETTERDEF - # define {getsetter_name}_GETSETTERDEF {{"{name}", (getter){getset_basename}_get, (setter){getset_basename}_set, NULL}}, + #if defined({getset_name}_GETSETDEF) + # undef {getset_name}_GETSETDEF + # define {getset_name}_GETSETDEF {{"{name}", (getter){getset_basename}_get, (setter){getset_basename}_set, NULL}}, #else - # define {getsetter_name}_GETSETTERDEF {{"{name}", NULL, (setter){getset_basename}_set, NULL}}, + # define {getset_name}_GETSETTERDEF {{"{name}", NULL, (setter){getset_basename}_set, NULL}}, #endif """) METHODDEF_PROTOTYPE_IFNDEF: Final[str] = normalize_snippet(""" @@ -1189,7 +1189,7 @@ def output_templates( methoddef_define = self.GETTERDEF_PROTOTYPE_DEFINE docstring_prototype = docstring_definition = '' elif f.kind is SETTER: - return_value_declaration = "int return_value;" + return_value_declaration = "int {return_value};" methoddef_define = self.SETTERDEF_PROTOTYPE_DEFINE docstring_prototype = docstring_prototype = docstring_definition = '' else: @@ -1972,7 +1972,7 @@ def render_function( template_dict = {'full_name': full_name} template_dict['name'] = f.displayname if f.kind in (GETTER, SETTER): - template_dict['getsetter_name'] = f.c_basename.upper() + template_dict['getset_name'] = f.c_basename.upper() template_dict['getset_basename'] = f.c_basename if f.kind is GETTER: template_dict['c_basename'] = f.c_basename + "_get" From 8e85ab3518d1cea02c8876cbdceb399b36a5627f Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Sun, 10 Dec 2023 19:33:24 +0900 Subject: [PATCH 05/18] nit --- Tools/clinic/clinic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index ea696db9054856..8581bb7fb08461 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -5381,7 +5381,7 @@ def at_getter(self) -> None: def at_setter(self) -> None: if self.kind in (GETTER, SETTER): - fail("@getter and @setter can not be declared at once") + fail("only one of @getter or @setter can be used") self.kind = SETTER def at_staticmethod(self) -> None: From f3517f989decd6aa7e8e710c8ae5fcaa1390c950 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Sun, 10 Dec 2023 19:39:02 +0900 Subject: [PATCH 06/18] Prohibit declaration of return type for `getset` --- Tools/clinic/clinic.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 8581bb7fb08461..ef6ca66b5c7bb0 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -5583,6 +5583,8 @@ def state_modulename_name(self, line: str) -> None: return_converter = None if returns: + if self.kind in {GETTER, SETTER}: + fail("@getter / @setter can not declare return type") ast_input = f"def x() -> {returns}: pass" try: module_node = ast.parse(ast_input) From 323cfc0522257e9c7d3cc6106055e6e72ed28d65 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Sun, 10 Dec 2023 19:49:45 +0900 Subject: [PATCH 07/18] Add test --- Lib/test/test_clinic.py | 24 ++++++++++++++++++++++++ Tools/clinic/clinic.py | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index f53e9481083106..0121df03a14536 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -2197,6 +2197,30 @@ class Foo "" "" expected_error = err_template.format(invalid_kind) self.expect_failure(block, expected_error, lineno=3) + def test_invalid_getset(self): + annotations = ["@getter", "@setter"] + for annotation in annotations: + with self.subTest(annotation=annotation): + block = f""" + module foo + class Foo "" "" + {annotation} + Foo.property -> int + """ + expected_error = "neither @getter nor @setter can define return type" + self.expect_failure(block, expected_error, lineno=3) + + block = f""" + module foo + class Foo "" "" + {annotation} + Foo.property + obj: int + / + """ + expected_error = "neither @getter nor @setter can define parameters" + self.expect_failure(block, expected_error, lineno=0) + def test_duplicate_coexist(self): err = "Called @coexist twice" block = """ diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index ef6ca66b5c7bb0..bd4f4d4f1edd95 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -5584,7 +5584,7 @@ def state_modulename_name(self, line: str) -> None: return_converter = None if returns: if self.kind in {GETTER, SETTER}: - fail("@getter / @setter can not declare return type") + fail("neither @getter nor @setter can define return type") ast_input = f"def x() -> {returns}: pass" try: module_node = ast.parse(ast_input) From 30da0cfa63ea0979f55bbf18418e3aaaaa46fcb3 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Mon, 11 Dec 2023 19:07:55 +0900 Subject: [PATCH 08/18] Update Tools/clinic/clinic.py Co-authored-by: Erlend E. Aasland --- Tools/clinic/clinic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index bd4f4d4f1edd95..4ee1d22d9ac09c 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -1246,7 +1246,7 @@ def parser_body( limited_capi = False parsearg: str | None - if f.kind in {GETTER, SETTER} and len(parameters) > 0: + if f.kind in {GETTER, SETTER} and parameters: fail("neither @getter nor @setter can define parameters") if not parameters: From 1539d1144e5590e414cc84dae11dc69cbbb9a513 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Mon, 11 Dec 2023 19:14:04 +0900 Subject: [PATCH 09/18] Address code review --- Lib/test/clinic.test.c | 16 ++++++++-------- Modules/_io/clinic/bufferedio.c.h | 20 ++++++++++---------- Modules/_io/clinic/stringio.c.h | 20 ++++++++++---------- Modules/_io/clinic/textio.c.h | 14 +++++++------- Tools/clinic/clinic.py | 12 ++++++------ 5 files changed, 41 insertions(+), 41 deletions(-) diff --git a/Lib/test/clinic.test.c b/Lib/test/clinic.test.c index 3625089ed5ae74..c7bc4d0214deaf 100644 --- a/Lib/test/clinic.test.c +++ b/Lib/test/clinic.test.c @@ -4957,10 +4957,10 @@ Test.property [clinic start generated code]*/ #if defined(TEST_PROPERTY_GETSETDEF) -# undef TEST_PROPERTY_GETSETTDEF -# define TEST_PROPERTY_GETSETDEF {"property", (getter)Test_property_get, (setter)Test_property_set, NULL}, +# undef TEST_PROPERTY_GETSETTDEF +# define TEST_PROPERTY_GETSETDEF {"property", (getter)Test_property_get, (setter)Test_property_set, NULL}, #else -# define TEST_PROPERTY_GETSETDEF {"property", (getter)Test_property_get, NULL, NULL}, +# define TEST_PROPERTY_GETSETDEF {"property", (getter)Test_property_get, NULL, NULL}, #endif static PyObject * @@ -4974,7 +4974,7 @@ Test_property_get(TestObj *self, void *Py_UNUSED(context)) static PyObject * Test_property_get_impl(TestObj *self) -/*[clinic end generated code: output=c957af8739d3ae67 input=2d92b3449fbc7d2b]*/ +/*[clinic end generated code: output=c7f18e7848b00cfa input=2d92b3449fbc7d2b]*/ /*[clinic input] @setter @@ -4982,10 +4982,10 @@ Test.property [clinic start generated code]*/ #if defined(TEST_PROPERTY_GETSETDEF) -# undef TEST_PROPERTY_GETSETDEF -# define TEST_PROPERTY_GETSETDEF {"property", (getter)Test_property_get, (setter)Test_property_set, NULL}, +# undef TEST_PROPERTY_GETSETDEF +# define TEST_PROPERTY_GETSETDEF {"property", (getter)Test_property_get, (setter)Test_property_set, NULL}, #else -# define TEST_PROPERTY_GETSETTERDEF {"property", NULL, (setter)Test_property_set, NULL}, +# define TEST_PROPERTY_GETSETTERDEF {"property", NULL, (setter)Test_property_set, NULL}, #endif static int @@ -4999,7 +4999,7 @@ Test_property_set(TestObj *self, PyObject *value, void *Py_UNUSED(context)) static int Test_property_set_impl(TestObj *self, PyObject *value) -/*[clinic end generated code: output=1b434343ddc0380d input=3bc3f46a23c83a88]*/ +/*[clinic end generated code: output=63e670882002b596 input=3bc3f46a23c83a88]*/ /*[clinic input] output push diff --git a/Modules/_io/clinic/bufferedio.c.h b/Modules/_io/clinic/bufferedio.c.h index 0412a208073c9a..6f406c1d4c24c7 100644 --- a/Modules/_io/clinic/bufferedio.c.h +++ b/Modules/_io/clinic/bufferedio.c.h @@ -328,10 +328,10 @@ _io__Buffered_simple_flush(buffered *self, PyObject *Py_UNUSED(ignored)) } #if defined(_IO__BUFFERED_CLOSED_GETSETDEF) -# undef _IO__BUFFERED_CLOSED_GETSETTDEF -# define _IO__BUFFERED_CLOSED_GETSETDEF {"closed", (getter)_io__Buffered_closed_get, (setter)_io__Buffered_closed_set, NULL}, +# undef _IO__BUFFERED_CLOSED_GETSETTDEF +# define _IO__BUFFERED_CLOSED_GETSETDEF {"closed", (getter)_io__Buffered_closed_get, (setter)_io__Buffered_closed_set, NULL}, #else -# define _IO__BUFFERED_CLOSED_GETSETDEF {"closed", (getter)_io__Buffered_closed_get, NULL, NULL}, +# define _IO__BUFFERED_CLOSED_GETSETDEF {"closed", (getter)_io__Buffered_closed_get, NULL, NULL}, #endif static PyObject * @@ -465,10 +465,10 @@ _io__Buffered_writable(buffered *self, PyObject *Py_UNUSED(ignored)) } #if defined(_IO__BUFFERED_NAME_GETSETDEF) -# undef _IO__BUFFERED_NAME_GETSETTDEF -# define _IO__BUFFERED_NAME_GETSETDEF {"name", (getter)_io__Buffered_name_get, (setter)_io__Buffered_name_set, NULL}, +# undef _IO__BUFFERED_NAME_GETSETTDEF +# define _IO__BUFFERED_NAME_GETSETDEF {"name", (getter)_io__Buffered_name_get, (setter)_io__Buffered_name_set, NULL}, #else -# define _IO__BUFFERED_NAME_GETSETDEF {"name", (getter)_io__Buffered_name_get, NULL, NULL}, +# define _IO__BUFFERED_NAME_GETSETDEF {"name", (getter)_io__Buffered_name_get, NULL, NULL}, #endif static PyObject * @@ -487,10 +487,10 @@ _io__Buffered_name_get(buffered *self, void *Py_UNUSED(context)) } #if defined(_IO__BUFFERED_MODE_GETSETDEF) -# undef _IO__BUFFERED_MODE_GETSETTDEF -# define _IO__BUFFERED_MODE_GETSETDEF {"mode", (getter)_io__Buffered_mode_get, (setter)_io__Buffered_mode_set, NULL}, +# undef _IO__BUFFERED_MODE_GETSETTDEF +# define _IO__BUFFERED_MODE_GETSETDEF {"mode", (getter)_io__Buffered_mode_get, (setter)_io__Buffered_mode_set, NULL}, #else -# define _IO__BUFFERED_MODE_GETSETDEF {"mode", (getter)_io__Buffered_mode_get, NULL, NULL}, +# define _IO__BUFFERED_MODE_GETSETDEF {"mode", (getter)_io__Buffered_mode_get, NULL, NULL}, #endif static PyObject * @@ -1230,4 +1230,4 @@ _io_BufferedRandom___init__(PyObject *self, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=d547078bfd4f6e31 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=481b8d69c67b4d55 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/stringio.c.h b/Modules/_io/clinic/stringio.c.h index 129de1b14786f9..89529a08d6f01e 100644 --- a/Modules/_io/clinic/stringio.c.h +++ b/Modules/_io/clinic/stringio.c.h @@ -476,10 +476,10 @@ _io_StringIO___setstate__(stringio *self, PyObject *state) } #if defined(_IO_STRINGIO_CLOSED_GETSETDEF) -# undef _IO_STRINGIO_CLOSED_GETSETTDEF -# define _IO_STRINGIO_CLOSED_GETSETDEF {"closed", (getter)_io_StringIO_closed_get, (setter)_io_StringIO_closed_set, NULL}, +# undef _IO_STRINGIO_CLOSED_GETSETTDEF +# define _IO_STRINGIO_CLOSED_GETSETDEF {"closed", (getter)_io_StringIO_closed_get, (setter)_io_StringIO_closed_set, NULL}, #else -# define _IO_STRINGIO_CLOSED_GETSETDEF {"closed", (getter)_io_StringIO_closed_get, NULL, NULL}, +# define _IO_STRINGIO_CLOSED_GETSETDEF {"closed", (getter)_io_StringIO_closed_get, NULL, NULL}, #endif static PyObject * @@ -498,10 +498,10 @@ _io_StringIO_closed_get(stringio *self, void *Py_UNUSED(context)) } #if defined(_IO_STRINGIO_LINE_BUFFERING_GETSETDEF) -# undef _IO_STRINGIO_LINE_BUFFERING_GETSETTDEF -# define _IO_STRINGIO_LINE_BUFFERING_GETSETDEF {"line_buffering", (getter)_io_StringIO_line_buffering_get, (setter)_io_StringIO_line_buffering_set, NULL}, +# undef _IO_STRINGIO_LINE_BUFFERING_GETSETTDEF +# define _IO_STRINGIO_LINE_BUFFERING_GETSETDEF {"line_buffering", (getter)_io_StringIO_line_buffering_get, (setter)_io_StringIO_line_buffering_set, NULL}, #else -# define _IO_STRINGIO_LINE_BUFFERING_GETSETDEF {"line_buffering", (getter)_io_StringIO_line_buffering_get, NULL, NULL}, +# define _IO_STRINGIO_LINE_BUFFERING_GETSETDEF {"line_buffering", (getter)_io_StringIO_line_buffering_get, NULL, NULL}, #endif static PyObject * @@ -520,10 +520,10 @@ _io_StringIO_line_buffering_get(stringio *self, void *Py_UNUSED(context)) } #if defined(_IO_STRINGIO_NEWLINES_GETSETDEF) -# undef _IO_STRINGIO_NEWLINES_GETSETTDEF -# define _IO_STRINGIO_NEWLINES_GETSETDEF {"newlines", (getter)_io_StringIO_newlines_get, (setter)_io_StringIO_newlines_set, NULL}, +# undef _IO_STRINGIO_NEWLINES_GETSETTDEF +# define _IO_STRINGIO_NEWLINES_GETSETDEF {"newlines", (getter)_io_StringIO_newlines_get, (setter)_io_StringIO_newlines_set, NULL}, #else -# define _IO_STRINGIO_NEWLINES_GETSETDEF {"newlines", (getter)_io_StringIO_newlines_get, NULL, NULL}, +# define _IO_STRINGIO_NEWLINES_GETSETDEF {"newlines", (getter)_io_StringIO_newlines_get, NULL, NULL}, #endif static PyObject * @@ -540,4 +540,4 @@ _io_StringIO_newlines_get(stringio *self, void *Py_UNUSED(context)) return return_value; } -/*[clinic end generated code: output=6f1964f017d3ae05 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=c68ed58e45ff9e0d input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/textio.c.h b/Modules/_io/clinic/textio.c.h index 143899c7c6b938..784749887182a8 100644 --- a/Modules/_io/clinic/textio.c.h +++ b/Modules/_io/clinic/textio.c.h @@ -1049,10 +1049,10 @@ _io_TextIOWrapper_close(textio *self, PyObject *Py_UNUSED(ignored)) } #if defined(_IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETDEF) -# undef _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETTDEF -# define _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETDEF {"_CHUNK_SIZE", (getter)_io_TextIOWrapper__CHUNK_SIZE_get, (setter)_io_TextIOWrapper__CHUNK_SIZE_set, NULL}, +# undef _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETTDEF +# define _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETDEF {"_CHUNK_SIZE", (getter)_io_TextIOWrapper__CHUNK_SIZE_get, (setter)_io_TextIOWrapper__CHUNK_SIZE_set, NULL}, #else -# define _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETDEF {"_CHUNK_SIZE", (getter)_io_TextIOWrapper__CHUNK_SIZE_get, NULL, NULL}, +# define _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETDEF {"_CHUNK_SIZE", (getter)_io_TextIOWrapper__CHUNK_SIZE_get, NULL, NULL}, #endif static PyObject * @@ -1071,10 +1071,10 @@ _io_TextIOWrapper__CHUNK_SIZE_get(textio *self, void *Py_UNUSED(context)) } #if defined(_IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETDEF) -# undef _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETDEF -# define _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETDEF {"_CHUNK_SIZE", (getter)_io_TextIOWrapper__CHUNK_SIZE_get, (setter)_io_TextIOWrapper__CHUNK_SIZE_set, NULL}, +# undef _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETDEF +# define _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETDEF {"_CHUNK_SIZE", (getter)_io_TextIOWrapper__CHUNK_SIZE_get, (setter)_io_TextIOWrapper__CHUNK_SIZE_set, NULL}, #else -# define _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETTERDEF {"_CHUNK_SIZE", NULL, (setter)_io_TextIOWrapper__CHUNK_SIZE_set, NULL}, +# define _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETTERDEF {"_CHUNK_SIZE", NULL, (setter)_io_TextIOWrapper__CHUNK_SIZE_set, NULL}, #endif static int @@ -1091,4 +1091,4 @@ _io_TextIOWrapper__CHUNK_SIZE_set(textio *self, PyObject *value, void *Py_UNUSED return return_value; } -/*[clinic end generated code: output=8a4bde8c47ea9fd9 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=d7f6e6ae6d81b506 input=a9049054013a1b77]*/ diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 4ee1d22d9ac09c..23a7a0f772beb4 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -875,18 +875,18 @@ class CLanguage(Language): """) GETTERDEF_PROTOTYPE_DEFINE: Final[str] = normalize_snippet(r""" #if defined({getset_name}_GETSETDEF) - # undef {getset_name}_GETSETTDEF - # define {getset_name}_GETSETDEF {{"{name}", (getter){getset_basename}_get, (setter){getset_basename}_set, NULL}}, + # undef {getset_name}_GETSETTDEF + # define {getset_name}_GETSETDEF {{"{name}", (getter){getset_basename}_get, (setter){getset_basename}_set, NULL}}, #else - # define {getset_name}_GETSETDEF {{"{name}", (getter){getset_basename}_get, NULL, NULL}}, + # define {getset_name}_GETSETDEF {{"{name}", (getter){getset_basename}_get, NULL, NULL}}, #endif """) SETTERDEF_PROTOTYPE_DEFINE: Final[str] = normalize_snippet(r""" #if defined({getset_name}_GETSETDEF) - # undef {getset_name}_GETSETDEF - # define {getset_name}_GETSETDEF {{"{name}", (getter){getset_basename}_get, (setter){getset_basename}_set, NULL}}, + # undef {getset_name}_GETSETDEF + # define {getset_name}_GETSETDEF {{"{name}", (getter){getset_basename}_get, (setter){getset_basename}_set, NULL}}, #else - # define {getset_name}_GETSETTERDEF {{"{name}", NULL, (setter){getset_basename}_set, NULL}}, + # define {getset_name}_GETSETTERDEF {{"{name}", NULL, (setter){getset_basename}_set, NULL}}, #endif """) METHODDEF_PROTOTYPE_IFNDEF: Final[str] = normalize_snippet(""" From d18cd494ea44c2930552a63a6e017ce6d372fd5e Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Mon, 11 Dec 2023 21:19:06 +0900 Subject: [PATCH 10/18] Address code review --- Lib/test/clinic.test.c | 8 ++++---- Modules/_io/clinic/bufferedio.c.h | 8 ++++---- Modules/_io/clinic/stringio.c.h | 8 ++++---- Modules/_io/clinic/textio.c.h | 6 +++--- Tools/clinic/clinic.py | 4 ++-- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Lib/test/clinic.test.c b/Lib/test/clinic.test.c index c7bc4d0214deaf..a6a21664bb82a1 100644 --- a/Lib/test/clinic.test.c +++ b/Lib/test/clinic.test.c @@ -4957,7 +4957,7 @@ Test.property [clinic start generated code]*/ #if defined(TEST_PROPERTY_GETSETDEF) -# undef TEST_PROPERTY_GETSETTDEF +# undef TEST_PROPERTY_GETSETDEF # define TEST_PROPERTY_GETSETDEF {"property", (getter)Test_property_get, (setter)Test_property_set, NULL}, #else # define TEST_PROPERTY_GETSETDEF {"property", (getter)Test_property_get, NULL, NULL}, @@ -4974,7 +4974,7 @@ Test_property_get(TestObj *self, void *Py_UNUSED(context)) static PyObject * Test_property_get_impl(TestObj *self) -/*[clinic end generated code: output=c7f18e7848b00cfa input=2d92b3449fbc7d2b]*/ +/*[clinic end generated code: output=af8140b692e0e2f1 input=2d92b3449fbc7d2b]*/ /*[clinic input] @setter @@ -4985,7 +4985,7 @@ Test.property # undef TEST_PROPERTY_GETSETDEF # define TEST_PROPERTY_GETSETDEF {"property", (getter)Test_property_get, (setter)Test_property_set, NULL}, #else -# define TEST_PROPERTY_GETSETTERDEF {"property", NULL, (setter)Test_property_set, NULL}, +# define TEST_PROPERTY_GETSETDEF {"property", NULL, (setter)Test_property_set, NULL}, #endif static int @@ -4999,7 +4999,7 @@ Test_property_set(TestObj *self, PyObject *value, void *Py_UNUSED(context)) static int Test_property_set_impl(TestObj *self, PyObject *value) -/*[clinic end generated code: output=63e670882002b596 input=3bc3f46a23c83a88]*/ +/*[clinic end generated code: output=f3eba6487d7550e2 input=3bc3f46a23c83a88]*/ /*[clinic input] output push diff --git a/Modules/_io/clinic/bufferedio.c.h b/Modules/_io/clinic/bufferedio.c.h index 6f406c1d4c24c7..ec46d5409a3d82 100644 --- a/Modules/_io/clinic/bufferedio.c.h +++ b/Modules/_io/clinic/bufferedio.c.h @@ -328,7 +328,7 @@ _io__Buffered_simple_flush(buffered *self, PyObject *Py_UNUSED(ignored)) } #if defined(_IO__BUFFERED_CLOSED_GETSETDEF) -# undef _IO__BUFFERED_CLOSED_GETSETTDEF +# undef _IO__BUFFERED_CLOSED_GETSETDEF # define _IO__BUFFERED_CLOSED_GETSETDEF {"closed", (getter)_io__Buffered_closed_get, (setter)_io__Buffered_closed_set, NULL}, #else # define _IO__BUFFERED_CLOSED_GETSETDEF {"closed", (getter)_io__Buffered_closed_get, NULL, NULL}, @@ -465,7 +465,7 @@ _io__Buffered_writable(buffered *self, PyObject *Py_UNUSED(ignored)) } #if defined(_IO__BUFFERED_NAME_GETSETDEF) -# undef _IO__BUFFERED_NAME_GETSETTDEF +# undef _IO__BUFFERED_NAME_GETSETDEF # define _IO__BUFFERED_NAME_GETSETDEF {"name", (getter)_io__Buffered_name_get, (setter)_io__Buffered_name_set, NULL}, #else # define _IO__BUFFERED_NAME_GETSETDEF {"name", (getter)_io__Buffered_name_get, NULL, NULL}, @@ -487,7 +487,7 @@ _io__Buffered_name_get(buffered *self, void *Py_UNUSED(context)) } #if defined(_IO__BUFFERED_MODE_GETSETDEF) -# undef _IO__BUFFERED_MODE_GETSETTDEF +# undef _IO__BUFFERED_MODE_GETSETDEF # define _IO__BUFFERED_MODE_GETSETDEF {"mode", (getter)_io__Buffered_mode_get, (setter)_io__Buffered_mode_set, NULL}, #else # define _IO__BUFFERED_MODE_GETSETDEF {"mode", (getter)_io__Buffered_mode_get, NULL, NULL}, @@ -1230,4 +1230,4 @@ _io_BufferedRandom___init__(PyObject *self, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=481b8d69c67b4d55 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=0999c33f666dc692 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/stringio.c.h b/Modules/_io/clinic/stringio.c.h index 89529a08d6f01e..fc2962d1c9c9a7 100644 --- a/Modules/_io/clinic/stringio.c.h +++ b/Modules/_io/clinic/stringio.c.h @@ -476,7 +476,7 @@ _io_StringIO___setstate__(stringio *self, PyObject *state) } #if defined(_IO_STRINGIO_CLOSED_GETSETDEF) -# undef _IO_STRINGIO_CLOSED_GETSETTDEF +# undef _IO_STRINGIO_CLOSED_GETSETDEF # define _IO_STRINGIO_CLOSED_GETSETDEF {"closed", (getter)_io_StringIO_closed_get, (setter)_io_StringIO_closed_set, NULL}, #else # define _IO_STRINGIO_CLOSED_GETSETDEF {"closed", (getter)_io_StringIO_closed_get, NULL, NULL}, @@ -498,7 +498,7 @@ _io_StringIO_closed_get(stringio *self, void *Py_UNUSED(context)) } #if defined(_IO_STRINGIO_LINE_BUFFERING_GETSETDEF) -# undef _IO_STRINGIO_LINE_BUFFERING_GETSETTDEF +# undef _IO_STRINGIO_LINE_BUFFERING_GETSETDEF # define _IO_STRINGIO_LINE_BUFFERING_GETSETDEF {"line_buffering", (getter)_io_StringIO_line_buffering_get, (setter)_io_StringIO_line_buffering_set, NULL}, #else # define _IO_STRINGIO_LINE_BUFFERING_GETSETDEF {"line_buffering", (getter)_io_StringIO_line_buffering_get, NULL, NULL}, @@ -520,7 +520,7 @@ _io_StringIO_line_buffering_get(stringio *self, void *Py_UNUSED(context)) } #if defined(_IO_STRINGIO_NEWLINES_GETSETDEF) -# undef _IO_STRINGIO_NEWLINES_GETSETTDEF +# undef _IO_STRINGIO_NEWLINES_GETSETDEF # define _IO_STRINGIO_NEWLINES_GETSETDEF {"newlines", (getter)_io_StringIO_newlines_get, (setter)_io_StringIO_newlines_set, NULL}, #else # define _IO_STRINGIO_NEWLINES_GETSETDEF {"newlines", (getter)_io_StringIO_newlines_get, NULL, NULL}, @@ -540,4 +540,4 @@ _io_StringIO_newlines_get(stringio *self, void *Py_UNUSED(context)) return return_value; } -/*[clinic end generated code: output=c68ed58e45ff9e0d input=a9049054013a1b77]*/ +/*[clinic end generated code: output=27726751d98ab617 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/textio.c.h b/Modules/_io/clinic/textio.c.h index 784749887182a8..a492f340c74c0d 100644 --- a/Modules/_io/clinic/textio.c.h +++ b/Modules/_io/clinic/textio.c.h @@ -1049,7 +1049,7 @@ _io_TextIOWrapper_close(textio *self, PyObject *Py_UNUSED(ignored)) } #if defined(_IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETDEF) -# undef _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETTDEF +# undef _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETDEF # define _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETDEF {"_CHUNK_SIZE", (getter)_io_TextIOWrapper__CHUNK_SIZE_get, (setter)_io_TextIOWrapper__CHUNK_SIZE_set, NULL}, #else # define _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETDEF {"_CHUNK_SIZE", (getter)_io_TextIOWrapper__CHUNK_SIZE_get, NULL, NULL}, @@ -1074,7 +1074,7 @@ _io_TextIOWrapper__CHUNK_SIZE_get(textio *self, void *Py_UNUSED(context)) # undef _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETDEF # define _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETDEF {"_CHUNK_SIZE", (getter)_io_TextIOWrapper__CHUNK_SIZE_get, (setter)_io_TextIOWrapper__CHUNK_SIZE_set, NULL}, #else -# define _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETTERDEF {"_CHUNK_SIZE", NULL, (setter)_io_TextIOWrapper__CHUNK_SIZE_set, NULL}, +# define _IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETDEF {"_CHUNK_SIZE", NULL, (setter)_io_TextIOWrapper__CHUNK_SIZE_set, NULL}, #endif static int @@ -1091,4 +1091,4 @@ _io_TextIOWrapper__CHUNK_SIZE_set(textio *self, PyObject *value, void *Py_UNUSED return return_value; } -/*[clinic end generated code: output=d7f6e6ae6d81b506 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=b312f2d2e2221580 input=a9049054013a1b77]*/ diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 23a7a0f772beb4..305ab1cf9ff7f9 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -875,7 +875,7 @@ class CLanguage(Language): """) GETTERDEF_PROTOTYPE_DEFINE: Final[str] = normalize_snippet(r""" #if defined({getset_name}_GETSETDEF) - # undef {getset_name}_GETSETTDEF + # undef {getset_name}_GETSETDEF # define {getset_name}_GETSETDEF {{"{name}", (getter){getset_basename}_get, (setter){getset_basename}_set, NULL}}, #else # define {getset_name}_GETSETDEF {{"{name}", (getter){getset_basename}_get, NULL, NULL}}, @@ -886,7 +886,7 @@ class CLanguage(Language): # undef {getset_name}_GETSETDEF # define {getset_name}_GETSETDEF {{"{name}", (getter){getset_basename}_get, (setter){getset_basename}_set, NULL}}, #else - # define {getset_name}_GETSETTERDEF {{"{name}", NULL, (setter){getset_basename}_set, NULL}}, + # define {getset_name}_GETSETDEF {{"{name}", NULL, (setter){getset_basename}_set, NULL}}, #endif """) METHODDEF_PROTOTYPE_IFNDEF: Final[str] = normalize_snippet(""" From bc373f6bdc31f9093ace9684a847141d076b32cd Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Wed, 13 Dec 2023 22:02:12 +0900 Subject: [PATCH 11/18] Apply suggestions from code review Co-authored-by: Alex Waygood --- Tools/clinic/clinic.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 305ab1cf9ff7f9..2ccde676192a0f 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -1971,7 +1971,7 @@ def render_function( full_name = f.full_name template_dict = {'full_name': full_name} template_dict['name'] = f.displayname - if f.kind in (GETTER, SETTER): + if f.kind in {GETTER, SETTER}: template_dict['getset_name'] = f.c_basename.upper() template_dict['getset_basename'] = f.c_basename if f.kind is GETTER: @@ -5584,7 +5584,7 @@ def state_modulename_name(self, line: str) -> None: return_converter = None if returns: if self.kind in {GETTER, SETTER}: - fail("neither @getter nor @setter can define return type") + fail(f"@{self.kind.name.lower()} methods cannot define a return type") ast_input = f"def x() -> {returns}: pass" try: module_node = ast.parse(ast_input) From 0cd047b96b06a07a6aacc72bfae9d40e02a6368e Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Wed, 13 Dec 2023 22:07:46 +0900 Subject: [PATCH 12/18] Use pattern matching --- Tools/clinic/clinic.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 2ccde676192a0f..09de7ef34c4630 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -5375,14 +5375,22 @@ def at_critical_section(self, *args: str) -> None: self.critical_section = True def at_getter(self) -> None: - if self.kind in (GETTER, SETTER): - fail("only one of @getter or @setter can be used") - self.kind = GETTER + match self.kind: + case FunctionKind.GETTER: + fail("Cannot apply @getter twice to the same function!") + case FunctionKind.SETTER: + fail("Cannot apply both @getter and @setter to the same function!") + case _: + self.kind = FunctionKind.GETTER def at_setter(self) -> None: - if self.kind in (GETTER, SETTER): - fail("only one of @getter or @setter can be used") - self.kind = SETTER + match self.kind: + case FunctionKind.SETTER: + fail("Cannot apply @setter twice to the same function!") + case FunctionKind.GETTER: + fail("Cannot apply both @getter and @setter to the same function!") + case _: + self.kind = FunctionKind.SETTER def at_staticmethod(self) -> None: if self.kind is not CALLABLE: From c8a035f88fdf19d106bb3aed5851ffc4db4774ef Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Wed, 13 Dec 2023 22:10:04 +0900 Subject: [PATCH 13/18] Address code review --- Tools/clinic/clinic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 09de7ef34c4630..1276a47911fbd4 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -1247,7 +1247,7 @@ def parser_body( parsearg: str | None if f.kind in {GETTER, SETTER} and parameters: - fail("neither @getter nor @setter can define parameters") + fail(f"@{f.kind.name.lower()} method cannot define parameters") if not parameters: parser_code: list[str] | None From 9c6696118efc407adf09a376f780bf58be77af90 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Wed, 13 Dec 2023 22:13:06 +0900 Subject: [PATCH 14/18] fix test --- Lib/test/test_clinic.py | 4 ++-- Tools/clinic/clinic.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index 0121df03a14536..bc3fcd766e0cd3 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -2207,7 +2207,7 @@ class Foo "" "" {annotation} Foo.property -> int """ - expected_error = "neither @getter nor @setter can define return type" + expected_error = f"{annotation} method cannot define a return type" self.expect_failure(block, expected_error, lineno=3) block = f""" @@ -2218,7 +2218,7 @@ class Foo "" "" obj: int / """ - expected_error = "neither @getter nor @setter can define parameters" + expected_error = f"{annotation} method cannot define parameters" self.expect_failure(block, expected_error, lineno=0) def test_duplicate_coexist(self): diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 1276a47911fbd4..bd3511a494a3d8 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -5592,7 +5592,7 @@ def state_modulename_name(self, line: str) -> None: return_converter = None if returns: if self.kind in {GETTER, SETTER}: - fail(f"@{self.kind.name.lower()} methods cannot define a return type") + fail(f"@{self.kind.name.lower()} method cannot define a return type") ast_input = f"def x() -> {returns}: pass" try: module_node = ast.parse(ast_input) From 06b1cb19b979fb2c364b13cd0982dbed759053c1 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Wed, 13 Dec 2023 22:19:08 +0900 Subject: [PATCH 15/18] Add test --- Lib/test/test_clinic.py | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index bc3fcd766e0cd3..ee23f9ec136baf 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -2219,7 +2219,33 @@ class Foo "" "" / """ expected_error = f"{annotation} method cannot define parameters" - self.expect_failure(block, expected_error, lineno=0) + + def test_duplicate_getset(self): + annotations = ["@getter", "@setter"] + for annotation in annotations: + with self.subTest(annotation=annotation): + block = f""" + module foo + class Foo "" "" + {annotation} + {annotation} + Foo.property -> int + """ + expected_error = f"Cannot apply {annotation} twice to the same function!" + self.expect_failure(block, expected_error, lineno=3) + + dup_annotations = [("@getter", "@setter"), ("@setter", "@getter")] + for dup in dup_annotations: + with self.subTest(dup=dup): + block = f""" + module foo + class Foo "" "" + {dup[0]} + {dup[1]} + Foo.property -> int + """ + expected_error = f"Cannot apply both @getter and @setter to the same function!" + self.expect_failure(block, expected_error, lineno=3) def test_duplicate_coexist(self): err = "Called @coexist twice" From 2510a350cbe51e4875932b83b3d8f9176570548e Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Wed, 13 Dec 2023 22:22:21 +0900 Subject: [PATCH 16/18] Address code review --- Lib/test/test_clinic.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index ee23f9ec136baf..b59b0ef56e8170 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -2234,6 +2234,7 @@ class Foo "" "" expected_error = f"Cannot apply {annotation} twice to the same function!" self.expect_failure(block, expected_error, lineno=3) + def test_getter_and_setter_disallowed_on_same_function(self): dup_annotations = [("@getter", "@setter"), ("@setter", "@getter")] for dup in dup_annotations: with self.subTest(dup=dup): From 53777dfd4f90c917ea6a20d5629e746e8e479768 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Wed, 13 Dec 2023 22:22:44 +0900 Subject: [PATCH 17/18] Update Lib/test/test_clinic.py Co-authored-by: Alex Waygood --- Lib/test/test_clinic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index b59b0ef56e8170..40c4ebcdf6f303 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -2245,7 +2245,7 @@ class Foo "" "" {dup[1]} Foo.property -> int """ - expected_error = f"Cannot apply both @getter and @setter to the same function!" + expected_error = "Cannot apply both @getter and @setter to the same function!" self.expect_failure(block, expected_error, lineno=3) def test_duplicate_coexist(self): From 61f7215993063c15249e639838ee49251b7fd191 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Wed, 13 Dec 2023 22:31:52 +0900 Subject: [PATCH 18/18] Fix --- Lib/test/test_clinic.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index 40c4ebcdf6f303..d3dbde88dd82a9 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -2219,6 +2219,7 @@ class Foo "" "" / """ expected_error = f"{annotation} method cannot define parameters" + self.expect_failure(block, expected_error) def test_duplicate_getset(self): annotations = ["@getter", "@setter"]