mirror of https://github.com/python/cpython
gh-112205: Support `@setter` annotation from AC (gh-112922)
--------- Co-authored-by: Erlend E. Aasland <erlend.aasland@protonmail.com> Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
This commit is contained in:
parent
9263173280
commit
498a096a51
|
@ -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_GETSETDEF)
|
||||
# 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},
|
||||
#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=af8140b692e0e2f1 input=2d92b3449fbc7d2b]*/
|
||||
|
||||
/*[clinic input]
|
||||
@setter
|
||||
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},
|
||||
#else
|
||||
# define TEST_PROPERTY_GETSETDEF {"property", NULL, (setter)Test_property_set, NULL},
|
||||
#endif
|
||||
|
||||
static int
|
||||
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);
|
||||
}
|
||||
|
||||
static int
|
||||
Test_property_set_impl(TestObj *self, PyObject *value)
|
||||
/*[clinic end generated code: output=f3eba6487d7550e2 input=3bc3f46a23c83a88]*/
|
||||
|
||||
/*[clinic input]
|
||||
output push
|
||||
|
|
|
@ -2197,6 +2197,58 @@ class ClinicParserTest(TestCase):
|
|||
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 = f"{annotation} method cannot define a return type"
|
||||
self.expect_failure(block, expected_error, lineno=3)
|
||||
|
||||
block = f"""
|
||||
module foo
|
||||
class Foo "" ""
|
||||
{annotation}
|
||||
Foo.property
|
||||
obj: int
|
||||
/
|
||||
"""
|
||||
expected_error = f"{annotation} method cannot define parameters"
|
||||
self.expect_failure(block, expected_error)
|
||||
|
||||
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)
|
||||
|
||||
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):
|
||||
block = f"""
|
||||
module foo
|
||||
class Foo "" ""
|
||||
{dup[0]}
|
||||
{dup[1]}
|
||||
Foo.property -> int
|
||||
"""
|
||||
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):
|
||||
err = "Called @coexist twice"
|
||||
block = """
|
||||
|
|
|
@ -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_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_GETTERDEF
|
||||
_IO__BUFFERED_NAME_GETTERDEF
|
||||
_IO__BUFFERED_MODE_GETTERDEF
|
||||
_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_GETTERDEF
|
||||
_IO__BUFFERED_NAME_GETTERDEF
|
||||
_IO__BUFFERED_MODE_GETTERDEF
|
||||
_IO__BUFFERED_CLOSED_GETSETDEF
|
||||
_IO__BUFFERED_NAME_GETSETDEF
|
||||
_IO__BUFFERED_MODE_GETSETDEF
|
||||
{NULL}
|
||||
};
|
||||
|
||||
|
|
|
@ -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_GETSETDEF)
|
||||
# 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},
|
||||
#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_GETSETDEF)
|
||||
# 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},
|
||||
#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_GETSETDEF)
|
||||
# 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},
|
||||
#endif
|
||||
|
||||
static PyObject *
|
||||
_io__Buffered_mode_get_impl(buffered *self);
|
||||
|
@ -1218,4 +1230,4 @@ skip_optional_pos:
|
|||
exit:
|
||||
return return_value;
|
||||
}
|
||||
/*[clinic end generated code: output=f21ed03255032b43 input=a9049054013a1b77]*/
|
||||
/*[clinic end generated code: output=0999c33f666dc692 input=a9049054013a1b77]*/
|
||||
|
|
|
@ -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_GETSETDEF)
|
||||
# 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},
|
||||
#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_GETSETDEF)
|
||||
# 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},
|
||||
#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_GETSETDEF)
|
||||
# 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},
|
||||
#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=27726751d98ab617 input=a9049054013a1b77]*/
|
||||
|
|
|
@ -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_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_GETSETDEF {"_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_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_GETSETDEF {"_CHUNK_SIZE", NULL, (setter)_io_TextIOWrapper__CHUNK_SIZE_set, NULL},
|
||||
#endif
|
||||
|
||||
static int
|
||||
_io_TextIOWrapper__CHUNK_SIZE_set_impl(textio *self, PyObject *value);
|
||||
|
||||
static int
|
||||
_io_TextIOWrapper__CHUNK_SIZE_set(textio *self, PyObject *value, void *Py_UNUSED(context))
|
||||
{
|
||||
int return_value;
|
||||
|
||||
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=b312f2d2e2221580 input=a9049054013a1b77]*/
|
||||
|
|
|
@ -1037,15 +1037,15 @@ static struct PyMethodDef stringio_methods[] = {
|
|||
};
|
||||
|
||||
static PyGetSetDef stringio_getset[] = {
|
||||
_IO_STRINGIO_CLOSED_GETTERDEF
|
||||
_IO_STRINGIO_NEWLINES_GETTERDEF
|
||||
_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_GETTERDEF
|
||||
_IO_STRINGIO_LINE_BUFFERING_GETSETDEF
|
||||
{NULL}
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
||||
_io_TextIOWrapper__CHUNK_SIZE_set_impl(textio *self, PyObject *value)
|
||||
/*[clinic end generated code: output=edb86d2db660a5ab 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_GETSETDEF
|
||||
{NULL}
|
||||
};
|
||||
|
||||
|
|
|
@ -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 int
|
||||
{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({getset_name}_GETSETDEF)
|
||||
# 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}},
|
||||
#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}},
|
||||
#else
|
||||
# define {getset_name}_GETSETDEF {{"{name}", NULL, (setter){getset_basename}_set, NULL}},
|
||||
#endif
|
||||
""")
|
||||
METHODDEF_PROTOTYPE_IFNDEF: Final[str] = normalize_snippet("""
|
||||
#ifndef {methoddef_name}
|
||||
|
@ -1172,6 +1188,10 @@ class CLanguage(Language):
|
|||
elif f.kind is GETTER:
|
||||
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:
|
||||
docstring_prototype = self.DOCSTRING_PROTOTYPE_VAR
|
||||
docstring_definition = self.DOCSTRING_PROTOTYPE_STRVAR
|
||||
|
@ -1226,12 +1246,19 @@ class CLanguage(Language):
|
|||
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:
|
||||
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 +1971,16 @@ class CLanguage(Language):
|
|||
full_name = f.full_name
|
||||
template_dict = {'full_name': full_name}
|
||||
template_dict['name'] = f.displayname
|
||||
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:
|
||||
template_dict['getter_name'] = f.c_basename.upper() + "_GETTERDEF"
|
||||
template_dict['c_basename'] = f.c_basename + "_get"
|
||||
elif f.kind is SETTER:
|
||||
template_dict['c_basename'] = f.c_basename + "_set"
|
||||
# Implicitly add the setter value parameter.
|
||||
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
|
||||
|
@ -1959,6 +1993,10 @@ class CLanguage(Language):
|
|||
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
|
||||
|
||||
template_dict['declarations'] = format_escape("\n".join(data.declarations))
|
||||
|
@ -2954,6 +2992,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 +3009,7 @@ CLASS_METHOD: Final = FunctionKind.CLASS_METHOD
|
|||
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 +3096,7 @@ class Function:
|
|||
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 +4742,7 @@ class Py_buffer_converter(CConverter):
|
|||
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,7 +5375,22 @@ class DSLParser:
|
|||
self.critical_section = True
|
||||
|
||||
def at_getter(self) -> None:
|
||||
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:
|
||||
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:
|
||||
|
@ -5536,6 +5591,8 @@ class DSLParser:
|
|||
|
||||
return_converter = None
|
||||
if returns:
|
||||
if self.kind in {GETTER, SETTER}:
|
||||
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)
|
||||
|
|
Loading…
Reference in New Issue