commit a14e53f1fe3147a2bf70dcb15bf3724b6a6a14d9 Author: Victor Stinner Date: Wed Jan 26 00:26:13 2022 +0100 bpo-45476: Add PyDescr_SET_TYPE() and PyDescr_SET_NAME() Add PyDescr_SET_TYPE() and PyDescr_SET_NAME() macros to set the type and name of a descriptor (PyDescrObject structure): classmethod_descriptor, member_descriptor or getset_descriptor. The main usage of these macros is to create an instance of a descriptor subclass. diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 4328ee6a50..f9e632b10a 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -677,6 +677,13 @@ New Features :c:macro:`PY_VERSION_HEX`. (Contributed by Gabriele N. Tornetta in :issue:`43931`.) +* Add ``PyDescr_SET_TYPE()`` and ``PyDescr_SET_NAME()`` macros to set the type + and name of a descriptor (``PyDescrObject`` structure): + ``classmethod_descriptor``, ``member_descriptor`` or ``getset_descriptor``. + The main usage of these macros is to create an instance of a descriptor + subclass. + (Contributed by Victor Stinner in :issue:`45476`.) + Porting to Python 3.11 ---------------------- diff --git a/Include/descrobject.h b/Include/descrobject.h index 703bc8fd6d..960dfafdad 100644 --- a/Include/descrobject.h +++ b/Include/descrobject.h @@ -49,6 +49,14 @@ typedef struct { #define PyDescr_TYPE(x) (((PyDescrObject *)(x))->d_type) #define PyDescr_NAME(x) (((PyDescrObject *)(x))->d_name) +#define PyDescr_QUALNAME(x) (((PyDescrObject *)(x))->d_qualname) + +#define PyDescr_SET_TYPE(x, type) \ + do { (((PyDescrObject *)(x))->d_type = (type)) } while (0) +#define PyDescr_SET_NAME(x, name) \ + do { (((PyDescrObject *)(x))->d_name = (name)) } while (0) +#define PyDescr_SET_QUALNAME(x, qualname) \ + do { (((PyDescrObject *)(x))->d_qualname = (qualname)) } while (0) typedef struct { PyDescr_COMMON; diff --git a/Misc/NEWS.d/next/C API/2022-01-26-00-31-20.bpo-45476.KiJM9A.rst b/Misc/NEWS.d/next/C API/2022-01-26-00-31-20.bpo-45476.KiJM9A.rst new file mode 100644 index 0000000000..3c7c5148ae --- /dev/null +++ b/Misc/NEWS.d/next/C API/2022-01-26-00-31-20.bpo-45476.KiJM9A.rst @@ -0,0 +1,5 @@ +Add ``PyDescr_SET_TYPE()`` and ``PyDescr_SET_NAME()`` macros to set the type +and name of a descriptor (``PyDescrObject`` structure): +``classmethod_descriptor``, ``member_descriptor`` or ``getset_descriptor``. The +main usage of these macros is to create an instance of a descriptor subclass. +Patch by Victor Stinner. diff --git a/Objects/descrobject.c b/Objects/descrobject.c index 962136beae..ee176b37d5 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -599,10 +599,14 @@ calculate_qualname(PyDescrObject *descr) static PyObject * descr_get_qualname(PyDescrObject *descr, void *Py_UNUSED(ignored)) { - if (descr->d_qualname == NULL) - descr->d_qualname = calculate_qualname(descr); - Py_XINCREF(descr->d_qualname); - return descr->d_qualname; + if (PyDescr_QUALNAME(descr) == NULL) { + PyObject *qualname = calculate_qualname(descr); + if (qualname == NULL) { + return NULL; + } + PyDescr_SET_QUALNAME(descr, qualname); + } + return Py_NewRef(PyDescr_QUALNAME(descr)); } static PyObject * @@ -876,24 +880,23 @@ PyTypeObject PyWrapperDescr_Type = { 0, /* tp_descr_set */ }; -static PyDescrObject * -descr_new(PyTypeObject *descrtype, PyTypeObject *type, const char *name) +PyDescrObject * +PyDescr_New(PyTypeObject *descrtype, PyTypeObject *type, const char *name) { - PyDescrObject *descr; + PyObject *name_obj = PyUnicode_InternFromString(name); + if (name_obj == NULL) { + return NULL; + } - descr = (PyDescrObject *)PyType_GenericAlloc(descrtype, 0); - if (descr != NULL) { - Py_XINCREF(type); - descr->d_type = type; - descr->d_name = PyUnicode_InternFromString(name); - if (descr->d_name == NULL) { - Py_DECREF(descr); - descr = NULL; - } - else { - descr->d_qualname = NULL; - } + PyDescrObject *descr = (PyDescrObject *)PyType_GenericAlloc(descrtype, 0); + if (descr == NULL) + Py_DECREF(name); + return NULL; } + + PyDescr_SET_TYPE(descr, Py_XNewRef(type)); + PyDescr_SET_NAME(descr, name_obj); + PyDescr_SET_QUALNAME(descr, NULL); return descr; }