From b5dd2e8407ef0673185e06b13f50ff3bfd339d1f Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Mon, 19 Oct 2026 12:44:36 -0400 Subject: [PATCH 1/6] Document missing descriptor C APIs. --- Doc/c-api/descriptor.rst | 39 ++++++++++++++++++++++++ Tools/check-c-api-docs/ignored_c_api.txt | 4 --- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/Doc/c-api/descriptor.rst b/Doc/c-api/descriptor.rst index 539c4610ce4f5b..db4a95c48a19d0 100644 --- a/Doc/c-api/descriptor.rst +++ b/Doc/c-api/descriptor.rst @@ -81,6 +81,21 @@ found in the dictionary of type objects. special method implemented by a type slot, together with the wrapper function used to adapt that slot to Python's calling convention. + .. c:member:: int flags + + Bitwise OR of flags that describe the wrapper function. Currently, the + only flag is :c:macro:`PyWrapperFlag_KEYWORDS`; all other bits must be + zero. + +.. c:macro:: PyWrapperFlag_KEYWORDS + + Flag that can be set in the :c:member:`~wrapperbase.flags` field of a + :c:struct:`wrapperbase` structure. + When set, the wrapper function is passed an additional argument with + a :class:`dict` instance containing the passed keyword arguments. + When not set, calling the wrapper descriptor with keyword arguments + raises :exc:`TypeError`. + .. c:function:: PyObject* PyDescr_NewWrapper(PyTypeObject *type, struct wrapperbase *base, void *wrapped) Create a new wrapper descriptor for extension type *type* from the @@ -138,6 +153,30 @@ found in the dictionary of type objects. On success, return a :term:`strong reference` to the wrapper object. Return ``NULL`` with an exception set on failure. +.. c:macro:: PyDescr_TYPE(descr) + + Return a :term:`borrowed reference` to the type that the descriptor + *descr* belongs to. This is accessible as :attr:`~object.__objclass__` + in Python. + + *descr* must be a descriptor object created by one of the + ``PyDescr_New*`` functions (an instance of + :c:var:`PyMethodDescr_Type`, :c:var:`PyClassMethodDescr_Type`, + :c:var:`PyMemberDescr_Type`, :c:var:`PyGetSetDescr_Type`, or + :c:var:`PyWrapperDescr_Type`). If the passed descriptor is not + an instance of one of these types, the behavior is undefined. + + +.. c:macro:: PyDescr_NAME(descr) + + Return the name of the descriptor *descr* as a :term:`borrowed reference` + to a :class:`str` object. This is available as :attr:`~definition.__name__` + in Python. + + *descr* must be a descriptor object created by one of the ``PyDescr_New*`` + functions. If not, the behavior is undefined. + + .. c:macro:: PyDescr_COMMON This is a macro including the common fields for a diff --git a/Tools/check-c-api-docs/ignored_c_api.txt b/Tools/check-c-api-docs/ignored_c_api.txt index af7b2772ef5e08..2da956df1043d4 100644 --- a/Tools/check-c-api-docs/ignored_c_api.txt +++ b/Tools/check-c-api-docs/ignored_c_api.txt @@ -29,10 +29,6 @@ PY_DWORD_MAX PY_BIG_ENDIAN # cpython/methodobject.h PyCFunction_GET_CLASS -# cpython/descrobject.h -PyDescr_NAME -PyDescr_TYPE -PyWrapperFlag_KEYWORDS # cpython/fileobject.h Py_UniversalNewlineFgets # cpython/pylifecycle.h From 75633aff727ad4a320f537c069baa0e9d025ffc2 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Mon, 19 Oct 2026 12:48:46 -0400 Subject: [PATCH 2/6] Add soft deprecation. --- Doc/c-api/descriptor.rst | 5 +++++ Doc/whatsnew/3.16.rst | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/Doc/c-api/descriptor.rst b/Doc/c-api/descriptor.rst index db4a95c48a19d0..a81e4fc0a0494c 100644 --- a/Doc/c-api/descriptor.rst +++ b/Doc/c-api/descriptor.rst @@ -96,6 +96,11 @@ found in the dictionary of type objects. When not set, calling the wrapper descriptor with keyword arguments raises :exc:`TypeError`. + This flag is specific to the way CPython implements slot wrappers; do not + use it in extensions. + + .. soft-deprecated:: 3.16 + .. c:function:: PyObject* PyDescr_NewWrapper(PyTypeObject *type, struct wrapperbase *base, void *wrapped) Create a new wrapper descriptor for extension type *type* from the diff --git a/Doc/whatsnew/3.16.rst b/Doc/whatsnew/3.16.rst index a1d7d1eaae7d52..baaa8bcf22ef36 100644 --- a/Doc/whatsnew/3.16.rst +++ b/Doc/whatsnew/3.16.rst @@ -1232,6 +1232,10 @@ Deprecated C APIs Use the safer :c:type:`PyUnicodeWriter` API instead. (Contributed by Victor Stinner in :gh:`157710`.) +* :c:macro:`PyWrapperFlag_KEYWORDS` is :term:`soft deprecated`. + It exposes CPython implementation details and has no replacement. + (Contributed by Peter Bierma in :gh:`141004`.) + .. Add C API deprecations above alphabetically, not here at the end. .. include:: ../deprecations/c-api-pending-removal-in-3.18.rst From 99d1f96fb2a59c728d9e256e18b2180150c973c4 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Wed, 21 Oct 2026 14:21:07 -0400 Subject: [PATCH 3/6] Explain how to use PyDescr_NewWrapper. --- Doc/c-api/descriptor.rst | 163 +++++++++++++++++++++++++++++++++++---- Doc/whatsnew/3.16.rst | 4 - 2 files changed, 150 insertions(+), 17 deletions(-) diff --git a/Doc/c-api/descriptor.rst b/Doc/c-api/descriptor.rst index a81e4fc0a0494c..dc39fde1a8b4f2 100644 --- a/Doc/c-api/descriptor.rst +++ b/Doc/c-api/descriptor.rst @@ -75,11 +75,63 @@ found in the dictionary of type objects. .. c:struct:: wrapperbase - Describes a slot wrapper used by :c:func:`PyDescr_NewWrapper`. + Describes how a type slot is exposed to Python as a special method. - Each ``wrapperbase`` record stores the Python-visible name and metadata for a - special method implemented by a type slot, together with the wrapper - function used to adapt that slot to Python's calling convention. + This is the structure behind the *slot wrapper* objects found in the + dictionaries of built-in and extension types, such as ``int.__add__`` or + ``object.__repr__``. CPython keeps an internal table of these records, one + for each special method name that corresponds to a slot of + :c:type:`PyTypeObject` or one of its sub-structures (such as + :c:type:`PyNumberMethods`). + + Extensions do not normally need this structure, because CPython creates + wrapper descriptors for the slots of every type automatically. It is useful + when a C function with a slot-like signature should be exposed as a + special method without being installed in a type slot, or when a slot + function needs to be exposed under a different name or with a different + docstring than the default one. + + A ``wrapperbase`` is not copied by :c:func:`PyDescr_NewWrapper`; it must + stay valid for as long as any descriptor created from it exists. + It is usually a static variable. + + .. c:member:: const char *name + + The name of the special method, such as ``"__add__"``. + This becomes the descriptor's :attr:`~definition.__name__` and is + used in error messages. + + .. c:member:: int offset + + Offset of the slot that this record describes, relative to + the start of :c:type:`!PyHeapTypeObject`. + This is generally not useful to extensions, as :c:func:`PyDescr_NewWrapper` + does not use this; set this to 0 when using that function. + + .. c:member:: void *function + + The generic slot implementation that CPython installs in a type's slot + when the corresponding special method is defined in Python, for example + in a subclass. Like :c:member:`~wrapperbase.offset`, it is only used by + CPython's internal table; set it to ``NULL`` for records that are only + used with :c:func:`PyDescr_NewWrapper`. + + .. c:member:: wrapperfunc wrapper + + The function that adapts the slot's C calling convention to a Python + call. It receives the instance the special method was called on, a + tuple of the remaining positional arguments, and the wrapped slot + function pointer. It must check that the number and types of arguments + are suitable for the slot function, call it, and convert the result + to a Python object. + + If :c:member:`~wrapperbase.flags` includes + :c:macro:`PyWrapperFlag_KEYWORDS`, this field must instead point to a + :c:type:`wrapperfunc_kwds` function, cast to :c:type:`wrapperfunc`. + + .. c:member:: const char *doc + + The docstring of the special method, or ``NULL``. .. c:member:: int flags @@ -87,25 +139,42 @@ found in the dictionary of type objects. only flag is :c:macro:`PyWrapperFlag_KEYWORDS`; all other bits must be zero. + .. c:member:: PyObject *name_strobj + + Reserved for internal use. Initialize it to ``NULL``. + +.. c:type:: PyObject *(*wrapperfunc)(PyObject *self, PyObject *args, void *wrapped) + + The type of the :c:member:`~wrapperbase.wrapper` function of a + :c:struct:`wrapperbase`. *self* is the instance the special method is called + on, *args* is a tuple of the positional arguments that follow it, and + *wrapped* is the slot function pointer that was passed to + :c:func:`PyDescr_NewWrapper`. + + On success, return a :term:`strong reference` to the result. Return ``NULL`` + with an exception set on failure. + +.. c:type:: PyObject *(*wrapperfunc_kwds)(PyObject *self, PyObject *args, void *wrapped, PyObject *kwds) + + Like :c:type:`wrapperfunc`, but with an additional *kwds* argument holding + a dictionary of keyword arguments, or ``NULL`` if no keyword arguments were + passed. Used for wrappers whose :c:member:`~wrapperbase.flags` include + :c:macro:`PyWrapperFlag_KEYWORDS`. + .. c:macro:: PyWrapperFlag_KEYWORDS Flag that can be set in the :c:member:`~wrapperbase.flags` field of a :c:struct:`wrapperbase` structure. - When set, the wrapper function is passed an additional argument with - a :class:`dict` instance containing the passed keyword arguments. + When set, the :c:member:`~wrapperbase.wrapper` function has the + :c:type:`wrapperfunc_kwds` signature and is passed the keyword arguments + of the call as a :class:`dict`. When not set, calling the wrapper descriptor with keyword arguments raises :exc:`TypeError`. - This flag is specific to the way CPython implements slot wrappers; do not - use it in extensions. - - .. soft-deprecated:: 3.16 - .. c:function:: PyObject* PyDescr_NewWrapper(PyTypeObject *type, struct wrapperbase *base, void *wrapped) Create a new wrapper descriptor for extension type *type* from the - :c:struct:`wrapperbase` structure *base* and the wrapped slot function - pointer + :c:struct:`wrapperbase` structure *base* and the slot function pointer *wrapped*. Wrapper descriptors expose special methods implemented by type slots. This @@ -113,9 +182,77 @@ found in the dictionary of type objects. methods such as ``__repr__`` or ``__add__``, and it appears in Python as a :class:`types.WrapperDescriptorType` object. + The descriptor only references *base*; see :c:struct:`wrapperbase` for the + lifetime requirements. + On success, return a :term:`strong reference` to the descriptor. Return ``NULL`` with an exception set on failure. + For example, the following gives the ``__len__`` method of a static type a + custom docstring. :c:func:`PyType_Ready` would normally create the + ``__len__`` descriptor itself from the + :c:member:`~PySequenceMethods.sq_length` slot, but it leaves the entry + alone if the type's dictionary already contains one:: + + static Py_ssize_t + my_len(PyObject *self) + { + /* ... */ + } + + static PyObject * + wrap_lenfunc(PyObject *self, PyObject *args, void *wrapped) + { + lenfunc func = (lenfunc)wrapped; + if (PyTuple_GET_SIZE(args) != 0) { + PyErr_SetString(PyExc_TypeError, + "__len__() takes no arguments"); + return NULL; + } + Py_ssize_t result = func(self); + if (result == -1 && PyErr_Occurred()) { + return NULL; + } + return PyLong_FromSsize_t(result); + } + + static struct wrapperbase len_wrapper = { + .name = "__len__", + .wrapper = wrap_lenfunc, + .doc = "__len__($self, /)\n--\n\nReturn the number of items.", + }; + + static PySequenceMethods my_as_sequence = { + .sq_length = my_len, + }; + + static PyTypeObject MyType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "mymodule.MyType", + .tp_as_sequence = &my_as_sequence, + /* ... */ + }; + + static int + ready_my_type(void) + { + MyType.tp_dict = PyDict_New(); + if (MyType.tp_dict == NULL) { + return -1; + } + PyObject *descr = PyDescr_NewWrapper(&MyType, &len_wrapper, + (void *)my_len); + if (descr == NULL) { + return -1; + } + int result = PyDict_SetItemString(MyType.tp_dict, "__len__", descr); + Py_DECREF(descr); + if (result < 0) { + return -1; + } + return PyType_Ready(&MyType); + } + .. c:var:: PyTypeObject PyWrapperDescr_Type The type object for wrapper descriptor objects created by diff --git a/Doc/whatsnew/3.16.rst b/Doc/whatsnew/3.16.rst index 47724aa94c0467..b29170b5b0b93d 100644 --- a/Doc/whatsnew/3.16.rst +++ b/Doc/whatsnew/3.16.rst @@ -1302,10 +1302,6 @@ Deprecated C APIs Use the safer :c:type:`PyUnicodeWriter` API instead. (Contributed by Victor Stinner in :gh:`157710`.) -* :c:macro:`PyWrapperFlag_KEYWORDS` is :term:`soft deprecated`. - It exposes CPython implementation details and has no replacement. - (Contributed by Peter Bierma in :gh:`141004`.) - .. Add C API deprecations above alphabetically, not here at the end. .. include:: ../deprecations/c-api-pending-removal-in-3.18.rst From 97030dc60323174d79abafd95b8dda882e6134f8 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Wed, 21 Oct 2026 14:27:42 -0400 Subject: [PATCH 4/6] Fix checker script. --- Tools/check-c-api-docs/ignored_c_api.txt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Tools/check-c-api-docs/ignored_c_api.txt b/Tools/check-c-api-docs/ignored_c_api.txt index c2003dff7b6b6b..6e1b77ba2786cb 100644 --- a/Tools/check-c-api-docs/ignored_c_api.txt +++ b/Tools/check-c-api-docs/ignored_c_api.txt @@ -1,4 +1 @@ -# cpython/descrobject.h -PyDescr_NAME -PyDescr_TYPE -PyWrapperFlag_KEYWORDS +# Nothing here :) From 0f76cbb397e19ce200050072476bdc53debd791d Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Wed, 21 Oct 2026 17:19:21 -0400 Subject: [PATCH 5/6] Document wrapper stuff as internal. --- Doc/c-api/descriptor.rst | 214 +++++---------------------------------- 1 file changed, 25 insertions(+), 189 deletions(-) diff --git a/Doc/c-api/descriptor.rst b/Doc/c-api/descriptor.rst index dc39fde1a8b4f2..37a5bd3530c738 100644 --- a/Doc/c-api/descriptor.rst +++ b/Doc/c-api/descriptor.rst @@ -73,195 +73,6 @@ found in the dictionary of type objects. objects in Python. -.. c:struct:: wrapperbase - - Describes how a type slot is exposed to Python as a special method. - - This is the structure behind the *slot wrapper* objects found in the - dictionaries of built-in and extension types, such as ``int.__add__`` or - ``object.__repr__``. CPython keeps an internal table of these records, one - for each special method name that corresponds to a slot of - :c:type:`PyTypeObject` or one of its sub-structures (such as - :c:type:`PyNumberMethods`). - - Extensions do not normally need this structure, because CPython creates - wrapper descriptors for the slots of every type automatically. It is useful - when a C function with a slot-like signature should be exposed as a - special method without being installed in a type slot, or when a slot - function needs to be exposed under a different name or with a different - docstring than the default one. - - A ``wrapperbase`` is not copied by :c:func:`PyDescr_NewWrapper`; it must - stay valid for as long as any descriptor created from it exists. - It is usually a static variable. - - .. c:member:: const char *name - - The name of the special method, such as ``"__add__"``. - This becomes the descriptor's :attr:`~definition.__name__` and is - used in error messages. - - .. c:member:: int offset - - Offset of the slot that this record describes, relative to - the start of :c:type:`!PyHeapTypeObject`. - This is generally not useful to extensions, as :c:func:`PyDescr_NewWrapper` - does not use this; set this to 0 when using that function. - - .. c:member:: void *function - - The generic slot implementation that CPython installs in a type's slot - when the corresponding special method is defined in Python, for example - in a subclass. Like :c:member:`~wrapperbase.offset`, it is only used by - CPython's internal table; set it to ``NULL`` for records that are only - used with :c:func:`PyDescr_NewWrapper`. - - .. c:member:: wrapperfunc wrapper - - The function that adapts the slot's C calling convention to a Python - call. It receives the instance the special method was called on, a - tuple of the remaining positional arguments, and the wrapped slot - function pointer. It must check that the number and types of arguments - are suitable for the slot function, call it, and convert the result - to a Python object. - - If :c:member:`~wrapperbase.flags` includes - :c:macro:`PyWrapperFlag_KEYWORDS`, this field must instead point to a - :c:type:`wrapperfunc_kwds` function, cast to :c:type:`wrapperfunc`. - - .. c:member:: const char *doc - - The docstring of the special method, or ``NULL``. - - .. c:member:: int flags - - Bitwise OR of flags that describe the wrapper function. Currently, the - only flag is :c:macro:`PyWrapperFlag_KEYWORDS`; all other bits must be - zero. - - .. c:member:: PyObject *name_strobj - - Reserved for internal use. Initialize it to ``NULL``. - -.. c:type:: PyObject *(*wrapperfunc)(PyObject *self, PyObject *args, void *wrapped) - - The type of the :c:member:`~wrapperbase.wrapper` function of a - :c:struct:`wrapperbase`. *self* is the instance the special method is called - on, *args* is a tuple of the positional arguments that follow it, and - *wrapped* is the slot function pointer that was passed to - :c:func:`PyDescr_NewWrapper`. - - On success, return a :term:`strong reference` to the result. Return ``NULL`` - with an exception set on failure. - -.. c:type:: PyObject *(*wrapperfunc_kwds)(PyObject *self, PyObject *args, void *wrapped, PyObject *kwds) - - Like :c:type:`wrapperfunc`, but with an additional *kwds* argument holding - a dictionary of keyword arguments, or ``NULL`` if no keyword arguments were - passed. Used for wrappers whose :c:member:`~wrapperbase.flags` include - :c:macro:`PyWrapperFlag_KEYWORDS`. - -.. c:macro:: PyWrapperFlag_KEYWORDS - - Flag that can be set in the :c:member:`~wrapperbase.flags` field of a - :c:struct:`wrapperbase` structure. - When set, the :c:member:`~wrapperbase.wrapper` function has the - :c:type:`wrapperfunc_kwds` signature and is passed the keyword arguments - of the call as a :class:`dict`. - When not set, calling the wrapper descriptor with keyword arguments - raises :exc:`TypeError`. - -.. c:function:: PyObject* PyDescr_NewWrapper(PyTypeObject *type, struct wrapperbase *base, void *wrapped) - - Create a new wrapper descriptor for extension type *type* from the - :c:struct:`wrapperbase` structure *base* and the slot function pointer - *wrapped*. - - Wrapper descriptors expose special methods implemented by type slots. This - is the same kind of descriptor that CPython creates for slot-based special - methods such as ``__repr__`` or ``__add__``, and it appears in Python as a - :class:`types.WrapperDescriptorType` object. - - The descriptor only references *base*; see :c:struct:`wrapperbase` for the - lifetime requirements. - - On success, return a :term:`strong reference` to the descriptor. Return - ``NULL`` with an exception set on failure. - - For example, the following gives the ``__len__`` method of a static type a - custom docstring. :c:func:`PyType_Ready` would normally create the - ``__len__`` descriptor itself from the - :c:member:`~PySequenceMethods.sq_length` slot, but it leaves the entry - alone if the type's dictionary already contains one:: - - static Py_ssize_t - my_len(PyObject *self) - { - /* ... */ - } - - static PyObject * - wrap_lenfunc(PyObject *self, PyObject *args, void *wrapped) - { - lenfunc func = (lenfunc)wrapped; - if (PyTuple_GET_SIZE(args) != 0) { - PyErr_SetString(PyExc_TypeError, - "__len__() takes no arguments"); - return NULL; - } - Py_ssize_t result = func(self); - if (result == -1 && PyErr_Occurred()) { - return NULL; - } - return PyLong_FromSsize_t(result); - } - - static struct wrapperbase len_wrapper = { - .name = "__len__", - .wrapper = wrap_lenfunc, - .doc = "__len__($self, /)\n--\n\nReturn the number of items.", - }; - - static PySequenceMethods my_as_sequence = { - .sq_length = my_len, - }; - - static PyTypeObject MyType = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "mymodule.MyType", - .tp_as_sequence = &my_as_sequence, - /* ... */ - }; - - static int - ready_my_type(void) - { - MyType.tp_dict = PyDict_New(); - if (MyType.tp_dict == NULL) { - return -1; - } - PyObject *descr = PyDescr_NewWrapper(&MyType, &len_wrapper, - (void *)my_len); - if (descr == NULL) { - return -1; - } - int result = PyDict_SetItemString(MyType.tp_dict, "__len__", descr); - Py_DECREF(descr); - if (result < 0) { - return -1; - } - return PyType_Ready(&MyType); - } - -.. c:var:: PyTypeObject PyWrapperDescr_Type - - The type object for wrapper descriptor objects created by - :c:func:`PyDescr_NewWrapper` and :c:func:`PyWrapper_New`. Wrapper - descriptors are used internally to expose special methods implemented - via wrapper structures, and appear in Python as - :class:`types.WrapperDescriptorType` objects. - - .. c:function:: PyObject* PyDescr_NewClassMethod(PyTypeObject *type, PyMethodDef *method) Create a new class method descriptor for extension type *type* from the @@ -332,6 +143,31 @@ found in the dictionary of type objects. .. soft-deprecated:: 3.15 +.. c:struct:: wrapperbase + :no-contents-entry: + :no-index-entry: + :no-typesetting: +.. c:type:: PyObject *(*wrapperfunc)(PyObject *self, PyObject *args, void *wrapped) + :no-contents-entry: + :no-index-entry: + :no-typesetting: +.. c:type:: PyObject *(*wrapperfunc_kwds)(PyObject *self, PyObject *args, void *wrapped, PyObject *kwds) + :no-contents-entry: + :no-index-entry: + :no-typesetting: +.. c:macro:: PyWrapperFlag_KEYWORDS + :no-contents-entry: + :no-index-entry: + :no-typesetting: +.. c:var:: PyTypeObject PyWrapperDescr_Type + :no-contents-entry: + :no-index-entry: + :no-typesetting: +.. c:function:: PyObject* PyDescr_NewWrapper(PyTypeObject *type, struct wrapperbase *base, void *wrapped) + + For internal use only; do not use in extensions. + + Built-in descriptors ^^^^^^^^^^^^^^^^^^^^ From ded0b996d7c52655b57178b10d5bf3f139cdcb26 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Wed, 21 Oct 2026 15:11:43 -0700 Subject: [PATCH 6/6] Here's what I meant :) - Mention the publicly-unusable API from prose, with no-typesetting entries for search & index - Merge the duplicate description of what wrapperdescrs are; put it in the type docs. (The *type* might be useful for extensions.) --- Doc/c-api/descriptor.rst | 53 +++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/Doc/c-api/descriptor.rst b/Doc/c-api/descriptor.rst index 37a5bd3530c738..5d3e7ec95f31e2 100644 --- a/Doc/c-api/descriptor.rst +++ b/Doc/c-api/descriptor.rst @@ -72,6 +72,34 @@ found in the dictionary of type objects. methods on a type, and correspond to :class:`types.MethodDescriptorType` objects in Python. +.. c:var:: PyTypeObject PyWrapperDescr_Type + + The type object for wrapper descriptor objects created by + :c:func:`PyDescr_NewWrapper` and :c:func:`PyWrapper_New`. + + Wrapper descriptors are used internally to expose special methods + such as ``__repr__`` or ``__add__``, which are implemented by type slots. + The type is exposed in Python as :class:`types.WrapperDescriptorType`. + + +.. `wrapperbase` & `PyWrapperFlag_KEYWORDS` show up in search and index, + and link here, but are only referenced in prose: + +.. c:struct:: wrapperbase + :no-typesetting: + +.. c:macro:: PyWrapperFlag_KEYWORDS + :no-typesetting: + +.. c:function:: PyObject* PyDescr_NewWrapper(PyTypeObject *type, struct wrapperbase *base, void *wrapped) + + Create a new wrapper descriptor of type :c:var:`PyWrapperDescr_Type`. + + This function is meant for internal use only; it and + related API (``struct wrapperbase`` and the ``PyWrapperFlag_KEYWORDS`` + flag) are exposed publicly for backwards compatibility reasons. + + See :c:func:`PyCMethod_New` for wrapping a C function. .. c:function:: PyObject* PyDescr_NewClassMethod(PyTypeObject *type, PyMethodDef *method) @@ -143,31 +171,6 @@ found in the dictionary of type objects. .. soft-deprecated:: 3.15 -.. c:struct:: wrapperbase - :no-contents-entry: - :no-index-entry: - :no-typesetting: -.. c:type:: PyObject *(*wrapperfunc)(PyObject *self, PyObject *args, void *wrapped) - :no-contents-entry: - :no-index-entry: - :no-typesetting: -.. c:type:: PyObject *(*wrapperfunc_kwds)(PyObject *self, PyObject *args, void *wrapped, PyObject *kwds) - :no-contents-entry: - :no-index-entry: - :no-typesetting: -.. c:macro:: PyWrapperFlag_KEYWORDS - :no-contents-entry: - :no-index-entry: - :no-typesetting: -.. c:var:: PyTypeObject PyWrapperDescr_Type - :no-contents-entry: - :no-index-entry: - :no-typesetting: -.. c:function:: PyObject* PyDescr_NewWrapper(PyTypeObject *type, struct wrapperbase *base, void *wrapped) - - For internal use only; do not use in extensions. - - Built-in descriptors ^^^^^^^^^^^^^^^^^^^^