From 556e94b8fe068d1d58064fe84467e0620b87f9ed Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Sat, 13 Apr 2013 15:45:44 +0100 Subject: [PATCH] Issue #17643: Add __callback__ attribute to weakref.ref. --- Doc/library/weakref.rst | 14 ++++++++++++-- Lib/test/test_weakref.py | 24 ++++++++++++++++++++++++ Misc/NEWS | 2 ++ Objects/weakrefobject.c | 7 ++++++- 4 files changed, 44 insertions(+), 3 deletions(-) diff --git a/Doc/library/weakref.rst b/Doc/library/weakref.rst index 1bf6b58770..78ff21d0c9 100644 --- a/Doc/library/weakref.rst +++ b/Doc/library/weakref.rst @@ -111,6 +111,15 @@ Extension types can easily be made to support weak references; see This is a subclassable type rather than a factory function. + .. attribute:: __callback__ + + This read-only attribute returns the callback currently associated to the + weakref. If there is no callback or if the referent of the weakref is + no longer alive then this attribute will have value ``None``. + + .. versionadded:: 3.4 + Added the :attr:`__callback__` attribute. + .. function:: proxy(object[, callback]) @@ -261,8 +270,9 @@ These method have the same issues as the and :meth:`keyrefs` method of Weak Reference Objects ---------------------- -Weak reference objects have no attributes or methods, but do allow the referent -to be obtained, if it still exists, by calling it: +Weak reference objects have no methods and no attributes besides +:attr:`ref.__callback__`. A weak reference object allows the referent to be +obtained, if it still exists, by calling it: >>> import weakref >>> class Object: diff --git a/Lib/test/test_weakref.py b/Lib/test/test_weakref.py index cdd26c76ae..e32e248561 100644 --- a/Lib/test/test_weakref.py +++ b/Lib/test/test_weakref.py @@ -802,6 +802,30 @@ class ReferencesTestCase(TestBase): del root gc.collect() + def test_callback_attribute(self): + x = Object(1) + callback = lambda ref: None + ref1 = weakref.ref(x, callback) + self.assertIs(ref1.__callback__, callback) + + ref2 = weakref.ref(x) + self.assertIsNone(ref2.__callback__) + + def test_callback_attribute_after_deletion(self): + x = Object(1) + ref = weakref.ref(x, self.callback) + self.assertIsNotNone(ref.__callback__) + del x + support.gc_collect() + self.assertIsNone(ref.__callback__) + + def test_set_callback_attribute(self): + x = Object(1) + callback = lambda ref: None + ref1 = weakref.ref(x, callback) + with self.assertRaises(AttributeError): + ref1.__callback__ = lambda ref: None + class SubclassableWeakrefTestCase(TestBase): diff --git a/Misc/NEWS b/Misc/NEWS index 4f42ff50b6..8adc9ef115 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ What's New in Python 3.4.0 Alpha 1? Core and Builtins ----------------- +- Issue #17643: Add __callback__ attribute to weakref.ref. + - Issue #16447: Fixed potential segmentation fault when setting __name__ on a class. diff --git a/Objects/weakrefobject.c b/Objects/weakrefobject.c index b49dcee1ad..c083f8fce5 100644 --- a/Objects/weakrefobject.c +++ b/Objects/weakrefobject.c @@ -338,6 +338,11 @@ weakref___init__(PyObject *self, PyObject *args, PyObject *kwargs) } +static PyMemberDef weakref_members[] = { + {"__callback__", T_OBJECT, offsetof(PyWeakReference, wr_callback), READONLY}, + {NULL} /* Sentinel */ +}; + PyTypeObject _PyWeakref_RefType = { PyVarObject_HEAD_INIT(&PyType_Type, 0) @@ -369,7 +374,7 @@ _PyWeakref_RefType = { 0, /*tp_iter*/ 0, /*tp_iternext*/ 0, /*tp_methods*/ - 0, /*tp_members*/ + weakref_members, /*tp_members*/ 0, /*tp_getset*/ 0, /*tp_base*/ 0, /*tp_dict*/ -- 2.40.0