Expanded ref checks

Fixed ref cycle in ImageItem -> HistogramLutItem
This commit is contained in:
Luke Campagnola 2014-04-27 13:07:31 -04:00
parent d45eadc9a5
commit 0479507dbb
2 changed files with 36 additions and 47 deletions

View File

@ -17,6 +17,7 @@ from .. import functions as fn
import numpy as np import numpy as np
from .. import debug as debug from .. import debug as debug
import weakref
__all__ = ['HistogramLUTItem'] __all__ = ['HistogramLUTItem']
@ -42,7 +43,7 @@ class HistogramLUTItem(GraphicsWidget):
""" """
GraphicsWidget.__init__(self) GraphicsWidget.__init__(self)
self.lut = None self.lut = None
self.imageItem = None self.imageItem = lambda: None # fake a dead weakref
self.layout = QtGui.QGraphicsGridLayout() self.layout = QtGui.QGraphicsGridLayout()
self.setLayout(self.layout) self.setLayout(self.layout)
@ -138,7 +139,7 @@ class HistogramLUTItem(GraphicsWidget):
#self.region.setBounds([vr.top(), vr.bottom()]) #self.region.setBounds([vr.top(), vr.bottom()])
def setImageItem(self, img): def setImageItem(self, img):
self.imageItem = img self.imageItem = weakref.ref(img)
img.sigImageChanged.connect(self.imageChanged) img.sigImageChanged.connect(self.imageChanged)
img.setLookupTable(self.getLookupTable) ## send function pointer, not the result img.setLookupTable(self.getLookupTable) ## send function pointer, not the result
#self.gradientChanged() #self.gradientChanged()
@ -150,11 +151,11 @@ class HistogramLUTItem(GraphicsWidget):
self.update() self.update()
def gradientChanged(self): def gradientChanged(self):
if self.imageItem is not None: if self.imageItem() is not None:
if self.gradient.isLookupTrivial(): if self.gradient.isLookupTrivial():
self.imageItem.setLookupTable(None) #lambda x: x.astype(np.uint8)) self.imageItem().setLookupTable(None) #lambda x: x.astype(np.uint8))
else: else:
self.imageItem.setLookupTable(self.getLookupTable) ## send function pointer, not the result self.imageItem().setLookupTable(self.getLookupTable) ## send function pointer, not the result
self.lut = None self.lut = None
#if self.imageItem is not None: #if self.imageItem is not None:
@ -178,14 +179,14 @@ class HistogramLUTItem(GraphicsWidget):
#self.update() #self.update()
def regionChanging(self): def regionChanging(self):
if self.imageItem is not None: if self.imageItem() is not None:
self.imageItem.setLevels(self.region.getRegion()) self.imageItem().setLevels(self.region.getRegion())
self.sigLevelsChanged.emit(self) self.sigLevelsChanged.emit(self)
self.update() self.update()
def imageChanged(self, autoLevel=False, autoRange=False): def imageChanged(self, autoLevel=False, autoRange=False):
profiler = debug.Profiler() profiler = debug.Profiler()
h = self.imageItem.getHistogram() h = self.imageItem().getHistogram()
profiler('get histogram') profiler('get histogram')
if h[0] is None: if h[0] is None:
return return

View File

@ -7,54 +7,42 @@ import numpy as np
import gc, weakref import gc, weakref
app = pg.mkQApp() app = pg.mkQApp()
def processEvents(): def assert_alldead(refs):
for i in range(3): for ref in refs:
gc.collect() assert ref() is None
app.processEvents()
# processEvents ignored DeferredDelete events; we must process these
# manually.
app.sendPostedEvents(None, pg.QtCore.QEvent.DeferredDelete)
#def test_PlotItem(): def mkrefs(*objs):
#for i in range(10): return map(weakref.ref, objs)
#plt = pg.PlotItem()
#plt.plot(np.random.normal(size=10000))
#processEvents()
#ot = pg.debug.ObjTracker()
#plots = []
#for i in range(10):
#plt = pg.PlotItem()
#plt.plot(np.random.normal(size=10000))
#plots.append(plt)
#processEvents()
#ot.diff()
#del plots
#processEvents()
#ot.diff()
#return ot
def test_PlotWidget(): def test_PlotWidget():
def mkref(*args, **kwds): def mkobjs(*args, **kwds):
iv = pg.PlotWidget(*args, **kwds) w = pg.PlotWidget(*args, **kwds)
return weakref.ref(iv) data = pg.np.array([1,5,2,4,3])
c = w.plot(data, name='stuff')
w.addLegend()
# test that connections do not keep objects alive
w.plotItem.vb.sigRangeChanged.connect(mkrefs)
app.focusChanged.connect(w.plotItem.vb.invertY)
# return weakrefs to a bunch of objects that should die when the scope exits.
return mkrefs(w, c, data, w.plotItem, w.plotItem.vb, w.plotItem.getMenu(), w.plotItem.getAxis('left'))
for i in range(5): for i in range(5):
assert mkref()() is None assert_alldead(mkobjs())
def test_ImageView(): def test_ImageView():
def mkref(*args, **kwds): def mkobjs():
iv = pg.ImageView(*args, **kwds) iv = pg.ImageView()
return weakref.ref(iv) data = np.zeros((10,10,5))
iv.setImage(data)
return mkrefs(iv, iv.imageItem, iv.view, iv.ui.histogram, data)
for i in range(5): for i in range(5):
assert mkref()() is None assert_alldead(mkobjs())
if __name__ == '__main__': if __name__ == '__main__':
ot = test_PlotItem() ot = test_PlotItem()