From de11e6315cb6262344fc38b9a1f88f61e5deb8e5 Mon Sep 17 00:00:00 2001 From: KIU Shueng Chuan Date: Mon, 8 Feb 2021 14:11:20 +0800 Subject: [PATCH 1/5] let examples have a chance to exit normally cleanup imported module 1) instantiate MainWindow class if present 2) delete attributes from imported module when done --- examples/test_examples.py | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/examples/test_examples.py b/examples/test_examples.py index ba1037ad..66be7ae0 100644 --- a/examples/test_examples.py +++ b/examples/test_examples.py @@ -212,22 +212,23 @@ def testExamples(frontend, f): import2 = os.path.splitext(os.path.split(fn)[1])[0] code = """ try: - %s + {0} import initExample import pyqtgraph as pg - import %s + import {1} import sys print("test complete") sys.stdout.flush() - import time - while True: ## run a little event loop - pg.QtGui.QApplication.processEvents() - time.sleep(0.01) + pg.Qt.QtCore.QTimer.singleShot(1000, pg.Qt.QtWidgets.QApplication.quit) + pg.Qt.QtWidgets.QApplication.instance().exec_() + names = [x for x in dir({1}) if not x.startswith('_')] + for name in names: + delattr({1}, name) except: print("test failed") raise -""" % (import1, import2) +""".format(import1, import2) if sys.platform.startswith('win'): process = subprocess.Popen([sys.executable], stdin=subprocess.PIPE, @@ -259,8 +260,13 @@ except: if output.endswith('test failed'): fail = True break - time.sleep(1) - process.kill() + start = time.time() + killed = False + while process.poll() is None: + time.sleep(0.1) + if time.time() - start > 2.0 and not killed: + process.kill() + killed = True #res = process.communicate() res = (process.stdout.read(), process.stderr.read()) if (fail or From 5f6be29f66f1c482322cb9814bb603947378352d Mon Sep 17 00:00:00 2001 From: Kiu Shueng Chuan Date: Fri, 26 Feb 2021 10:28:09 +0800 Subject: [PATCH 2/5] connect paletteChanged to standalone function --- pyqtgraph/Qt.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/pyqtgraph/Qt.py b/pyqtgraph/Qt.py index 142b3f30..f3b0f5cb 100644 --- a/pyqtgraph/Qt.py +++ b/pyqtgraph/Qt.py @@ -464,16 +464,8 @@ if m is not None and list(map(int, m.groups())) < versionReq: print(list(map(int, m.groups()))) raise Exception('pyqtgraph requires Qt version >= %d.%d (your version is %s)' % (versionReq[0], versionReq[1], QtVersion)) -class App(QtGui.QApplication): - - def __init__(self, *args, **kwargs): - super(App, self).__init__(*args, **kwargs) - self.paletteChanged.connect(self.onPaletteChange) - self.onPaletteChange(self.palette()) - - def onPaletteChange(self, palette): - color = palette.base().color().name() - self.setProperty('darkMode', color.lower() != "#ffffff") +App = QtWidgets.QApplication +# subclassing QApplication causes segfaults on PySide{2, 6} / Python 3.8.7+ QAPP = None def mkQApp(name=None): @@ -487,6 +479,11 @@ def mkQApp(name=None): """ global QAPP + def onPaletteChange(palette): + color = palette.base().color().name() + app = QtWidgets.QApplication.instance() + app.setProperty('darkMode', color.lower() != "#ffffff") + QAPP = QtGui.QApplication.instance() if QAPP is None: # hidpi handling @@ -500,7 +497,9 @@ def mkQApp(name=None): else: # qt 5.12 and 5.13 QtGui.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling) QtGui.QApplication.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps) - QAPP = App(sys.argv or ["pyqtgraph"]) + QAPP = QtGui.QApplication(sys.argv or ["pyqtgraph"]) + QAPP.paletteChanged.connect(onPaletteChange) + QAPP.paletteChanged.emit(QAPP.palette()) if name is not None: QAPP.setApplicationName(name) From 1ad7d4990810def11b326ad7b4d4933c178a0552 Mon Sep 17 00:00:00 2001 From: Kiu Shueng Chuan Date: Fri, 26 Feb 2021 13:38:12 +0800 Subject: [PATCH 3/5] de-duplicate Big Sur opengl skip testing --- examples/test_examples.py | 107 ++++++++++---------------------------- 1 file changed, 27 insertions(+), 80 deletions(-) diff --git a/examples/test_examples.py b/examples/test_examples.py index 66be7ae0..bb399f6d 100644 --- a/examples/test_examples.py +++ b/examples/test_examples.py @@ -56,6 +56,13 @@ installedFrontends = sorted([ frontend for frontend, isPresent in frontends.items() if isPresent ]) +darwin_opengl_broken = (platform.system() == "Darwin" and + tuple(map(int, platform.mac_ver()[0].split("."))) >= (10, 16) and + (sys.version_info <= (3, 8, 7) or (3, 9) <= sys.version_info < (3, 9, 1))) + +darwin_opengl_reason = ("pyopenGL cannot find openGL library on big sur: " + "https://github.com/python/cpython/pull/21241") + exceptionCondition = namedtuple("exceptionCondition", ["condition", "reason"]) conditionalExamples = { "test_ExampleApp.py": exceptionCondition( @@ -71,104 +78,44 @@ conditionalExamples = { reason="Test is being problematic on CI machines" ), 'GLVolumeItem.py': exceptionCondition( - not(platform.system() == "Darwin" and - tuple(map(int, platform.mac_ver()[0].split("."))) >= (10, 16) and - (sys.version_info <= (3, 8, 7) or - (sys.version_info >= (3, 9) and sys.version_info < (3, 9, 1)))), - reason=( - "pyopenGL cannot find openGL libray on big sur: " - "https://github.com/python/cpython/pull/21241" - ) + not darwin_opengl_broken, + reason=darwin_opengl_reason ), 'GLIsosurface.py': exceptionCondition( - not(platform.system() == "Darwin" and - tuple(map(int, platform.mac_ver()[0].split("."))) >= (10, 16) and - (sys.version_info <= (3, 8, 7) or - (sys.version_info >= (3, 9) and sys.version_info < (3, 9, 1)))), - reason=( - "pyopenGL cannot find openGL libray on big sur: " - "https://github.com/python/cpython/pull/21241" - ) + not darwin_opengl_broken, + reason=darwin_opengl_reason ), 'GLSurfacePlot.py': exceptionCondition( - not(platform.system() == "Darwin" and - tuple(map(int, platform.mac_ver()[0].split("."))) >= (10, 16) and - (sys.version_info <= (3, 8, 7) or - (sys.version_info >= (3, 9) and sys.version_info < (3, 9, 1)))), - reason=( - "pyopenGL cannot find openGL libray on big sur: " - "https://github.com/python/cpython/pull/21241" - ) + not darwin_opengl_broken, + reason=darwin_opengl_reason ), 'GLScatterPlotItem.py': exceptionCondition( - not(platform.system() == "Darwin" and - tuple(map(int, platform.mac_ver()[0].split("."))) >= (10, 16) and - (sys.version_info <= (3, 8, 7) or - (sys.version_info >= (3, 9) and sys.version_info < (3, 9, 1)))), - reason=( - "pyopenGL cannot find openGL libray on big sur: " - "https://github.com/python/cpython/pull/21241" - ) + not darwin_opengl_broken, + reason=darwin_opengl_reason ), 'GLshaders.py': exceptionCondition( - not(platform.system() == "Darwin" and - tuple(map(int, platform.mac_ver()[0].split("."))) >= (10, 16) and - (sys.version_info <= (3, 8, 7) or - (sys.version_info >= (3, 9) and sys.version_info < (3, 9, 1)))), - reason=( - "pyopenGL cannot find openGL libray on big sur: " - "https://github.com/python/cpython/pull/21241" - ) + not darwin_opengl_broken, + reason=darwin_opengl_reason ), 'GLLinePlotItem.py': exceptionCondition( - not(platform.system() == "Darwin" and - tuple(map(int, platform.mac_ver()[0].split("."))) >= (10, 16) and - (sys.version_info <= (3, 8, 7) or - (sys.version_info >= (3, 9) and sys.version_info < (3, 9, 1)))), - reason=( - "pyopenGL cannot find openGL libray on big sur: " - "https://github.com/python/cpython/pull/21241" - ) + not darwin_opengl_broken, + reason=darwin_opengl_reason ), 'GLMeshItem.py': exceptionCondition( - not(platform.system() == "Darwin" and - tuple(map(int, platform.mac_ver()[0].split("."))) >= (10, 16) and - (sys.version_info <= (3, 8, 7) or - (sys.version_info >= (3, 9) and sys.version_info < (3, 9, 1)))), - reason=( - "pyopenGL cannot find openGL libray on big sur: " - "https://github.com/python/cpython/pull/21241" - ) + not darwin_opengl_broken, + reason=darwin_opengl_reason ), 'GLImageItem.py': exceptionCondition( - not(platform.system() == "Darwin" and - tuple(map(int, platform.mac_ver()[0].split("."))) >= (10, 16) and - (sys.version_info <= (3, 8, 7) or - (sys.version_info >= (3, 9) and sys.version_info < (3, 9, 1)))), - reason=( - "pyopenGL cannot find openGL libray on big sur: " - "https://github.com/python/cpython/pull/21241" - ) + not darwin_opengl_broken, + reason=darwin_opengl_reason ), 'GLBarGraphItem.py': exceptionCondition( - not(platform.system() == "Darwin" and - tuple(map(int, platform.mac_ver()[0].split("."))) >= (10, 16) and - (sys.version_info <= (3, 8, 7) or - (sys.version_info >= (3, 9) and sys.version_info < (3, 9, 1)))), - reason=( - "pyopenGL cannot find openGL libray on big sur: " - "https://github.com/python/cpython/pull/21241" - ) + not darwin_opengl_broken, + reason=darwin_opengl_reason ), 'GLViewWidget.py': exceptionCondition( - not(platform.system() == "Darwin" and - tuple(map(int, platform.mac_ver()[0].split("."))) >= (10, 16) and - (sys.version_info <= (3, 8, 7) or - (sys.version_info >= (3, 9) and sys.version_info < (3, 9, 1)))), - reason=( - "pyopenGL cannot find openGL libray on big sur: " - "https://github.com/python/cpython/pull/21241" - ) + not darwin_opengl_broken, + reason=darwin_opengl_reason ) } From 85e894dd73d21b479bcc0d98431e17ed88d583d3 Mon Sep 17 00:00:00 2001 From: KIU Shueng Chuan Date: Mon, 1 Mar 2021 13:45:00 +0800 Subject: [PATCH 4/5] convert uses of QTimer.singleShot to QTimer instances On macOS and Linux with PyQt bindings, QTimer.singleShot continues to fire on python interpreter shutdown. --- examples/ImageItem.py | 8 ++++++-- examples/PColorMeshItem.py | 7 ++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/examples/ImageItem.py b/examples/ImageItem.py index 9982d65c..49141084 100644 --- a/examples/ImageItem.py +++ b/examples/ImageItem.py @@ -36,6 +36,10 @@ i = 0 updateTime = ptime.time() fps = 0 +timer = QtCore.QTimer() +timer.setSingleShot(True) +# not using QTimer.singleShot() because of persistence on PyQt. see PR #1605 + def updateData(): global img, data, i, updateTime, fps @@ -43,7 +47,7 @@ def updateData(): img.setImage(data[i]) i = (i+1) % data.shape[0] - QtCore.QTimer.singleShot(1, updateData) + timer.start(1) now = ptime.time() fps2 = 1.0 / (now-updateTime) updateTime = now @@ -51,7 +55,7 @@ def updateData(): #print "%0.1f fps" % fps - +timer.timeout.connect(updateData) updateData() ## Start Qt event loop unless running in interactive mode. diff --git a/examples/PColorMeshItem.py b/examples/PColorMeshItem.py index 1e5f4e85..44604c8e 100644 --- a/examples/PColorMeshItem.py +++ b/examples/PColorMeshItem.py @@ -61,6 +61,10 @@ wave_speed = 0.3 wave_length = 10 color_speed = 0.3 +timer = QtCore.QTimer() +timer.setSingleShot(True) +# not using QTimer.singleShot() because of persistence on PyQt. see PR #1605 + i=0 def updateData(): global i @@ -74,8 +78,9 @@ def updateData(): new_z) i += wave_speed - QtCore.QTimer.singleShot(1000//fps, updateData) + timer.start(1000//fps) +timer.timeout.connect(updateData) updateData() ## Start Qt event loop unless running in interactive mode. From c49e471192873ff99fc0f1d6c4cd1cfbbcae364f Mon Sep 17 00:00:00 2001 From: KIU Shueng Chuan Date: Mon, 1 Mar 2021 14:38:13 +0800 Subject: [PATCH 5/5] don't skip test_ExampleApp.py --- examples/test_examples.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/examples/test_examples.py b/examples/test_examples.py index bb399f6d..4339875c 100644 --- a/examples/test_examples.py +++ b/examples/test_examples.py @@ -65,10 +65,6 @@ darwin_opengl_reason = ("pyopenGL cannot find openGL library on big sur: " exceptionCondition = namedtuple("exceptionCondition", ["condition", "reason"]) conditionalExamples = { - "test_ExampleApp.py": exceptionCondition( - not(platform.system() == "Linux" and frontends[Qt.PYSIDE2]), - reason="Unexplained, intermittent segfault and subsequent timeout on CI" - ), "hdf5.py": exceptionCondition( False, reason="Example requires user interaction"