diff -r 9c34ead53f94 Include/descrobject.h --- a/Include/descrobject.h Thu Dec 08 17:56:55 2011 +0000 +++ b/Include/descrobject.h Sun Dec 11 14:27:47 2011 +0000 @@ -42,6 +42,7 @@ PyObject_HEAD PyTypeObject *d_type; PyObject *d_name; + PyObject *d_qualname; } PyDescrObject; #define PyDescr_COMMON PyDescrObject d_common diff -r 9c34ead53f94 Lib/test/test_sys.py --- a/Lib/test/test_sys.py Thu Dec 08 17:56:55 2011 +0000 +++ b/Lib/test/test_sys.py Sun Dec 11 14:27:47 2011 +0000 @@ -670,17 +670,17 @@ # complex check(complex(0,1), size(h + '2d')) # method_descriptor (descriptor object) - check(str.lower, size(h + '2PP')) + check(str.lower, size(h + '3PP')) # classmethod_descriptor (descriptor object) # XXX # member_descriptor (descriptor object) import datetime - check(datetime.timedelta.days, size(h + '2PP')) + check(datetime.timedelta.days, size(h + '3PP')) # getset_descriptor (descriptor object) import collections - check(collections.defaultdict.default_factory, size(h + '2PP')) + check(collections.defaultdict.default_factory, size(h + '3PP')) # wrapper_descriptor (descriptor object) - check(int.__add__, size(h + '2P2P')) + check(int.__add__, size(h + '3P2P')) # method-wrapper (descriptor object) check({}.__iter__, size(h + '2P')) # dict diff -r 9c34ead53f94 Objects/descrobject.c --- a/Objects/descrobject.c Thu Dec 08 17:56:55 2011 +0000 +++ b/Objects/descrobject.c Sun Dec 11 14:27:47 2011 +0000 @@ -9,6 +9,7 @@ _PyObject_GC_UNTRACK(descr); Py_XDECREF(descr->d_type); Py_XDECREF(descr->d_name); + Py_XDECREF(descr->d_qualname); PyObject_GC_Del(descr); } @@ -321,6 +322,52 @@ return PyUnicode_FromString(descr->d_method->ml_doc); } +static PyObject * +calculate_qualname(PyDescrObject *descr) +{ + static PyObject *qualname = NULL; + PyObject *type_qualname, *res; + + if (qualname == NULL) { + qualname = PyUnicode_InternFromString("__qualname__"); + if (qualname == NULL) + return NULL; + } + + if (descr->d_name == NULL || !PyUnicode_Check(descr->d_name)) { + PyErr_SetString(PyExc_AssertionError, + ".__name__ is not a unicode object"); + return NULL; + } + + if (descr->d_type == NULL) { + PyErr_SetString(PyExc_AssertionError, + ".__objclass__ is null"); + return NULL; + } + + type_qualname = PyObject_GetAttr((PyObject *)descr->d_type, qualname); + if (type_qualname == NULL || !PyUnicode_Check(type_qualname)) { + PyErr_SetString(PyExc_AssertionError, ".__objclass__." + "__qualname__ is not a unicode object"); + Py_XDECREF(type_qualname); + return NULL; + } + + res = PyUnicode_FromFormat("%S.%S", type_qualname, descr->d_name); + Py_DECREF(type_qualname); + return res; +} + +static PyObject * +descr_get_qualname(PyDescrObject *descr) +{ + if (descr->d_qualname == NULL) + descr->d_qualname = calculate_qualname(descr); + Py_XINCREF(descr->d_qualname); + return descr->d_qualname; +} + static PyMemberDef descr_members[] = { {"__objclass__", T_OBJECT, offsetof(PyDescrObject, d_type), READONLY}, {"__name__", T_OBJECT, offsetof(PyDescrObject, d_name), READONLY}, @@ -329,6 +376,7 @@ static PyGetSetDef method_getset[] = { {"__doc__", (getter)method_get_doc}, + {"__qualname__", (getter)descr_get_qualname}, {0} }; @@ -344,6 +392,7 @@ static PyGetSetDef member_getset[] = { {"__doc__", (getter)member_get_doc}, + {"__qualname__", (getter)descr_get_qualname}, {0} }; @@ -359,6 +408,7 @@ static PyGetSetDef getset_getset[] = { {"__doc__", (getter)getset_get_doc}, + {"__qualname__", (getter)descr_get_qualname}, {0} }; @@ -374,6 +424,7 @@ static PyGetSetDef wrapperdescr_getset[] = { {"__doc__", (getter)wrapperdescr_get_doc}, + {"__qualname__", (getter)descr_get_qualname}, {0} }; @@ -585,6 +636,7 @@ Py_DECREF(descr); descr = NULL; } + descr->d_qualname = NULL; } return descr; } @@ -987,9 +1039,16 @@ } } +static PyObject * +wrapper_qualname(wrapperobject *wp) +{ + return descr_get_qualname((PyDescrObject *)wp->descr); +} + static PyGetSetDef wrapper_getsets[] = { {"__objclass__", (getter)wrapper_objclass}, {"__name__", (getter)wrapper_name}, + {"__qualname__", (getter)wrapper_qualname}, {"__doc__", (getter)wrapper_doc}, {0} };