Skip to content

Commit 6ad31bb

Browse files
corona10erlend-aaslandAlexWaygood
authored andcommitted
pythongh-112205: Support @setter annotation from AC (pythongh-112922)
--------- Co-authored-by: Erlend E. Aasland <erlend.aasland@protonmail.com> Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
1 parent d3f9166 commit 6ad31bb

File tree

9 files changed

+262
-64
lines changed

9 files changed

+262
-64
lines changed

Lib/test/clinic.test.c

+31-3
Original file line numberDiff line numberDiff line change
@@ -4956,8 +4956,12 @@ Test_meth_coexist_impl(TestObj *self)
49564956
Test.property
49574957
[clinic start generated code]*/
49584958

4959-
#define TEST_PROPERTY_GETTERDEF \
4960-
{"property", (getter)Test_property_get, NULL, NULL},
4959+
#if defined(TEST_PROPERTY_GETSETDEF)
4960+
# undef TEST_PROPERTY_GETSETDEF
4961+
# define TEST_PROPERTY_GETSETDEF {"property", (getter)Test_property_get, (setter)Test_property_set, NULL},
4962+
#else
4963+
# define TEST_PROPERTY_GETSETDEF {"property", (getter)Test_property_get, NULL, NULL},
4964+
#endif
49614965

49624966
static PyObject *
49634967
Test_property_get_impl(TestObj *self);
@@ -4970,8 +4974,32 @@ Test_property_get(TestObj *self, void *Py_UNUSED(context))
49704974

49714975
static PyObject *
49724976
Test_property_get_impl(TestObj *self)
4973-
/*[clinic end generated code: output=892b6fb351ff85fd input=2d92b3449fbc7d2b]*/
4977+
/*[clinic end generated code: output=af8140b692e0e2f1 input=2d92b3449fbc7d2b]*/
4978+
4979+
/*[clinic input]
4980+
@setter
4981+
Test.property
4982+
[clinic start generated code]*/
4983+
4984+
#if defined(TEST_PROPERTY_GETSETDEF)
4985+
# undef TEST_PROPERTY_GETSETDEF
4986+
# define TEST_PROPERTY_GETSETDEF {"property", (getter)Test_property_get, (setter)Test_property_set, NULL},
4987+
#else
4988+
# define TEST_PROPERTY_GETSETDEF {"property", NULL, (setter)Test_property_set, NULL},
4989+
#endif
4990+
4991+
static int
4992+
Test_property_set_impl(TestObj *self, PyObject *value);
4993+
4994+
static int
4995+
Test_property_set(TestObj *self, PyObject *value, void *Py_UNUSED(context))
4996+
{
4997+
return Test_property_set_impl(self, value);
4998+
}
49744999

5000+
static int
5001+
Test_property_set_impl(TestObj *self, PyObject *value)
5002+
/*[clinic end generated code: output=f3eba6487d7550e2 input=3bc3f46a23c83a88]*/
49755003

49765004
/*[clinic input]
49775005
output push

Lib/test/test_clinic.py

+52
Original file line numberDiff line numberDiff line change
@@ -2197,6 +2197,58 @@ class Foo "" ""
21972197
expected_error = err_template.format(invalid_kind)
21982198
self.expect_failure(block, expected_error, lineno=3)
21992199

2200+
def test_invalid_getset(self):
2201+
annotations = ["@getter", "@setter"]
2202+
for annotation in annotations:
2203+
with self.subTest(annotation=annotation):
2204+
block = f"""
2205+
module foo
2206+
class Foo "" ""
2207+
{annotation}
2208+
Foo.property -> int
2209+
"""
2210+
expected_error = f"{annotation} method cannot define a return type"
2211+
self.expect_failure(block, expected_error, lineno=3)
2212+
2213+
block = f"""
2214+
module foo
2215+
class Foo "" ""
2216+
{annotation}
2217+
Foo.property
2218+
obj: int
2219+
/
2220+
"""
2221+
expected_error = f"{annotation} method cannot define parameters"
2222+
self.expect_failure(block, expected_error)
2223+
2224+
def test_duplicate_getset(self):
2225+
annotations = ["@getter", "@setter"]
2226+
for annotation in annotations:
2227+
with self.subTest(annotation=annotation):
2228+
block = f"""
2229+
module foo
2230+
class Foo "" ""
2231+
{annotation}
2232+
{annotation}
2233+
Foo.property -> int
2234+
"""
2235+
expected_error = f"Cannot apply {annotation} twice to the same function!"
2236+
self.expect_failure(block, expected_error, lineno=3)
2237+
2238+
def test_getter_and_setter_disallowed_on_same_function(self):
2239+
dup_annotations = [("@getter", "@setter"), ("@setter", "@getter")]
2240+
for dup in dup_annotations:
2241+
with self.subTest(dup=dup):
2242+
block = f"""
2243+
module foo
2244+
class Foo "" ""
2245+
{dup[0]}
2246+
{dup[1]}
2247+
Foo.property -> int
2248+
"""
2249+
expected_error = "Cannot apply both @getter and @setter to the same function!"
2250+
self.expect_failure(block, expected_error, lineno=3)
2251+
22002252
def test_duplicate_coexist(self):
22012253
err = "Called @coexist twice"
22022254
block = """

Modules/_io/bufferedio.c

+9-9
Original file line numberDiff line numberDiff line change
@@ -2526,9 +2526,9 @@ static PyMemberDef bufferedreader_members[] = {
25262526
};
25272527

25282528
static PyGetSetDef bufferedreader_getset[] = {
2529-
_IO__BUFFERED_CLOSED_GETTERDEF
2530-
_IO__BUFFERED_NAME_GETTERDEF
2531-
_IO__BUFFERED_MODE_GETTERDEF
2529+
_IO__BUFFERED_CLOSED_GETSETDEF
2530+
_IO__BUFFERED_NAME_GETSETDEF
2531+
_IO__BUFFERED_MODE_GETSETDEF
25322532
{NULL}
25332533
};
25342534

@@ -2586,9 +2586,9 @@ static PyMemberDef bufferedwriter_members[] = {
25862586
};
25872587

25882588
static PyGetSetDef bufferedwriter_getset[] = {
2589-
_IO__BUFFERED_CLOSED_GETTERDEF
2590-
_IO__BUFFERED_NAME_GETTERDEF
2591-
_IO__BUFFERED_MODE_GETTERDEF
2589+
_IO__BUFFERED_CLOSED_GETSETDEF
2590+
_IO__BUFFERED_NAME_GETSETDEF
2591+
_IO__BUFFERED_MODE_GETSETDEF
25922592
{NULL}
25932593
};
25942594

@@ -2704,9 +2704,9 @@ static PyMemberDef bufferedrandom_members[] = {
27042704
};
27052705

27062706
static PyGetSetDef bufferedrandom_getset[] = {
2707-
_IO__BUFFERED_CLOSED_GETTERDEF
2708-
_IO__BUFFERED_NAME_GETTERDEF
2709-
_IO__BUFFERED_MODE_GETTERDEF
2707+
_IO__BUFFERED_CLOSED_GETSETDEF
2708+
_IO__BUFFERED_NAME_GETSETDEF
2709+
_IO__BUFFERED_MODE_GETSETDEF
27102710
{NULL}
27112711
};
27122712

Modules/_io/clinic/bufferedio.c.h

+19-7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/_io/clinic/stringio.c.h

+19-7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/_io/clinic/textio.c.h

+45-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/_io/stringio.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -1037,15 +1037,15 @@ static struct PyMethodDef stringio_methods[] = {
10371037
};
10381038

10391039
static PyGetSetDef stringio_getset[] = {
1040-
_IO_STRINGIO_CLOSED_GETTERDEF
1041-
_IO_STRINGIO_NEWLINES_GETTERDEF
1040+
_IO_STRINGIO_CLOSED_GETSETDEF
1041+
_IO_STRINGIO_NEWLINES_GETSETDEF
10421042
/* (following comments straight off of the original Python wrapper:)
10431043
XXX Cruft to support the TextIOWrapper API. This would only
10441044
be meaningful if StringIO supported the buffer attribute.
10451045
Hopefully, a better solution, than adding these pseudo-attributes,
10461046
will be found.
10471047
*/
1048-
_IO_STRINGIO_LINE_BUFFERING_GETTERDEF
1048+
_IO_STRINGIO_LINE_BUFFERING_GETSETDEF
10491049
{NULL}
10501050
};
10511051

Modules/_io/textio.c

+18-25
Original file line numberDiff line numberDiff line change
@@ -3238,33 +3238,37 @@ textiowrapper_errors_get(textio *self, void *context)
32383238
return result;
32393239
}
32403240

3241+
/*[clinic input]
3242+
@critical_section
3243+
@getter
3244+
_io.TextIOWrapper._CHUNK_SIZE
3245+
[clinic start generated code]*/
3246+
32413247
static PyObject *
3242-
textiowrapper_chunk_size_get_impl(textio *self, void *context)
3248+
_io_TextIOWrapper__CHUNK_SIZE_get_impl(textio *self)
3249+
/*[clinic end generated code: output=039925cd2df375bc input=e9715b0e06ff0fa6]*/
32433250
{
32443251
CHECK_ATTACHED(self);
32453252
return PyLong_FromSsize_t(self->chunk_size);
32463253
}
32473254

3248-
static PyObject *
3249-
textiowrapper_chunk_size_get(textio *self, void *context)
3250-
{
3251-
PyObject *result = NULL;
3252-
Py_BEGIN_CRITICAL_SECTION(self);
3253-
result = textiowrapper_chunk_size_get_impl(self, context);
3254-
Py_END_CRITICAL_SECTION();
3255-
return result;
3256-
}
3255+
/*[clinic input]
3256+
@critical_section
3257+
@setter
3258+
_io.TextIOWrapper._CHUNK_SIZE
3259+
[clinic start generated code]*/
32573260

32583261
static int
3259-
textiowrapper_chunk_size_set_impl(textio *self, PyObject *arg, void *context)
3262+
_io_TextIOWrapper__CHUNK_SIZE_set_impl(textio *self, PyObject *value)
3263+
/*[clinic end generated code: output=edb86d2db660a5ab input=32fc99861db02a0a]*/
32603264
{
32613265
Py_ssize_t n;
32623266
CHECK_ATTACHED_INT(self);
3263-
if (arg == NULL) {
3267+
if (value == NULL) {
32643268
PyErr_SetString(PyExc_AttributeError, "cannot delete attribute");
32653269
return -1;
32663270
}
3267-
n = PyNumber_AsSsize_t(arg, PyExc_ValueError);
3271+
n = PyNumber_AsSsize_t(value, PyExc_ValueError);
32683272
if (n == -1 && PyErr_Occurred())
32693273
return -1;
32703274
if (n <= 0) {
@@ -3276,16 +3280,6 @@ textiowrapper_chunk_size_set_impl(textio *self, PyObject *arg, void *context)
32763280
return 0;
32773281
}
32783282

3279-
static int
3280-
textiowrapper_chunk_size_set(textio *self, PyObject *arg, void *context)
3281-
{
3282-
int result = 0;
3283-
Py_BEGIN_CRITICAL_SECTION(self);
3284-
result = textiowrapper_chunk_size_set_impl(self, arg, context);
3285-
Py_END_CRITICAL_SECTION();
3286-
return result;
3287-
}
3288-
32893283
static PyMethodDef incrementalnewlinedecoder_methods[] = {
32903284
_IO_INCREMENTALNEWLINEDECODER_DECODE_METHODDEF
32913285
_IO_INCREMENTALNEWLINEDECODER_GETSTATE_METHODDEF
@@ -3361,8 +3355,7 @@ static PyGetSetDef textiowrapper_getset[] = {
33613355
*/
33623356
{"newlines", (getter)textiowrapper_newlines_get, NULL, NULL},
33633357
{"errors", (getter)textiowrapper_errors_get, NULL, NULL},
3364-
{"_CHUNK_SIZE", (getter)textiowrapper_chunk_size_get,
3365-
(setter)textiowrapper_chunk_size_set, NULL},
3358+
_IO_TEXTIOWRAPPER__CHUNK_SIZE_GETSETDEF
33663359
{NULL}
33673360
};
33683361

0 commit comments

Comments
 (0)