diff options
author | Antoine Pitrou <solipsis@pitrou.net> | 2011-12-23 11:40:16 (GMT) |
---|---|---|
committer | Antoine Pitrou <solipsis@pitrou.net> | 2011-12-23 11:40:16 (GMT) |
commit | 5b62942074f2f6ae57c0e1bd8e4993dff4f5997f (patch) | |
tree | bf3f323f4b84a51edae986f2fee3686cc2d4c9bd | |
parent | d22983d081845009e894dced4c4d835f18755520 (diff) | |
download | cpython-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.h | 3 | ||||
-rw-r--r-- | Lib/test/test_funcattrs.py | 28 | ||||
-rw-r--r-- | Misc/NEWS | 3 | ||||
-rw-r--r-- | Objects/methodobject.c | 44 | ||||
-rw-r--r-- | Objects/typeobject.c | 2 |
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() @@ -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); |