[Python-checkins] cpython: Issue #13577: various kinds of descriptors now have a __qualname__ attribute.
antoine.pitrou
python-checkins at python.org
Mon Dec 12 13:47:40 CET 2011
http://hg.python.org/cpython/rev/24238e89f938
changeset: 73948:24238e89f938
user: Antoine Pitrou <solipsis at pitrou.net>
date: Mon Dec 12 13:47:25 2011 +0100
summary:
Issue #13577: various kinds of descriptors now have a __qualname__ attribute.
Patch by sbt.
files:
Include/descrobject.h | 1 +
Lib/test/test_descr.py | 18 ++++++++++
Lib/test/test_sys.py | 8 ++--
Objects/descrobject.c | 51 ++++++++++++++++++++++++++++++
4 files changed, 74 insertions(+), 4 deletions(-)
diff --git a/Include/descrobject.h b/Include/descrobject.h
--- a/Include/descrobject.h
+++ b/Include/descrobject.h
@@ -42,6 +42,7 @@
PyObject_HEAD
PyTypeObject *d_type;
PyObject *d_name;
+ PyObject *d_qualname;
} PyDescrObject;
#define PyDescr_COMMON PyDescrObject d_common
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -4442,6 +4442,24 @@
self.assertIn("can't delete X.__doc__", str(cm.exception))
self.assertEqual(X.__doc__, "banana")
+ def test_qualname(self):
+ descriptors = [str.lower, complex.real, float.real, int.__add__]
+ types = ['method', 'member', 'getset', 'wrapper']
+
+ # make sure we have an example of each type of descriptor
+ for d, n in zip(descriptors, types):
+ self.assertEqual(type(d).__name__, n + '_descriptor')
+
+ for d in descriptors:
+ qualname = d.__objclass__.__qualname__ + '.' + d.__name__
+ self.assertEqual(d.__qualname__, qualname)
+
+ self.assertEqual(str.lower.__qualname__, 'str.lower')
+ self.assertEqual(complex.real.__qualname__, 'complex.real')
+ self.assertEqual(float.real.__qualname__, 'float.real')
+ self.assertEqual(int.__add__.__qualname__, 'int.__add__')
+
+
class DictProxyTests(unittest.TestCase):
def setUp(self):
class C(object):
diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py
--- a/Lib/test/test_sys.py
+++ b/Lib/test/test_sys.py
@@ -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 --git a/Objects/descrobject.c b/Objects/descrobject.c
--- a/Objects/descrobject.c
+++ b/Objects/descrobject.c
@@ -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,44 @@
return PyUnicode_FromString(descr->d_method->ml_doc);
}
+static PyObject *
+calculate_qualname(PyDescrObject *descr)
+{
+ PyObject *type_qualname, *res;
+ _Py_IDENTIFIER(__qualname__);
+
+ if (descr->d_name == NULL || !PyUnicode_Check(descr->d_name)) {
+ PyErr_SetString(PyExc_TypeError,
+ "<descriptor>.__name__ is not a unicode object");
+ return NULL;
+ }
+
+ type_qualname = _PyObject_GetAttrId((PyObject *)descr->d_type,
+ &PyId___qualname__);
+ if (type_qualname == NULL)
+ return NULL;
+
+ if (!PyUnicode_Check(type_qualname)) {
+ PyErr_SetString(PyExc_TypeError, "<descriptor>.__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 +368,7 @@
static PyGetSetDef method_getset[] = {
{"__doc__", (getter)method_get_doc},
+ {"__qualname__", (getter)descr_get_qualname},
{0}
};
@@ -344,6 +384,7 @@
static PyGetSetDef member_getset[] = {
{"__doc__", (getter)member_get_doc},
+ {"__qualname__", (getter)descr_get_qualname},
{0}
};
@@ -359,6 +400,7 @@
static PyGetSetDef getset_getset[] = {
{"__doc__", (getter)getset_get_doc},
+ {"__qualname__", (getter)descr_get_qualname},
{0}
};
@@ -374,6 +416,7 @@
static PyGetSetDef wrapperdescr_getset[] = {
{"__doc__", (getter)wrapperdescr_get_doc},
+ {"__qualname__", (getter)descr_get_qualname},
{0}
};
@@ -585,6 +628,7 @@
Py_DECREF(descr);
descr = NULL;
}
+ descr->d_qualname = NULL;
}
return descr;
}
@@ -987,9 +1031,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}
};
--
Repository URL: http://hg.python.org/cpython
More information about the Python-checkins
mailing list