@@ -9,6 +9,7 @@ descr_dealloc(PyDescrObject *descr)
99 _PyObject_GC_UNTRACK (descr );
1010 Py_XDECREF (descr -> d_type );
1111 Py_XDECREF (descr -> d_name );
12+ Py_XDECREF (descr -> d_qualname );
1213 PyObject_GC_Del (descr );
1314}
1415
@@ -321,6 +322,44 @@ method_get_doc(PyMethodDescrObject *descr, void *closure)
321322 return PyUnicode_FromString (descr -> d_method -> ml_doc );
322323}
323324
325+ static PyObject *
326+ calculate_qualname (PyDescrObject * descr )
327+ {
328+ PyObject * type_qualname , * res ;
329+ _Py_IDENTIFIER (__qualname__ );
330+
331+ if (descr -> d_name == NULL || !PyUnicode_Check (descr -> d_name )) {
332+ PyErr_SetString (PyExc_TypeError ,
333+ "<descriptor>.__name__ is not a unicode object" );
334+ return NULL ;
335+ }
336+
337+ type_qualname = _PyObject_GetAttrId ((PyObject * )descr -> d_type ,
338+ & PyId___qualname__ );
339+ if (type_qualname == NULL )
340+ return NULL ;
341+
342+ if (!PyUnicode_Check (type_qualname )) {
343+ PyErr_SetString (PyExc_TypeError , "<descriptor>.__objclass__."
344+ "__qualname__ is not a unicode object" );
345+ Py_XDECREF (type_qualname );
346+ return NULL ;
347+ }
348+
349+ res = PyUnicode_FromFormat ("%S.%S" , type_qualname , descr -> d_name );
350+ Py_DECREF (type_qualname );
351+ return res ;
352+ }
353+
354+ static PyObject *
355+ descr_get_qualname (PyDescrObject * descr )
356+ {
357+ if (descr -> d_qualname == NULL )
358+ descr -> d_qualname = calculate_qualname (descr );
359+ Py_XINCREF (descr -> d_qualname );
360+ return descr -> d_qualname ;
361+ }
362+
324363static PyMemberDef descr_members [] = {
325364 {"__objclass__" , T_OBJECT , offsetof(PyDescrObject , d_type ), READONLY },
326365 {"__name__" , T_OBJECT , offsetof(PyDescrObject , d_name ), READONLY },
@@ -329,6 +368,7 @@ static PyMemberDef descr_members[] = {
329368
330369static PyGetSetDef method_getset [] = {
331370 {"__doc__" , (getter )method_get_doc },
371+ {"__qualname__" , (getter )descr_get_qualname },
332372 {0 }
333373};
334374
@@ -344,6 +384,7 @@ member_get_doc(PyMemberDescrObject *descr, void *closure)
344384
345385static PyGetSetDef member_getset [] = {
346386 {"__doc__" , (getter )member_get_doc },
387+ {"__qualname__" , (getter )descr_get_qualname },
347388 {0 }
348389};
349390
@@ -359,6 +400,7 @@ getset_get_doc(PyGetSetDescrObject *descr, void *closure)
359400
360401static PyGetSetDef getset_getset [] = {
361402 {"__doc__" , (getter )getset_get_doc },
403+ {"__qualname__" , (getter )descr_get_qualname },
362404 {0 }
363405};
364406
@@ -374,6 +416,7 @@ wrapperdescr_get_doc(PyWrapperDescrObject *descr, void *closure)
374416
375417static PyGetSetDef wrapperdescr_getset [] = {
376418 {"__doc__" , (getter )wrapperdescr_get_doc },
419+ {"__qualname__" , (getter )descr_get_qualname },
377420 {0 }
378421};
379422
@@ -585,6 +628,7 @@ descr_new(PyTypeObject *descrtype, PyTypeObject *type, const char *name)
585628 Py_DECREF (descr );
586629 descr = NULL ;
587630 }
631+ descr -> d_qualname = NULL ;
588632 }
589633 return descr ;
590634}
@@ -987,9 +1031,16 @@ wrapper_doc(wrapperobject *wp)
9871031 }
9881032}
9891033
1034+ static PyObject *
1035+ wrapper_qualname (wrapperobject * wp )
1036+ {
1037+ return descr_get_qualname ((PyDescrObject * )wp -> descr );
1038+ }
1039+
9901040static PyGetSetDef wrapper_getsets [] = {
9911041 {"__objclass__" , (getter )wrapper_objclass },
9921042 {"__name__" , (getter )wrapper_name },
1043+ {"__qualname__" , (getter )wrapper_qualname },
9931044 {"__doc__" , (getter )wrapper_doc },
9941045 {0 }
9951046};
0 commit comments