cpython: 92dcee426014 (original) (raw)
Mercurial > cpython
changeset 92170:92dcee426014
use __qualname__ to compute bound method repr (closes #21389) Patch from Steven Barker. [#21389]
Benjamin Peterson benjamin@python.org | |
---|---|
date | Wed, 20 Aug 2014 18:41:57 -0500 |
parents | 10d0a692b1b6 |
children | 5875c50e93fe |
files | Lib/test/test_defaultdict.py Lib/test/test_descr.py Misc/NEWS Objects/classobject.c |
diffstat | 4 files changed, 75 insertions(+), 33 deletions(-)[+] [-] Lib/test/test_defaultdict.py 5 Lib/test/test_descr.py 55 Misc/NEWS 3 Objects/classobject.c 45 |
line wrap: on
line diff
--- a/Lib/test/test_defaultdict.py +++ b/Lib/test/test_defaultdict.py @@ -157,8 +157,9 @@ class TestDefaultDict(unittest.TestCase) def _factory(self): return [] d = sub()
self.assertTrue(repr(d).startswith([](#l1.7)
"defaultdict(<bound method sub._factory of defaultdict(..."))[](#l1.8)
self.assertRegex(repr(d),[](#l1.9)
r"defaultdict\(<bound method .*sub\._factory "[](#l1.10)
r"of defaultdict\(\.\.\., \{\}\)>, \{\}\)")[](#l1.11)
# NOTE: printing a subclass of a builtin type does not call its # tp_print slot. So this part is essentially the same test as above.
--- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -4423,6 +4423,61 @@ order (MRO) for bases """ self.assertIn("dict", Base.dict) self.assertNotIn("dict", Sub.dict)
- def test_bound_method_repr(self):
class Foo:[](#l2.8)
def method(self):[](#l2.9)
pass[](#l2.10)
self.assertRegex(repr(Foo().method),[](#l2.11)
r"<bound method .*Foo\.method of <.*Foo object at .*>>")[](#l2.12)
class Base:[](#l2.15)
def method(self):[](#l2.16)
pass[](#l2.17)
class Derived1(Base):[](#l2.18)
pass[](#l2.19)
class Derived2(Base):[](#l2.20)
def method(self):[](#l2.21)
pass[](#l2.22)
base = Base()[](#l2.23)
derived1 = Derived1()[](#l2.24)
derived2 = Derived2()[](#l2.25)
super_d2 = super(Derived2, derived2)[](#l2.26)
self.assertRegex(repr(base.method),[](#l2.27)
r"<bound method .*Base\.method of <.*Base object at .*>>")[](#l2.28)
self.assertRegex(repr(derived1.method),[](#l2.29)
r"<bound method .*Base\.method of <.*Derived1 object at .*>>")[](#l2.30)
self.assertRegex(repr(derived2.method),[](#l2.31)
r"<bound method .*Derived2\.method of <.*Derived2 object at .*>>")[](#l2.32)
self.assertRegex(repr(super_d2.method),[](#l2.33)
r"<bound method .*Base\.method of <.*Derived2 object at .*>>")[](#l2.34)
class Foo:[](#l2.36)
@classmethod[](#l2.37)
def method(cls):[](#l2.38)
pass[](#l2.39)
foo = Foo()[](#l2.40)
self.assertRegex(repr(foo.method), # access via instance[](#l2.41)
r"<bound method .*Foo\.method of <class '.*Foo'>>")[](#l2.42)
self.assertRegex(repr(Foo.method), # access via the class[](#l2.43)
r"<bound method .*Foo\.method of <class '.*Foo'>>")[](#l2.44)
class MyCallable:[](#l2.47)
def __call__(self, arg):[](#l2.48)
pass[](#l2.49)
func = MyCallable() # func has no __name__ or __qualname__ attributes[](#l2.50)
instance = object()[](#l2.51)
method = types.MethodType(func, instance)[](#l2.52)
self.assertRegex(repr(method),[](#l2.53)
r"<bound method \? of <object object at .*>>")[](#l2.54)
func.__name__ = "name"[](#l2.55)
self.assertRegex(repr(method),[](#l2.56)
r"<bound method name of <object object at .*>>")[](#l2.57)
func.__qualname__ = "qualname"[](#l2.58)
self.assertRegex(repr(method),[](#l2.59)
r"<bound method qualname of <object object at .*>>")[](#l2.60)
+ class DictProxyTests(unittest.TestCase): def setUp(self):
--- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Release date: TBA Core and Builtins ----------------- +- Issue #21389: Displaying the qualname of the underlying function in the
- Issue #22206: Using pthread, PyThread_create_key() now sets errno to ENOMEM and returns -1 (error) on integer overflow.
--- a/Objects/classobject.c +++ b/Objects/classobject.c @@ -15,6 +15,7 @@ static int numfree = 0; #endif _Py_IDENTIFIER(name); +_Py_IDENTIFIER(qualname); PyObject * PyMethod_Function(PyObject *im) @@ -243,51 +244,33 @@ method_repr(PyMethodObject *a) { PyObject *self = a->im_self; PyObject *func = a->im_func;
- if (self == NULL) {
PyErr_BadInternalCall();[](#l4.22)
return NULL;[](#l4.23)
- }
- klass = (PyObject*)Py_TYPE(self);
- funcname = PyObject_GetAttrId(func, &PyId___qualname_); if (funcname == NULL) { if (!PyErr_ExceptionMatches(PyExc_AttributeError)) return NULL; PyErr_Clear();
funcname = _PyObject_GetAttrId(func, &PyId___name__);[](#l4.34)
if (funcname == NULL) {[](#l4.35)
if (!PyErr_ExceptionMatches(PyExc_AttributeError))[](#l4.36)
return NULL;[](#l4.37)
PyErr_Clear();[](#l4.38)
}}[](#l4.39)
- if (klass == NULL)
klassname = NULL;[](#l4.49)
- else {
klassname = _PyObject_GetAttrId(klass, &PyId___name__);[](#l4.51)
if (klassname == NULL) {[](#l4.52)
if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {[](#l4.53)
Py_XDECREF(funcname);[](#l4.54)
return NULL;[](#l4.55)
}[](#l4.56)
PyErr_Clear();[](#l4.57)
}[](#l4.58)
else if (!PyUnicode_Check(klassname)) {[](#l4.59)
Py_DECREF(klassname);[](#l4.60)
klassname = NULL;[](#l4.61)
}[](#l4.62)
- }