summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAntoine Pitrou <solipsis@pitrou.net>2011-12-23 11:40:16 (GMT)
committerAntoine Pitrou <solipsis@pitrou.net>2011-12-23 11:40:16 (GMT)
commit5b62942074f2f6ae57c0e1bd8e4993dff4f5997f (patch)
treebf3f323f4b84a51edae986f2fee3686cc2d4c9bd
parentd22983d081845009e894dced4c4d835f18755520 (diff)
downloadcpython-5b62942074f2f6ae57c0e1bd8e4993dff4f5997f.zip
cpython-5b62942074f2f6ae57c0e1bd8e4993dff4f5997f.tar.gz
cpython-5b62942074f2f6ae57c0e1bd8e4993dff4f5997f.tar.bz2
Issue #13577: Built-in methods and functions now have a __qualname__.
Patch by sbt.
-rw-r--r--Include/methodobject.h3
-rw-r--r--Lib/test/test_funcattrs.py28
-rw-r--r--Misc/NEWS3
-rw-r--r--Objects/methodobject.c44
-rw-r--r--Objects/typeobject.c2
5 files changed, 73 insertions, 7 deletions
diff --git a/Include/methodobject.h b/Include/methodobject.h
index 7e67c0b..d798d13 100644
--- a/Include/methodobject.h
+++ b/Include/methodobject.h
@@ -30,7 +30,8 @@ PyAPI_FUNC(int) PyCFunction_GetFlags(PyObject *);
#define PyCFunction_GET_FUNCTION(func) \
(((PyCFunctionObject *)func) -> m_ml -> ml_meth)
#define PyCFunction_GET_SELF(func) \
- (((PyCFunctionObject *)func) -> m_self)
+ (((PyCFunctionObject *)func) -> m_ml -> ml_flags & METH_STATIC ? \
+ NULL : ((PyCFunctionObject *)func) -> m_self)
#define PyCFunction_GET_FLAGS(func) \
(((PyCFunctionObject *)func) -> m_ml -> ml_flags)
#endif
diff --git a/Lib/test/test_funcattrs.py b/Lib/test/test_funcattrs.py
index f4a38b9..c8ed830 100644
--- a/Lib/test/test_funcattrs.py
+++ b/Lib/test/test_funcattrs.py
@@ -342,11 +342,37 @@ class StaticMethodAttrsTest(unittest.TestCase):
self.assertTrue(s.__func__ is f)
+class BuiltinFunctionPropertiesTest(unittest.TestCase):
+ # XXX Not sure where this should really go since I can't find a
+ # test module specifically for builtin_function_or_method.
+
+ def test_builtin__qualname__(self):
+ import time
+
+ # builtin function:
+ self.assertEqual(len.__qualname__, 'len')
+ self.assertEqual(time.time.__qualname__, 'time')
+
+ # builtin classmethod:
+ self.assertEqual(dict.fromkeys.__qualname__, 'dict.fromkeys')
+ self.assertEqual(float.__getformat__.__qualname__,
+ 'float.__getformat__')
+
+ # builtin staticmethod:
+ self.assertEqual(str.maketrans.__qualname__, 'str.maketrans')
+ self.assertEqual(bytes.maketrans.__qualname__, 'bytes.maketrans')
+
+ # builtin bound instance method:
+ self.assertEqual([1, 2, 3].append.__qualname__, 'list.append')
+ self.assertEqual({'foo': 'bar'}.pop.__qualname__, 'dict.pop')
+
+
def test_main():
support.run_unittest(FunctionPropertiesTest, InstancemethodAttrTest,
ArbitraryFunctionAttrTest, FunctionDictsTest,
FunctionDocstringTest, CellTest,
- StaticMethodAttrsTest)
+ StaticMethodAttrsTest,
+ BuiltinFunctionPropertiesTest)
if __name__ == "__main__":
test_main()
diff --git a/Misc/NEWS b/Misc/NEWS
index cff3140..1dc721a 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,9 @@ What's New in Python 3.3 Alpha 1?
Core and Builtins
-----------------
+- Issue #13577: Built-in methods and functions now have a __qualname__.
+ Patch by sbt.
+
- Issue #6695: Full garbage collection runs now clear the freelist of set
objects. Initial patch by Matthias Troffaes.
diff --git a/Objects/methodobject.c b/Objects/methodobject.c
index a7334cf..c3a6409 100644
--- a/Objects/methodobject.c
+++ b/Objects/methodobject.c
@@ -44,7 +44,7 @@ PyCFunction_GetFunction(PyObject *op)
PyErr_BadInternalCall();
return NULL;
}
- return ((PyCFunctionObject *)op) -> m_ml -> ml_meth;
+ return PyCFunction_GET_FUNCTION(op);
}
PyObject *
@@ -54,7 +54,7 @@ PyCFunction_GetSelf(PyObject *op)
PyErr_BadInternalCall();
return NULL;
}
- return ((PyCFunctionObject *)op) -> m_self;
+ return PyCFunction_GET_SELF(op);
}
int
@@ -64,7 +64,7 @@ PyCFunction_GetFlags(PyObject *op)
PyErr_BadInternalCall();
return -1;
}
- return ((PyCFunctionObject *)op) -> m_ml -> ml_flags;
+ return PyCFunction_GET_FLAGS(op);
}
PyObject *
@@ -151,6 +151,41 @@ meth_get__name__(PyCFunctionObject *m, void *closure)
return PyUnicode_FromString(m->m_ml->ml_name);
}
+static PyObject *
+meth_get__qualname__(PyCFunctionObject *m, void *closure)
+{
+ /* If __self__ is a module or NULL, return m.__name__
+ (e.g. len.__qualname__ == 'len')
+
+ If __self__ is a type, return m.__self__.__qualname__ + '.' + m.__name__
+ (e.g. dict.fromkeys.__qualname__ == 'dict.fromkeys')
+
+ Otherwise return type(m.__self__).__qualname__ + '.' + m.__name__
+ (e.g. [].append.__qualname__ == 'list.append') */
+ PyObject *type, *type_qualname, *res;
+ _Py_IDENTIFIER(__qualname__);
+
+ if (m->m_self == NULL || PyModule_Check(m->m_self))
+ return PyUnicode_FromString(m->m_ml->ml_name);
+
+ type = PyType_Check(m->m_self) ? m->m_self : (PyObject*)Py_TYPE(m->m_self);
+
+ type_qualname = _PyObject_GetAttrId(type, &PyId___qualname__);
+ if (type_qualname == NULL)
+ return NULL;
+
+ if (!PyUnicode_Check(type_qualname)) {
+ PyErr_SetString(PyExc_TypeError, "<method>.__class__."
+ "__qualname__ is not a unicode object");
+ Py_XDECREF(type_qualname);
+ return NULL;
+ }
+
+ res = PyUnicode_FromFormat("%S.%s", type_qualname, m->m_ml->ml_name);
+ Py_DECREF(type_qualname);
+ return res;
+}
+
static int
meth_traverse(PyCFunctionObject *m, visitproc visit, void *arg)
{
@@ -164,7 +199,7 @@ meth_get__self__(PyCFunctionObject *m, void *closure)
{
PyObject *self;
- self = m->m_self;
+ self = PyCFunction_GET_SELF(m);
if (self == NULL)
self = Py_None;
Py_INCREF(self);
@@ -174,6 +209,7 @@ meth_get__self__(PyCFunctionObject *m, void *closure)
static PyGetSetDef meth_getsets [] = {
{"__doc__", (getter)meth_get__doc__, NULL, NULL},
{"__name__", (getter)meth_get__name__, NULL, NULL},
+ {"__qualname__", (getter)meth_get__qualname__, NULL, NULL},
{"__self__", (getter)meth_get__self__, NULL, NULL},
{0}
};
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 02999d6..508e35c4 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -3726,7 +3726,7 @@ add_methods(PyTypeObject *type, PyMethodDef *meth)
descr = PyDescr_NewClassMethod(type, meth);
}
else if (meth->ml_flags & METH_STATIC) {
- PyObject *cfunc = PyCFunction_New(meth, NULL);
+ PyObject *cfunc = PyCFunction_New(meth, (PyObject*)type);
if (cfunc == NULL)
return -1;
descr = PyStaticMethod_New(cfunc);