Skip to content

Commit 708aa7c

Browse files
Argument Clinic: document deletion of an attribute and @deleter (GH-1886)
Also update the example of the generated code.
1 parent 3f36f40 commit 708aa7c

1 file changed

Lines changed: 51 additions & 4 deletions

File tree

development-tools/clinic/howto.rst

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -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
14511498
decorated by :py:class:`property`:

0 commit comments

Comments
 (0)