gh-117281: Change weakref repr() to fully qualified name (#117285)

Use the fully qualified type name in repr() of weakref.ref and
weakref.proxy types.

Fix a crash in proxy_repr() when the reference is dead.

Add also test_ref_repr() and test_proxy_repr().
This commit is contained in:
Victor Stinner 2024-04-03 12:18:05 +02:00 committed by GitHub
parent 8987a5c809
commit 8ef98924d3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 57 additions and 8 deletions

View File

@ -116,6 +116,33 @@ class ReferencesTestCase(TestBase):
del o del o
repr(wr) repr(wr)
@support.cpython_only
def test_ref_repr(self):
obj = C()
ref = weakref.ref(obj)
self.assertRegex(repr(ref),
rf"<weakref at 0x[0-9a-fA-F]+; "
rf"to '{C.__module__}.{C.__qualname__}' "
rf"at 0x[0-9a-fA-F]+>")
obj = None
gc_collect()
self.assertRegex(repr(ref),
rf'<weakref at 0x[0-9a-fA-F]+; dead>')
# test type with __name__
class WithName:
@property
def __name__(self):
return "custom_name"
obj2 = WithName()
ref2 = weakref.ref(obj2)
self.assertRegex(repr(ref2),
rf"<weakref at 0x[0-9a-fA-F]+; "
rf"to '{WithName.__module__}.{WithName.__qualname__}' "
rf"at 0x[0-9a-fA-F]+ \(custom_name\)>")
def test_repr_failure_gh99184(self): def test_repr_failure_gh99184(self):
class MyConfig(dict): class MyConfig(dict):
def __getattr__(self, x): def __getattr__(self, x):
@ -195,6 +222,20 @@ class ReferencesTestCase(TestBase):
self.assertRaises(ReferenceError, bool, ref3) self.assertRaises(ReferenceError, bool, ref3)
self.assertEqual(self.cbcalled, 2) self.assertEqual(self.cbcalled, 2)
@support.cpython_only
def test_proxy_repr(self):
obj = C()
ref = weakref.proxy(obj, self.callback)
self.assertRegex(repr(ref),
rf"<weakproxy at 0x[0-9a-fA-F]+; "
rf"to '{C.__module__}.{C.__qualname__}' "
rf"at 0x[0-9a-fA-F]+>")
obj = None
gc_collect()
self.assertRegex(repr(ref),
rf'<weakproxy at 0x[0-9a-fA-F]+; dead>')
def check_basic_ref(self, factory): def check_basic_ref(self, factory):
o = factory() o = factory()
ref = weakref.ref(o) ref = weakref.ref(o)

View File

@ -177,13 +177,13 @@ weakref_repr(PyObject *self)
PyObject *repr; PyObject *repr;
if (name == NULL || !PyUnicode_Check(name)) { if (name == NULL || !PyUnicode_Check(name)) {
repr = PyUnicode_FromFormat( repr = PyUnicode_FromFormat(
"<weakref at %p; to '%s' at %p>", "<weakref at %p; to '%T' at %p>",
self, Py_TYPE(obj)->tp_name, obj); self, obj, obj);
} }
else { else {
repr = PyUnicode_FromFormat( repr = PyUnicode_FromFormat(
"<weakref at %p; to '%s' at %p (%U)>", "<weakref at %p; to '%T' at %p (%U)>",
self, Py_TYPE(obj)->tp_name, obj, name); self, obj, obj, name);
} }
Py_DECREF(obj); Py_DECREF(obj);
Py_XDECREF(name); Py_XDECREF(name);
@ -471,10 +471,18 @@ static PyObject *
proxy_repr(PyObject *proxy) proxy_repr(PyObject *proxy)
{ {
PyObject *obj = _PyWeakref_GET_REF(proxy); PyObject *obj = _PyWeakref_GET_REF(proxy);
PyObject *repr = PyUnicode_FromFormat( PyObject *repr;
"<weakproxy at %p to %s at %p>", if (obj != NULL) {
proxy, Py_TYPE(obj)->tp_name, obj); repr = PyUnicode_FromFormat(
Py_DECREF(obj); "<weakproxy at %p; to '%T' at %p>",
proxy, obj, obj);
Py_DECREF(obj);
}
else {
repr = PyUnicode_FromFormat(
"<weakproxy at %p; dead>",
proxy);
}
return repr; return repr;
} }