@@ -1397,65 +1397,108 @@ that facilitate :py:class:`property`-like access for a class.
13971397You can use the ``@getter `` and ``@setter `` directives to generate
13981398"impl" functions using Argument Clinic.
13991399
1400- This example --- taken from :cpy-file: `Modules/_io/textio .c ` ---
1400+ This example --- taken from :cpy-file: `Modules/_ssl .c ` ---
14011401shows the use of ``@getter `` and ``@setter `` in combination with
14021402the :ref: `@critical_section <clinic-howto-critical-sections >` directive
14031403(which achieves thread safety without causing deadlocks between threads)::
14041404
14051405 /*[clinic input]
14061406 @critical_section
14071407 @getter
1408- _io.TextIOWrapper._CHUNK_SIZE
1408+ _ssl._SSLContext.check_hostname -> bool
14091409 [clinic start generated code]*/
14101410
14111411 /*[clinic input]
14121412 @critical_section
14131413 @setter
1414- _io.TextIOWrapper._CHUNK_SIZE
1414+ _ssl._SSLContext.check_hostname
1415+ value: bool
14151416 [clinic start generated code]*/
14161417
14171418The generated glue code looks like this:
14181419
14191420.. code-block :: c
14201421
14211422 static PyObject *
1422- _io_TextIOWrapper__CHUNK_SIZE_get (PyObject *self, void *Py_UNUSED(context))
1423+ _ssl__SSLContext_check_hostname_get (PyObject *self, void *Py_UNUSED(context))
14231424 {
14241425 PyObject *return_value = NULL;
1426+ int _return_value;
14251427
14261428 Py_BEGIN_CRITICAL_SECTION(self);
1427- return_value = _io_TextIOWrapper__CHUNK_SIZE_get_impl((textio *)self);
1429+ _return_value = _ssl__SSLContext_check_hostname_get_impl((PySSLContext *)self);
14281430 Py_END_CRITICAL_SECTION();
1431+ if ((_return_value == -1) && PyErr_Occurred()) {
1432+ goto exit;
1433+ }
1434+ return_value = PyBool_FromLong((long)_return_value);
14291435
1436+ exit:
14301437 return return_value;
14311438 }
14321439
14331440 static int
1434- _io_TextIOWrapper__CHUNK_SIZE_set (PyObject *self, PyObject *value , void *Py_UNUSED(context))
1441+ _ssl__SSLContext_check_hostname_set (PyObject *self, PyObject *arg , void *Py_UNUSED(context))
14351442 {
1436- int return_value;
1443+ int return_value = -1;
1444+ int value;
14371445
1438- if (value == NULL) {
1446+ if (arg == NULL) {
14391447 PyErr_Format(PyExc_AttributeError,
1440- "attribute '_CHUNK_SIZE ' of '%.100s' objects cannot be deleted",
1448+ "attribute 'check_hostname ' of '%.100s' objects cannot be deleted",
14411449 Py_TYPE(self)->tp_name);
14421450 return -1;
14431451 }
1452+ value = PyObject_IsTrue(arg);
1453+ if (value < 0) {
1454+ goto exit;
1455+ }
14441456 Py_BEGIN_CRITICAL_SECTION(self);
1445- return_value = _io_TextIOWrapper__CHUNK_SIZE_set_impl((textio *)self, value);
1457+ return_value = _ssl__SSLContext_check_hostname_set_impl((PySSLContext *)self, value);
14461458 Py_END_CRITICAL_SECTION();
14471459
1460+ exit:
14481461 return return_value;
14491462 }
14501463
14511464 .. note ::
14521465
14531466 Getters and setters must be declared as separate functions.
1454- The *value * parameter for a "setter" is added implicitly by Argument Clinic.
14551467 It is possible to create a docstring for the property by adding it to
14561468 the ``@getter ``.
1457- The accessors of the same attribute must share the C basename;
1458- declaring the same accessor twice is an error.
1469+ The accessors of the same attribute are identified by the Python name of
1470+ that attribute, so they can use different C basenames.
1471+ Declaring the same accessor twice is only allowed if each of them is
1472+ compiled under its own preprocessor condition.
1473+
1474+ And then the implementation will work the same as a Python method which is
1475+ decorated by :py:class: `property `:
1476+
1477+ .. code-block :: pycon
1478+
1479+ >>> import ssl
1480+ >>> ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
1481+ >>> ctx.check_hostname
1482+ True
1483+ >>> ctx.check_hostname = False
1484+ >>> ctx.check_hostname
1485+ False
1486+ >>> del ctx.check_hostname
1487+ Traceback (most recent call last):
1488+ ...
1489+ AttributeError: attribute 'check_hostname' of 'SSLContext' objects cannot be deleted
1490+
1491+ A "getter" can define a :ref: `return converter
1492+ <clinic-howto-return-converters>`, as shown above, so that the "impl"
1493+ function returns a C value instead of an object.
1494+
1495+ The new value of the attribute is passed to the "impl" function as the only
1496+ argument.
1497+ As shown above, it can be declared as a parameter named *value *, with
1498+ a converter, and is then converted like an argument of a function.
1499+ If it is not declared, ``value: object `` is added implicitly.
1500+ Note that an error for a value of a wrong type names the attribute instead of
1501+ an argument of a function.
14591502
14601503The setter slot of :c:type: `PyGetSetDef ` is used both for setting and for
14611504deleting the attribute: the setter is called with ``NULL `` as the value to
@@ -1473,42 +1516,20 @@ handling this case, as in this example taken from
14731516 @critical_section
14741517 @setter
14751518 @deleter
1476- function.__annotations__
1519+ function.__type_params__
1520+ value: object(subclass_of='&PyTuple_Type') = NULL
14771521 [clinic start generated code]*/
14781522
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- }
1496-
1497- And then the implementation will work the same as a Python method which is
1498- decorated by :py:class: `property `:
1499-
1500- .. code-block :: pycon
1501-
1502- >>> import sys, _io
1503- >>> a = _io.TextIOWrapper(sys.stdout)
1504- >>> a._CHUNK_SIZE
1505- 8192
1506- >>> a._CHUNK_SIZE = 30
1507- >>> a._CHUNK_SIZE
1508- 30
1523+ The value is only converted if the attribute is not deleted, so it must have
1524+ a default value, which the "impl" function receives for the deletion.
1525+ The implicitly declared value gets the default ``NULL ``.
15091526
15101527.. versionadded :: 3.13
15111528
1529+ .. versionchanged :: 3.16
1530+ Added support for converters and for several implementations of the same
1531+ accessor in different preprocessor conditional blocks.
1532+
15121533
15131534.. _clinic-howto-deprecate-positional :
15141535.. _clinic-howto-deprecate-keyword :
0 commit comments