@@ -1419,24 +1419,32 @@ The generated glue code looks like this:
14191419.. code-block :: c
14201420
14211421 static PyObject *
1422- _io_TextIOWrapper__CHUNK_SIZE_get(textio *self, void *Py_UNUSED(context))
1422+ _io_TextIOWrapper__CHUNK_SIZE_get(PyObject *self, void *Py_UNUSED(context))
14231423 {
14241424 PyObject *return_value = NULL;
14251425
14261426 Py_BEGIN_CRITICAL_SECTION(self);
1427- return_value = _io_TextIOWrapper__CHUNK_SIZE_get_impl(self);
1427+ return_value = _io_TextIOWrapper__CHUNK_SIZE_get_impl((textio *) self);
14281428 Py_END_CRITICAL_SECTION();
14291429
14301430 return return_value;
14311431 }
14321432
14331433 static int
1434- _io_TextIOWrapper__CHUNK_SIZE_set(textio *self, PyObject *value, void *Py_UNUSED(context))
1434+ _io_TextIOWrapper__CHUNK_SIZE_set(PyObject *self, PyObject *value, void *Py_UNUSED(context))
14351435 {
14361436 int return_value;
1437+
1438+ if (value == NULL) {
1439+ PyErr_Format(PyExc_AttributeError,
1440+ "attribute '_CHUNK_SIZE' of '%.100s' objects cannot be deleted",
1441+ Py_TYPE(self)->tp_name);
1442+ return -1;
1443+ }
14371444 Py_BEGIN_CRITICAL_SECTION(self);
1438- return_value = _io_TextIOWrapper__CHUNK_SIZE_set_impl(self, value);
1445+ return_value = _io_TextIOWrapper__CHUNK_SIZE_set_impl((textio *) self, value);
14391446 Py_END_CRITICAL_SECTION();
1447+
14401448 return return_value;
14411449 }
14421450
@@ -1446,6 +1454,45 @@ The generated glue code looks like this:
14461454 The *value * parameter for a "setter" is added implicitly by Argument Clinic.
14471455 It is possible to create a docstring for the property by adding it to
14481456 the ``@getter ``.
1457+ The accessors of the same attribute must share the C basename;
1458+ declaring the same accessor twice is an error.
1459+
1460+ The setter slot of :c:type: `PyGetSetDef ` is used both for setting and for
1461+ deleting the attribute: the setter is called with ``NULL `` as the value to
1462+ delete it.
1463+ As shown above, the generated setter rejects the deletion with an
1464+ :exc: `AttributeError ` before calling the "impl" function.
1465+
1466+ If the attribute can be deleted, add the ``@deleter `` directive after
1467+ ``@setter ``.
1468+ The "impl" function is then called with ``NULL `` and is responsible for
1469+ handling this case, as in this example taken from
1470+ :cpy-file: `Objects/funcobject.c `::
1471+
1472+ /*[clinic input]
1473+ @critical_section
1474+ @setter
1475+ @deleter
1476+ function.__annotations__
1477+ [clinic start generated code]*/
1478+
1479+ .. code-block :: c
1480+
1481+ static int
1482+ function___annotations___set_impl(PyFunctionObject *self, PyObject *value)
1483+ {
1484+ if (value == Py_None)
1485+ value = NULL;
1486+ /* Legal to del f.func_annotations.
1487+ * Can only set func_annotations to NULL (through C api)
1488+ * or a dict. */
1489+ if (value != NULL && !PyDict_Check(value)) {
1490+ PyErr_SetString(PyExc_TypeError,
1491+ "__annotations__ must be set to a dict object");
1492+ return -1;
1493+ }
1494+ ...
1495+ }
14491496
14501497 And then the implementation will work the same as a Python method which is
14511498decorated by :py:class: `property `:
0 commit comments