diff --git a/pyqtgraph/Qt.py b/pyqtgraph/Qt.py index 62ffa2d0..2fcff32f 100644 --- a/pyqtgraph/Qt.py +++ b/pyqtgraph/Qt.py @@ -32,8 +32,22 @@ else: if USE_PYSIDE: from PySide import QtGui, QtCore, QtOpenGL, QtSvg import PySide - from PySide import shiboken - isQObjectAlive = shiboken.isValid + try: + from PySide import shiboken + isQObjectAlive = shiboken.isValid + except ImportError: + def isQObjectAlive(obj): + try: + if hasattr(obj, 'parent'): + obj.parent() + elif hasattr(obj, 'parentItem'): + obj.parentItem() + else: + raise Exception("Cannot determine whether Qt object %s is still alive." % obj) + except RuntimeError: + return False + else: + return True VERSION_INFO = 'PySide ' + PySide.__version__ @@ -82,7 +96,8 @@ else: import sip - isQObjectAlive = sip.isdeleted + def isQObjectAlive(obj): + return not sip.isdeleted(obj) loadUiType = uic.loadUiType QtCore.Signal = QtCore.pyqtSignal diff --git a/pyqtgraph/__init__.py b/pyqtgraph/__init__.py index cd78cfa8..64c642c0 100644 --- a/pyqtgraph/__init__.py +++ b/pyqtgraph/__init__.py @@ -56,6 +56,7 @@ CONFIG_OPTIONS = { 'weaveDebug': False, ## Print full error message if weave compile fails 'exitCleanup': True, ## Attempt to work around some exit crash bugs in PyQt and PySide 'enableExperimental': False, ## Enable experimental features (the curious can search for this key in the code) + 'crashWarning': False, # If True, print warnings about situations that may result in a crash } @@ -286,8 +287,10 @@ def cleanup(): for o in gc.get_objects(): try: if isinstance(o, QtGui.QGraphicsItem) and isQObjectAlive(o) and o.scene() is None: - sys.stderr.write( - 'Error: graphics item without scene. Make sure ViewBox.close() and GraphicsView.close() are properly called before app shutdown (%s)\n' % (o,)) + if getConfigOption('crashWarning'): + sys.stderr.write('Error: graphics item without scene. ' + 'Make sure ViewBox.close() and GraphicsView.close() ' + 'are properly called before app shutdown (%s)\n' % (o,)) s.addItem(o) except RuntimeError: ## occurs if a python wrapper no longer has its underlying C++ object diff --git a/pyqtgraph/graphicsItems/PlotItem/PlotItem.py b/pyqtgraph/graphicsItems/PlotItem/PlotItem.py index c0b9adab..847ff3ac 100644 --- a/pyqtgraph/graphicsItems/PlotItem/PlotItem.py +++ b/pyqtgraph/graphicsItems/PlotItem/PlotItem.py @@ -295,22 +295,20 @@ class PlotItem(GraphicsWidget): #Important: don't use a settattr(m, getattr(self.vb, m)) as we'd be leaving the viebox alive #because we had a reference to an instance method (creating wrapper methods at runtime instead). - frame = sys._getframe() for m in [ 'setXRange', 'setYRange', 'setXLink', 'setYLink', 'setAutoPan', 'setAutoVisible', 'setRange', 'autoRange', 'viewRect', 'viewRange', 'setMouseEnabled', 'setLimits', 'enableAutoRange', 'disableAutoRange', 'setAspectLocked', 'invertY', 'register', 'unregister']: ## NOTE: If you update this list, please update the class docstring as well. - def _create_method(name): # @NoSelf + def _create_method(name): def method(self, *args, **kwargs): return getattr(self.vb, name)(*args, **kwargs) method.__name__ = name return method - frame.f_locals[m] = _create_method(m) + locals()[m] = _create_method(m) del _create_method - del frame def setLogMode(self, x=None, y=None): """ diff --git a/pyqtgraph/graphicsItems/ViewBox/ViewBox.py b/pyqtgraph/graphicsItems/ViewBox/ViewBox.py index ef5b4319..b27e6e4b 100644 --- a/pyqtgraph/graphicsItems/ViewBox/ViewBox.py +++ b/pyqtgraph/graphicsItems/ViewBox/ViewBox.py @@ -1655,8 +1655,8 @@ class ViewBox(GraphicsWidget): ## called when the application is about to exit. ## this disables all callbacks, which might otherwise generate errors if invoked during exit. for k in ViewBox.AllViews: - if isQObjectAlive(k): - sys.stderr.write('ViewBox should be closed before application exit!') + if isQObjectAlive(k) and getConfigOption('crashWarning'): + sys.stderr.write('Warning: ViewBox should be closed before application exit.\n') try: k.destroyed.disconnect() diff --git a/pyqtgraph/tests/test_qt.py b/pyqtgraph/tests/test_qt.py new file mode 100644 index 00000000..cef54777 --- /dev/null +++ b/pyqtgraph/tests/test_qt.py @@ -0,0 +1,10 @@ +import pyqtgraph as pg +import gc + +def test_isQObjectAlive(): + o1 = pg.QtCore.QObject() + o2 = pg.QtCore.QObject() + o2.setParent(o1) + del o1 + gc.collect() + assert not pg.Qt.isQObjectAlive(o2)