diff --git a/Include/memoryobject.h b/Include/memoryobject.h index 4ac6f6525c9..c2e11944467 100644 --- a/Include/memoryobject.h +++ b/Include/memoryobject.h @@ -63,6 +63,7 @@ typedef struct { Py_ssize_t exports; /* number of buffer re-exports */ Py_buffer view; /* private copy of the exporter's view */ char format[_Py_MEMORYVIEW_MAX_FORMAT]; /* used for casting */ + PyObject *weakreflist; Py_ssize_t ob_array[1]; /* shape, strides, suboffsets */ } PyMemoryViewObject; #endif diff --git a/Lib/test/test_memoryview.py b/Lib/test/test_memoryview.py index 8809930acbe..5a33d035a18 100644 --- a/Lib/test/test_memoryview.py +++ b/Lib/test/test_memoryview.py @@ -336,6 +336,21 @@ class AbstractMemoryTests: m = self._view(b) self.assertRaises(ValueError, hash, m) + def test_weakref(self): + # Check memoryviews are weakrefable + for tp in self._types: + b = tp(self._source) + m = self._view(b) + L = [] + def callback(wr, b=b): + L.append(b) + wr = weakref.ref(m, callback) + self.assertIs(wr(), m) + del m + test.support.gc_collect() + self.assertIs(wr(), None) + self.assertIs(L[0], b) + # Variations on source objects for the buffer: bytes-like objects, then arrays # with itemsize > 1. # NOTE: support for multi-dimensional objects is unimplemented. diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index e3629ffc7ca..b024d9a261c 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -778,7 +778,7 @@ class SizeofTest(unittest.TestCase): check(int(PyLong_BASE**2-1), size(vh) + 2*self.longdigit) check(int(PyLong_BASE**2), size(vh) + 3*self.longdigit) # memoryview - check(memoryview(b''), size(h + 'PPiP4P2i5P3cP')) + check(memoryview(b''), size(h + 'PPiP4P2i5P3c2P')) # module check(unittest, size(h + '3P')) # None diff --git a/Misc/NEWS b/Misc/NEWS index 011cdf08fbf..10f05d803b7 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ What's New in Python 3.3.0 Alpha 4? Core and Builtins ----------------- +- Issue #14930: Make memoryview objects weakrefable. + - Issue #14775: Fix a potential quadratic dict build-up due to the garbage collector repeatedly trying to untrack dicts. diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c index 67f7e01fe28..62427d4b863 100644 --- a/Objects/memoryobject.c +++ b/Objects/memoryobject.c @@ -595,6 +595,7 @@ memory_alloc(int ndim) mv->view.shape = mv->ob_array; mv->view.strides = mv->ob_array + ndim; mv->view.suboffsets = mv->ob_array + 2 * ndim; + mv->weakreflist = NULL; _PyObject_GC_TRACK(mv); return mv; @@ -969,6 +970,8 @@ memory_dealloc(PyMemoryViewObject *self) _PyObject_GC_UNTRACK(self); (void)_memory_release(self); Py_CLEAR(self->mbuf); + if (self->weakreflist != NULL) + PyObject_ClearWeakRefs((PyObject *) self); PyObject_GC_Del(self); } @@ -2608,7 +2611,7 @@ PyTypeObject PyMemoryView_Type = { (traverseproc)memory_traverse, /* tp_traverse */ (inquiry)memory_clear, /* tp_clear */ memory_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ + offsetof(PyMemoryViewObject, weakreflist),/* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ memory_methods, /* tp_methods */