mirror of
https://github.com/python/cpython.git
synced 2025-10-03 05:35:59 +00:00
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
9 changed files with 262 additions and 64 deletions
|
@ -4956,8 +4956,12 @@ Test_meth_coexist_impl(TestObj *self)
|
||||||
Test.property
|
Test.property
|
||||||
[clinic start generated code]*/
|
[clinic start generated code]*/
|
||||||
|
|
||||||
#define TEST_PROPERTY_GETTERDEF \
|
#if defined(TEST_PROPERTY_GETSETDEF)
|
||||||
{"property", (getter)Test_property_get, NULL, NULL},
|
# 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 *
|
static PyObject *
|
||||||
Test_property_get_impl(TestObj *self);
|
Test_property_get_impl(TestObj *self);
|
||||||
|
@ -4970,8 +4974,32 @@ Test_property_get(TestObj *self, void *Py_UNUSED(context))
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
Test_property_get_impl(TestObj *self)
|
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]
|
/*[clinic input]
|
||||||
output push
|
output push
|
||||||
|
|
|
@ -2197,6 +2197,58 @@ class ClinicParserTest(TestCase):
|
||||||
expected_error = err_template.format(invalid_kind)
|
expected_error = err_template.format(invalid_kind)
|
||||||
self.expect_failure(block, expected_error, lineno=3)
|
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):
|
def test_duplicate_coexist(self):
|
||||||
err = "Called @coexist twice"
|
err = "Called @coexist twice"
|
||||||
block = """
|
block = """
|
||||||
|
|
|
@ -2526,9 +2526,9 @@ static PyMemberDef bufferedreader_members[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static PyGetSetDef bufferedreader_getset[] = {
|
static PyGetSetDef bufferedreader_getset[] = {
|
||||||
_IO__BUFFERED_CLOSED_GETTERDEF
|
_IO__BUFFERED_CLOSED_GETSETDEF
|
||||||
_IO__BUFFERED_NAME_GETTERDEF
|
_IO__BUFFERED_NAME_GETSETDEF
|
||||||
_IO__BUFFERED_MODE_GETTERDEF
|
_IO__BUFFERED_MODE_GETSETDEF
|
||||||
{NULL}
|
{NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2586,9 +2586,9 @@ static PyMemberDef bufferedwriter_members[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static PyGetSetDef bufferedwriter_getset[] = {
|
static PyGetSetDef bufferedwriter_getset[] = {
|
||||||
_IO__BUFFERED_CLOSED_GETTERDEF
|
_IO__BUFFERED_CLOSED_GETSETDEF
|
||||||
_IO__BUFFERED_NAME_GETTERDEF
|
_IO__BUFFERED_NAME_GETSETDEF
|
||||||
_IO__BUFFERED_MODE_GETTERDEF
|
_IO__BUFFERED_MODE_GETSETDEF
|
||||||
{NULL}
|
{NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2704,9 +2704,9 @@ static PyMemberDef bufferedrandom_members[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static PyGetSetDef bufferedrandom_getset[] = {
|
static PyGetSetDef bufferedrandom_getset[] = {
|
||||||
_IO__BUFFERED_CLOSED_GETTERDEF
|
_IO__BUFFERED_CLOSED_GETSETDEF
|
||||||
_IO__BUFFERED_NAME_GETTERDEF
|
_IO__BUFFERED_NAME_GETSETDEF
|
||||||
_IO__BUFFERED_MODE_GETTERDEF
|
_IO__BUFFERED_MODE_GETSETDEF
|
||||||
{NULL}
|
{NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
26
Modules/_io/clinic/bufferedio.c.h
generated
26
Modules/_io/clinic/bufferedio.c.h
generated
|
@ -327,8 +327,12 @@ _io__Buffered_simple_flush(buffered *self, PyObject *Py_UNUSED(ignored))
|
||||||
return return_value;
|
return return_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define _IO__BUFFERED_CLOSED_GETTERDEF \
|
#if defined(_IO__BUFFERED_CLOSED_GETSETDEF)
|
||||||
{"closed", (getter)_io__Buffered_closed_get, NULL, NULL},
|
# 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 *
|
static PyObject *
|
||||||
_io__Buffered_closed_get_impl(buffered *self);
|
_io__Buffered_closed_get_impl(buffered *self);
|
||||||
|
@ -460,8 +464,12 @@ _io__Buffered_writable(buffered *self, PyObject *Py_UNUSED(ignored))
|
||||||
return return_value;
|
return return_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define _IO__BUFFERED_NAME_GETTERDEF \
|
#if defined(_IO__BUFFERED_NAME_GETSETDEF)
|
||||||
{"name", (getter)_io__Buffered_name_get, NULL, NULL},
|
# 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 *
|
static PyObject *
|
||||||
_io__Buffered_name_get_impl(buffered *self);
|
_io__Buffered_name_get_impl(buffered *self);
|
||||||
|
@ -478,8 +486,12 @@ _io__Buffered_name_get(buffered *self, void *Py_UNUSED(context))
|
||||||
return return_value;
|
return return_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define _IO__BUFFERED_MODE_GETTERDEF \
|
#if defined(_IO__BUFFERED_MODE_GETSETDEF)
|
||||||
{"mode", (getter)_io__Buffered_mode_get, NULL, NULL},
|
# 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 *
|
static PyObject *
|
||||||
_io__Buffered_mode_get_impl(buffered *self);
|
_io__Buffered_mode_get_impl(buffered *self);
|
||||||
|
@ -1218,4 +1230,4 @@ skip_optional_pos:
|
||||||
exit:
|
exit:
|
||||||
return return_value;
|
return return_value;
|
||||||
}
|
}
|
||||||
/*[clinic end generated code: output=f21ed03255032b43 input=a9049054013a1b77]*/
|
/*[clinic end generated code: output=0999c33f666dc692 input=a9049054013a1b77]*/
|
||||||
|
|
26
Modules/_io/clinic/stringio.c.h
generated
26
Modules/_io/clinic/stringio.c.h
generated
|
@ -475,8 +475,12 @@ _io_StringIO___setstate__(stringio *self, PyObject *state)
|
||||||
return return_value;
|
return return_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define _IO_STRINGIO_CLOSED_GETTERDEF \
|
#if defined(_IO_STRINGIO_CLOSED_GETSETDEF)
|
||||||
{"closed", (getter)_io_StringIO_closed_get, NULL, NULL},
|
# 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 *
|
static PyObject *
|
||||||
_io_StringIO_closed_get_impl(stringio *self);
|
_io_StringIO_closed_get_impl(stringio *self);
|
||||||
|
@ -493,8 +497,12 @@ _io_StringIO_closed_get(stringio *self, void *Py_UNUSED(context))
|
||||||
return return_value;
|
return return_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define _IO_STRINGIO_LINE_BUFFERING_GETTERDEF \
|
#if defined(_IO_STRINGIO_LINE_BUFFERING_GETSETDEF)
|
||||||
{"line_buffering", (getter)_io_StringIO_line_buffering_get, NULL, NULL},
|
# 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 *
|
static PyObject *
|
||||||
_io_StringIO_line_buffering_get_impl(stringio *self);
|
_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;
|
return return_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define _IO_STRINGIO_NEWLINES_GETTERDEF \
|
#if defined(_IO_STRINGIO_NEWLINES_GETSETDEF)
|
||||||
{"newlines", (getter)_io_StringIO_newlines_get, NULL, NULL},
|
# 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 *
|
static PyObject *
|
||||||
_io_StringIO_newlines_get_impl(stringio *self);
|
_io_StringIO_newlines_get_impl(stringio *self);
|
||||||
|
@ -528,4 +540,4 @@ _io_StringIO_newlines_get(stringio *self, void *Py_UNUSED(context))
|
||||||
|
|
||||||
return return_value;
|
return return_value;
|
||||||
}
|
}
|
||||||
/*[clinic end generated code: output=3a92e8b6c322f61b input=a9049054013a1b77]*/
|
/*[clinic end generated code: output=27726751d98ab617 input=a9049054013a1b77]*/
|
||||||
|
|
46
Modules/_io/clinic/textio.c.h
generated
46
Modules/_io/clinic/textio.c.h
generated
|
@ -1047,4 +1047,48 @@ _io_TextIOWrapper_close(textio *self, PyObject *Py_UNUSED(ignored))
|
||||||
|
|
||||||
return return_value;
|
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[] = {
|
static PyGetSetDef stringio_getset[] = {
|
||||||
_IO_STRINGIO_CLOSED_GETTERDEF
|
_IO_STRINGIO_CLOSED_GETSETDEF
|
||||||
_IO_STRINGIO_NEWLINES_GETTERDEF
|
_IO_STRINGIO_NEWLINES_GETSETDEF
|
||||||
/* (following comments straight off of the original Python wrapper:)
|
/* (following comments straight off of the original Python wrapper:)
|
||||||
XXX Cruft to support the TextIOWrapper API. This would only
|
XXX Cruft to support the TextIOWrapper API. This would only
|
||||||
be meaningful if StringIO supported the buffer attribute.
|
be meaningful if StringIO supported the buffer attribute.
|
||||||
Hopefully, a better solution, than adding these pseudo-attributes,
|
Hopefully, a better solution, than adding these pseudo-attributes,
|
||||||
will be found.
|
will be found.
|
||||||
*/
|
*/
|
||||||
_IO_STRINGIO_LINE_BUFFERING_GETTERDEF
|
_IO_STRINGIO_LINE_BUFFERING_GETSETDEF
|
||||||
{NULL}
|
{NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -3238,33 +3238,37 @@ textiowrapper_errors_get(textio *self, void *context)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*[clinic input]
|
||||||
|
@critical_section
|
||||||
|
@getter
|
||||||
|
_io.TextIOWrapper._CHUNK_SIZE
|
||||||
|
[clinic start generated code]*/
|
||||||
|
|
||||||
static PyObject *
|
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);
|
CHECK_ATTACHED(self);
|
||||||
return PyLong_FromSsize_t(self->chunk_size);
|
return PyLong_FromSsize_t(self->chunk_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
/*[clinic input]
|
||||||
textiowrapper_chunk_size_get(textio *self, void *context)
|
@critical_section
|
||||||
{
|
@setter
|
||||||
PyObject *result = NULL;
|
_io.TextIOWrapper._CHUNK_SIZE
|
||||||
Py_BEGIN_CRITICAL_SECTION(self);
|
[clinic start generated code]*/
|
||||||
result = textiowrapper_chunk_size_get_impl(self, context);
|
|
||||||
Py_END_CRITICAL_SECTION();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
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;
|
Py_ssize_t n;
|
||||||
CHECK_ATTACHED_INT(self);
|
CHECK_ATTACHED_INT(self);
|
||||||
if (arg == NULL) {
|
if (value == NULL) {
|
||||||
PyErr_SetString(PyExc_AttributeError, "cannot delete attribute");
|
PyErr_SetString(PyExc_AttributeError, "cannot delete attribute");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
n = PyNumber_AsSsize_t(arg, PyExc_ValueError);
|
n = PyNumber_AsSsize_t(value, PyExc_ValueError);
|
||||||
if (n == -1 && PyErr_Occurred())
|
if (n == -1 && PyErr_Occurred())
|
||||||
return -1;
|
return -1;
|
||||||
if (n <= 0) {
|
if (n <= 0) {
|
||||||
|
@ -3276,16 +3280,6 @@ textiowrapper_chunk_size_set_impl(textio *self, PyObject *arg, void *context)
|
||||||
return 0;
|
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[] = {
|
static PyMethodDef incrementalnewlinedecoder_methods[] = {
|
||||||
_IO_INCREMENTALNEWLINEDECODER_DECODE_METHODDEF
|
_IO_INCREMENTALNEWLINEDECODER_DECODE_METHODDEF
|
||||||
_IO_INCREMENTALNEWLINEDECODER_GETSTATE_METHODDEF
|
_IO_INCREMENTALNEWLINEDECODER_GETSTATE_METHODDEF
|
||||||
|
@ -3361,8 +3355,7 @@ static PyGetSetDef textiowrapper_getset[] = {
|
||||||
*/
|
*/
|
||||||
{"newlines", (getter)textiowrapper_newlines_get, NULL, NULL},
|
{"newlines", (getter)textiowrapper_newlines_get, NULL, NULL},
|
||||||
{"errors", (getter)textiowrapper_errors_get, NULL, NULL},
|
{"errors", (getter)textiowrapper_errors_get, NULL, NULL},
|
||||||
{"_CHUNK_SIZE", (getter)textiowrapper_chunk_size_get,
|
_IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETDEF
|
||||||
(setter)textiowrapper_chunk_size_set, NULL},
|
|
||||||
{NULL}
|
{NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -850,6 +850,10 @@ class CLanguage(Language):
|
||||||
static PyObject *
|
static PyObject *
|
||||||
{c_basename}({self_type}{self_name}, void *Py_UNUSED(context))
|
{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("""
|
METH_O_PROTOTYPE: Final[str] = normalize_snippet("""
|
||||||
static PyObject *
|
static PyObject *
|
||||||
{c_basename}({impl_parameters})
|
{c_basename}({impl_parameters})
|
||||||
|
@ -870,8 +874,20 @@ class CLanguage(Language):
|
||||||
{{"{name}", {methoddef_cast}{c_basename}{methoddef_cast_end}, {methoddef_flags}, {c_basename}__doc__}},
|
{{"{name}", {methoddef_cast}{c_basename}{methoddef_cast_end}, {methoddef_flags}, {c_basename}__doc__}},
|
||||||
""")
|
""")
|
||||||
GETTERDEF_PROTOTYPE_DEFINE: Final[str] = normalize_snippet(r"""
|
GETTERDEF_PROTOTYPE_DEFINE: Final[str] = normalize_snippet(r"""
|
||||||
#define {getter_name} \
|
#if defined({getset_name}_GETSETDEF)
|
||||||
{{"{name}", (getter){c_basename}, NULL, NULL}},
|
# 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("""
|
METHODDEF_PROTOTYPE_IFNDEF: Final[str] = normalize_snippet("""
|
||||||
#ifndef {methoddef_name}
|
#ifndef {methoddef_name}
|
||||||
|
@ -1172,6 +1188,10 @@ class CLanguage(Language):
|
||||||
elif f.kind is GETTER:
|
elif f.kind is GETTER:
|
||||||
methoddef_define = self.GETTERDEF_PROTOTYPE_DEFINE
|
methoddef_define = self.GETTERDEF_PROTOTYPE_DEFINE
|
||||||
docstring_prototype = docstring_definition = ''
|
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:
|
else:
|
||||||
docstring_prototype = self.DOCSTRING_PROTOTYPE_VAR
|
docstring_prototype = self.DOCSTRING_PROTOTYPE_VAR
|
||||||
docstring_definition = self.DOCSTRING_PROTOTYPE_STRVAR
|
docstring_definition = self.DOCSTRING_PROTOTYPE_STRVAR
|
||||||
|
@ -1226,12 +1246,19 @@ class CLanguage(Language):
|
||||||
limited_capi = False
|
limited_capi = False
|
||||||
|
|
||||||
parsearg: str | None
|
parsearg: str | None
|
||||||
|
if f.kind in {GETTER, SETTER} and parameters:
|
||||||
|
fail(f"@{f.kind.name.lower()} method cannot define parameters")
|
||||||
|
|
||||||
if not parameters:
|
if not parameters:
|
||||||
parser_code: list[str] | None
|
parser_code: list[str] | None
|
||||||
if f.kind is GETTER:
|
if f.kind is GETTER:
|
||||||
flags = "" # This should end up unused
|
flags = "" # This should end up unused
|
||||||
parser_prototype = self.PARSER_PROTOTYPE_GETTER
|
parser_prototype = self.PARSER_PROTOTYPE_GETTER
|
||||||
parser_code = []
|
parser_code = []
|
||||||
|
elif f.kind is SETTER:
|
||||||
|
flags = ""
|
||||||
|
parser_prototype = self.PARSER_PROTOTYPE_SETTER
|
||||||
|
parser_code = []
|
||||||
elif not requires_defining_class:
|
elif not requires_defining_class:
|
||||||
# no parameters, METH_NOARGS
|
# no parameters, METH_NOARGS
|
||||||
flags = "METH_NOARGS"
|
flags = "METH_NOARGS"
|
||||||
|
@ -1944,9 +1971,16 @@ class CLanguage(Language):
|
||||||
full_name = f.full_name
|
full_name = f.full_name
|
||||||
template_dict = {'full_name': full_name}
|
template_dict = {'full_name': full_name}
|
||||||
template_dict['name'] = f.displayname
|
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:
|
if f.kind is GETTER:
|
||||||
template_dict['getter_name'] = f.c_basename.upper() + "_GETTERDEF"
|
|
||||||
template_dict['c_basename'] = f.c_basename + "_get"
|
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:
|
else:
|
||||||
template_dict['methoddef_name'] = f.c_basename.upper() + "_METHODDEF"
|
template_dict['methoddef_name'] = f.c_basename.upper() + "_METHODDEF"
|
||||||
template_dict['c_basename'] = f.c_basename
|
template_dict['c_basename'] = f.c_basename
|
||||||
|
@ -1959,6 +1993,10 @@ class CLanguage(Language):
|
||||||
converter.set_template_dict(template_dict)
|
converter.set_template_dict(template_dict)
|
||||||
|
|
||||||
f.return_converter.render(f, data)
|
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['impl_return_type'] = f.return_converter.type
|
||||||
|
|
||||||
template_dict['declarations'] = format_escape("\n".join(data.declarations))
|
template_dict['declarations'] = format_escape("\n".join(data.declarations))
|
||||||
|
@ -2954,6 +2992,7 @@ class FunctionKind(enum.Enum):
|
||||||
METHOD_INIT = enum.auto()
|
METHOD_INIT = enum.auto()
|
||||||
METHOD_NEW = enum.auto()
|
METHOD_NEW = enum.auto()
|
||||||
GETTER = enum.auto()
|
GETTER = enum.auto()
|
||||||
|
SETTER = enum.auto()
|
||||||
|
|
||||||
@functools.cached_property
|
@functools.cached_property
|
||||||
def new_or_init(self) -> bool:
|
def new_or_init(self) -> bool:
|
||||||
|
@ -2970,6 +3009,7 @@ CLASS_METHOD: Final = FunctionKind.CLASS_METHOD
|
||||||
METHOD_INIT: Final = FunctionKind.METHOD_INIT
|
METHOD_INIT: Final = FunctionKind.METHOD_INIT
|
||||||
METHOD_NEW: Final = FunctionKind.METHOD_NEW
|
METHOD_NEW: Final = FunctionKind.METHOD_NEW
|
||||||
GETTER: Final = FunctionKind.GETTER
|
GETTER: Final = FunctionKind.GETTER
|
||||||
|
SETTER: Final = FunctionKind.SETTER
|
||||||
|
|
||||||
ParamDict = dict[str, "Parameter"]
|
ParamDict = dict[str, "Parameter"]
|
||||||
ReturnConverterType = Callable[..., "CReturnConverter"]
|
ReturnConverterType = Callable[..., "CReturnConverter"]
|
||||||
|
@ -3056,7 +3096,7 @@ class Function:
|
||||||
case FunctionKind.STATIC_METHOD:
|
case FunctionKind.STATIC_METHOD:
|
||||||
flags.append('METH_STATIC')
|
flags.append('METH_STATIC')
|
||||||
case _ as kind:
|
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}"
|
assert kind in acceptable_kinds, f"unknown kind: {kind!r}"
|
||||||
if self.coexist:
|
if self.coexist:
|
||||||
flags.append('METH_COEXIST')
|
flags.append('METH_COEXIST')
|
||||||
|
@ -4702,7 +4742,7 @@ class Py_buffer_converter(CConverter):
|
||||||
def correct_name_for_self(
|
def correct_name_for_self(
|
||||||
f: Function
|
f: Function
|
||||||
) -> tuple[str, str]:
|
) -> tuple[str, str]:
|
||||||
if f.kind in {CALLABLE, METHOD_INIT, GETTER}:
|
if f.kind in {CALLABLE, METHOD_INIT, GETTER, SETTER}:
|
||||||
if f.cls:
|
if f.cls:
|
||||||
return "PyObject *", "self"
|
return "PyObject *", "self"
|
||||||
return "PyObject *", "module"
|
return "PyObject *", "module"
|
||||||
|
@ -5335,7 +5375,22 @@ class DSLParser:
|
||||||
self.critical_section = True
|
self.critical_section = True
|
||||||
|
|
||||||
def at_getter(self) -> None:
|
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:
|
def at_staticmethod(self) -> None:
|
||||||
if self.kind is not CALLABLE:
|
if self.kind is not CALLABLE:
|
||||||
|
@ -5536,6 +5591,8 @@ class DSLParser:
|
||||||
|
|
||||||
return_converter = None
|
return_converter = None
|
||||||
if returns:
|
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"
|
ast_input = f"def x() -> {returns}: pass"
|
||||||
try:
|
try:
|
||||||
module_node = ast.parse(ast_input)
|
module_node = ast.parse(ast_input)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue