diff --git a/examples/__main__.py b/examples/__main__.py index 06f77f10..09b3c83c 100644 --- a/examples/__main__.py +++ b/examples/__main__.py @@ -1,4 +1,6 @@ -import sys, os, subprocess, time +import sys, os +import pyqtgraph as pg + if __name__ == "__main__" and (__package__ is None or __package__==''): parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) @@ -6,277 +8,10 @@ if __name__ == "__main__" and (__package__ is None or __package__==''): import examples __package__ = "examples" -from . import initExample -from pyqtgraph.Qt import QtCore, QtGui, USE_PYSIDE, USE_PYQT5 -from pyqtgraph.python2_3 import basestring -import pyqtgraph as pg - -if USE_PYSIDE: - from .exampleLoaderTemplate_pyside import Ui_Form -elif USE_PYQT5: - from .exampleLoaderTemplate_pyqt5 import Ui_Form -else: - from .exampleLoaderTemplate_pyqt import Ui_Form - -import os, sys -from pyqtgraph.pgcollections import OrderedDict - -examples = OrderedDict([ - ('Command-line usage', 'CLIexample.py'), - ('Basic Plotting', 'Plotting.py'), - ('ImageView', 'ImageView.py'), - ('ParameterTree', 'parametertree.py'), - ('Crosshair / Mouse interaction', 'crosshair.py'), - ('Data Slicing', 'DataSlicing.py'), - ('Plot Customization', 'customPlot.py'), - ('Image Analysis', 'imageAnalysis.py'), - ('Dock widgets', 'dockarea.py'), - ('Console', 'ConsoleWidget.py'), - ('Histograms', 'histogram.py'), - ('Beeswarm plot', 'beeswarm.py'), - ('Auto-range', 'PlotAutoRange.py'), - ('Remote Plotting', 'RemoteSpeedTest.py'), - ('Scrolling plots', 'scrollingPlots.py'), - ('HDF5 big data', 'hdf5.py'), - ('Demos', OrderedDict([ - ('Optics', 'optics_demos.py'), - ('Special relativity', 'relativity_demo.py'), - ('Verlet chain', 'verlet_chain_demo.py'), - ])), - ('GraphicsItems', OrderedDict([ - ('Scatter Plot', 'ScatterPlot.py'), - #('PlotItem', 'PlotItem.py'), - ('IsocurveItem', 'isocurve.py'), - ('GraphItem', 'GraphItem.py'), - ('ErrorBarItem', 'ErrorBarItem.py'), - ('FillBetweenItem', 'FillBetweenItem.py'), - ('ImageItem - video', 'ImageItem.py'), - ('ImageItem - draw', 'Draw.py'), - ('Region-of-Interest', 'ROIExamples.py'), - ('Bar Graph', 'BarGraphItem.py'), - ('GraphicsLayout', 'GraphicsLayout.py'), - ('LegendItem', 'Legend.py'), - ('Text Item', 'text.py'), - ('Linked Views', 'linkedViews.py'), - ('Arrow', 'Arrow.py'), - ('ViewBox', 'ViewBox.py'), - ('Custom Graphics', 'customGraphicsItem.py'), - ('Labeled Graph', 'CustomGraphItem.py'), - ])), - ('Benchmarks', OrderedDict([ - ('Video speed test', 'VideoSpeedTest.py'), - ('Line Plot update', 'PlotSpeedTest.py'), - ('Scatter Plot update', 'ScatterPlotSpeedTest.py'), - ('Multiple plots', 'MultiPlotSpeedTest.py'), - ])), - ('3D Graphics', OrderedDict([ - ('Volumetric', 'GLVolumeItem.py'), - ('Isosurface', 'GLIsosurface.py'), - ('Surface Plot', 'GLSurfacePlot.py'), - ('Scatter Plot', 'GLScatterPlotItem.py'), - ('Shaders', 'GLshaders.py'), - ('Line Plot', 'GLLinePlotItem.py'), - ('Mesh', 'GLMeshItem.py'), - ('Image', 'GLImageItem.py'), - ])), - ('Widgets', OrderedDict([ - ('PlotWidget', 'PlotWidget.py'), - ('SpinBox', 'SpinBox.py'), - ('ConsoleWidget', 'ConsoleWidget.py'), - ('Histogram / lookup table', 'HistogramLUT.py'), - ('TreeWidget', 'TreeWidget.py'), - ('ScatterPlotWidget', 'ScatterPlotWidget.py'), - ('DataTreeWidget', 'DataTreeWidget.py'), - ('GradientWidget', 'GradientWidget.py'), - ('TableWidget', 'TableWidget.py'), - ('ColorButton', 'ColorButton.py'), - #('CheckTable', '../widgets/CheckTable.py'), - #('VerticalLabel', '../widgets/VerticalLabel.py'), - ('JoystickButton', 'JoystickButton.py'), - ])), - - ('Flowcharts', 'Flowchart.py'), - ('Custom Flowchart Nodes', 'FlowchartCustomNode.py'), -]) - -path = os.path.abspath(os.path.dirname(__file__)) - -class ExampleLoader(QtGui.QMainWindow): - def __init__(self): - QtGui.QMainWindow.__init__(self) - self.ui = Ui_Form() - self.cw = QtGui.QWidget() - self.setCentralWidget(self.cw) - self.ui.setupUi(self.cw) - - self.codeBtn = QtGui.QPushButton('Run Edited Code') - self.codeLayout = QtGui.QGridLayout() - self.ui.codeView.setLayout(self.codeLayout) - self.codeLayout.addItem(QtGui.QSpacerItem(100,100,QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Expanding), 0, 0) - self.codeLayout.addWidget(self.codeBtn, 1, 1) - self.codeBtn.hide() - - global examples - self.itemCache = [] - self.populateTree(self.ui.exampleTree.invisibleRootItem(), examples) - self.ui.exampleTree.expandAll() - - self.resize(1000,500) - self.show() - self.ui.splitter.setSizes([250,750]) - self.ui.loadBtn.clicked.connect(self.loadFile) - self.ui.exampleTree.currentItemChanged.connect(self.showFile) - self.ui.exampleTree.itemDoubleClicked.connect(self.loadFile) - self.ui.codeView.textChanged.connect(self.codeEdited) - self.codeBtn.clicked.connect(self.runEditedCode) - - def populateTree(self, root, examples): - for key, val in examples.items(): - item = QtGui.QTreeWidgetItem([key]) - self.itemCache.append(item) # PyQt 4.9.6 no longer keeps references to these wrappers, - # so we need to make an explicit reference or else the .file - # attribute will disappear. - if isinstance(val, basestring): - item.file = val - else: - self.populateTree(item, val) - root.addChild(item) - - def currentFile(self): - item = self.ui.exampleTree.currentItem() - if hasattr(item, 'file'): - global path - return os.path.join(path, item.file) - return None - - def loadFile(self, edited=False): - - extra = [] - qtLib = str(self.ui.qtLibCombo.currentText()) - gfxSys = str(self.ui.graphicsSystemCombo.currentText()) - - if qtLib != 'default': - extra.append(qtLib.lower()) - elif gfxSys != 'default': - extra.append(gfxSys) - - if edited: - path = os.path.abspath(os.path.dirname(__file__)) - proc = subprocess.Popen([sys.executable, '-'] + extra, stdin=subprocess.PIPE, cwd=path) - code = str(self.ui.codeView.toPlainText()).encode('UTF-8') - proc.stdin.write(code) - proc.stdin.close() - else: - fn = self.currentFile() - if fn is None: - return - if sys.platform.startswith('win'): - os.spawnl(os.P_NOWAIT, sys.executable, '"'+sys.executable+'"', '"' + fn + '"', *extra) - else: - os.spawnl(os.P_NOWAIT, sys.executable, sys.executable, fn, *extra) - - def showFile(self): - fn = self.currentFile() - if fn is None: - self.ui.codeView.clear() - return - if os.path.isdir(fn): - fn = os.path.join(fn, '__main__.py') - text = open(fn).read() - self.ui.codeView.setPlainText(text) - self.ui.loadedFileLabel.setText(fn) - self.codeBtn.hide() - - def codeEdited(self): - self.codeBtn.show() - - def runEditedCode(self): - self.loadFile(edited=True) - -def run(): - app = QtGui.QApplication([]) - loader = ExampleLoader() - - app.exec_() - -def buildFileList(examples, files=None): - if files == None: - files = [] - for key, val in examples.items(): - #item = QtGui.QTreeWidgetItem([key]) - if isinstance(val, basestring): - #item.file = val - files.append((key,val)) - else: - buildFileList(val, files) - return files - -def testFile(name, f, exe, lib, graphicsSystem=None): - global path - fn = os.path.join(path,f) - #print "starting process: ", fn - os.chdir(path) - sys.stdout.write(name) - sys.stdout.flush() - - import1 = "import %s" % lib if lib != '' else '' - import2 = os.path.splitext(os.path.split(fn)[1])[0] - graphicsSystem = '' if graphicsSystem is None else "pg.QtGui.QApplication.setGraphicsSystem('%s')" % graphicsSystem - code = """ -try: - %s - import initExample - import pyqtgraph as pg - %s - import %s - 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) -except: - print("test failed") - raise - -""" % (import1, graphicsSystem, import2) - - if sys.platform.startswith('win'): - process = subprocess.Popen([exe], stdin=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE) - process.stdin.write(code.encode('UTF-8')) - process.stdin.close() - else: - process = subprocess.Popen(['exec %s -i' % (exe)], shell=True, stdin=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE) - process.stdin.write(code.encode('UTF-8')) - process.stdin.close() ##? - output = '' - fail = False - while True: - c = process.stdout.read(1).decode() - output += c - #sys.stdout.write(c) - #sys.stdout.flush() - if output.endswith('test complete'): - break - if output.endswith('test failed'): - fail = True - break - time.sleep(1) - process.kill() - #res = process.communicate() - res = (process.stdout.read(), process.stderr.read()) - - if fail or 'exception' in res[1].decode().lower() or 'error' in res[1].decode().lower(): - print('.' * (50-len(name)) + 'FAILED') - print(res[0].decode()) - print(res[1].decode()) - else: - print('.' * (50-len(name)) + 'passed') - - +from .utils import buildFileList, testFile, run, path if __name__ == '__main__': + args = sys.argv[1:] if '--test' in args: diff --git a/examples/tests.py b/examples/tests.py new file mode 100644 index 00000000..12142a77 --- /dev/null +++ b/examples/tests.py @@ -0,0 +1,8 @@ + +from .__main__ import buildFileList, testFile, sys, examples + +def test_pyside(): + files = buildFileList(examples) + for f in files: + yield testFile, f[0], f[1], sys.executable, 'PySide' + # testFile(f[0], f[1], sys.executable, 'PySide') diff --git a/examples/utils.py b/examples/utils.py new file mode 100644 index 00000000..98a44146 --- /dev/null +++ b/examples/utils.py @@ -0,0 +1,270 @@ +from __future__ import division, print_function, absolute_import +import subprocess +import time +import os +import sys +from pyqtgraph.pgcollections import OrderedDict +from pyqtgraph.Qt import QtGui, USE_PYSIDE, USE_PYQT5 +from pyqtgraph.python2_3 import basestring + +if USE_PYSIDE: + from .exampleLoaderTemplate_pyside import Ui_Form +elif USE_PYQT5: + from .exampleLoaderTemplate_pyqt5 import Ui_Form +else: + from .exampleLoaderTemplate_pyqt import Ui_Form + + +path = os.path.abspath(os.path.dirname(__file__)) + + +examples = OrderedDict([ + ('Command-line usage', 'CLIexample.py'), + ('Basic Plotting', 'Plotting.py'), + ('ImageView', 'ImageView.py'), + ('ParameterTree', 'parametertree.py'), + ('Crosshair / Mouse interaction', 'crosshair.py'), + ('Data Slicing', 'DataSlicing.py'), + ('Plot Customization', 'customPlot.py'), + ('Image Analysis', 'imageAnalysis.py'), + ('Dock widgets', 'dockarea.py'), + ('Console', 'ConsoleWidget.py'), + ('Histograms', 'histogram.py'), + ('Beeswarm plot', 'beeswarm.py'), + ('Auto-range', 'PlotAutoRange.py'), + ('Remote Plotting', 'RemoteSpeedTest.py'), + ('Scrolling plots', 'scrollingPlots.py'), + ('HDF5 big data', 'hdf5.py'), + ('Demos', OrderedDict([ + ('Optics', 'optics_demos.py'), + ('Special relativity', 'relativity_demo.py'), + ('Verlet chain', 'verlet_chain_demo.py'), + ])), + ('GraphicsItems', OrderedDict([ + ('Scatter Plot', 'ScatterPlot.py'), + #('PlotItem', 'PlotItem.py'), + ('IsocurveItem', 'isocurve.py'), + ('GraphItem', 'GraphItem.py'), + ('ErrorBarItem', 'ErrorBarItem.py'), + ('FillBetweenItem', 'FillBetweenItem.py'), + ('ImageItem - video', 'ImageItem.py'), + ('ImageItem - draw', 'Draw.py'), + ('Region-of-Interest', 'ROIExamples.py'), + ('Bar Graph', 'BarGraphItem.py'), + ('GraphicsLayout', 'GraphicsLayout.py'), + ('LegendItem', 'Legend.py'), + ('Text Item', 'text.py'), + ('Linked Views', 'linkedViews.py'), + ('Arrow', 'Arrow.py'), + ('ViewBox', 'ViewBox.py'), + ('Custom Graphics', 'customGraphicsItem.py'), + ('Labeled Graph', 'CustomGraphItem.py'), + ])), + ('Benchmarks', OrderedDict([ + ('Video speed test', 'VideoSpeedTest.py'), + ('Line Plot update', 'PlotSpeedTest.py'), + ('Scatter Plot update', 'ScatterPlotSpeedTest.py'), + ('Multiple plots', 'MultiPlotSpeedTest.py'), + ])), + ('3D Graphics', OrderedDict([ + ('Volumetric', 'GLVolumeItem.py'), + ('Isosurface', 'GLIsosurface.py'), + ('Surface Plot', 'GLSurfacePlot.py'), + ('Scatter Plot', 'GLScatterPlotItem.py'), + ('Shaders', 'GLshaders.py'), + ('Line Plot', 'GLLinePlotItem.py'), + ('Mesh', 'GLMeshItem.py'), + ('Image', 'GLImageItem.py'), + ])), + ('Widgets', OrderedDict([ + ('PlotWidget', 'PlotWidget.py'), + ('SpinBox', 'SpinBox.py'), + ('ConsoleWidget', 'ConsoleWidget.py'), + ('Histogram / lookup table', 'HistogramLUT.py'), + ('TreeWidget', 'TreeWidget.py'), + ('ScatterPlotWidget', 'ScatterPlotWidget.py'), + ('DataTreeWidget', 'DataTreeWidget.py'), + ('GradientWidget', 'GradientWidget.py'), + ('TableWidget', 'TableWidget.py'), + ('ColorButton', 'ColorButton.py'), + #('CheckTable', '../widgets/CheckTable.py'), + #('VerticalLabel', '../widgets/VerticalLabel.py'), + ('JoystickButton', 'JoystickButton.py'), + ])), + + ('Flowcharts', 'Flowchart.py'), + ('Custom Flowchart Nodes', 'FlowchartCustomNode.py'), +]) + +class ExampleLoader(QtGui.QMainWindow): + def __init__(self): + QtGui.QMainWindow.__init__(self) + self.ui = Ui_Form() + self.cw = QtGui.QWidget() + self.setCentralWidget(self.cw) + self.ui.setupUi(self.cw) + + self.codeBtn = QtGui.QPushButton('Run Edited Code') + self.codeLayout = QtGui.QGridLayout() + self.ui.codeView.setLayout(self.codeLayout) + self.codeLayout.addItem(QtGui.QSpacerItem(100,100,QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Expanding), 0, 0) + self.codeLayout.addWidget(self.codeBtn, 1, 1) + self.codeBtn.hide() + + global examples + self.itemCache = [] + self.populateTree(self.ui.exampleTree.invisibleRootItem(), examples) + self.ui.exampleTree.expandAll() + + self.resize(1000,500) + self.show() + self.ui.splitter.setSizes([250,750]) + self.ui.loadBtn.clicked.connect(self.loadFile) + self.ui.exampleTree.currentItemChanged.connect(self.showFile) + self.ui.exampleTree.itemDoubleClicked.connect(self.loadFile) + self.ui.codeView.textChanged.connect(self.codeEdited) + self.codeBtn.clicked.connect(self.runEditedCode) + + def populateTree(self, root, examples): + for key, val in examples.items(): + item = QtGui.QTreeWidgetItem([key]) + self.itemCache.append(item) # PyQt 4.9.6 no longer keeps references to these wrappers, + # so we need to make an explicit reference or else the .file + # attribute will disappear. + if isinstance(val, basestring): + item.file = val + else: + self.populateTree(item, val) + root.addChild(item) + + def currentFile(self): + item = self.ui.exampleTree.currentItem() + if hasattr(item, 'file'): + global path + return os.path.join(path, item.file) + return None + + def loadFile(self, edited=False): + + extra = [] + qtLib = str(self.ui.qtLibCombo.currentText()) + gfxSys = str(self.ui.graphicsSystemCombo.currentText()) + + if qtLib != 'default': + extra.append(qtLib.lower()) + elif gfxSys != 'default': + extra.append(gfxSys) + + if edited: + path = os.path.abspath(os.path.dirname(__file__)) + proc = subprocess.Popen([sys.executable, '-'] + extra, stdin=subprocess.PIPE, cwd=path) + code = str(self.ui.codeView.toPlainText()).encode('UTF-8') + proc.stdin.write(code) + proc.stdin.close() + else: + fn = self.currentFile() + if fn is None: + return + if sys.platform.startswith('win'): + os.spawnl(os.P_NOWAIT, sys.executable, '"'+sys.executable+'"', '"' + fn + '"', *extra) + else: + os.spawnl(os.P_NOWAIT, sys.executable, sys.executable, fn, *extra) + + def showFile(self): + fn = self.currentFile() + if fn is None: + self.ui.codeView.clear() + return + if os.path.isdir(fn): + fn = os.path.join(fn, '__main__.py') + text = open(fn).read() + self.ui.codeView.setPlainText(text) + self.ui.loadedFileLabel.setText(fn) + self.codeBtn.hide() + + def codeEdited(self): + self.codeBtn.show() + + def runEditedCode(self): + self.loadFile(edited=True) + +def run(): + app = QtGui.QApplication([]) + loader = ExampleLoader() + + app.exec_() + +def buildFileList(examples, files=None): + if files == None: + files = [] + for key, val in examples.items(): + #item = QtGui.QTreeWidgetItem([key]) + if isinstance(val, basestring): + #item.file = val + files.append((key,val)) + else: + buildFileList(val, files) + return files + +def testFile(name, f, exe, lib, graphicsSystem=None): + global path + fn = os.path.join(path,f) + #print "starting process: ", fn + os.chdir(path) + sys.stdout.write(name) + sys.stdout.flush() + + import1 = "import %s" % lib if lib != '' else '' + import2 = os.path.splitext(os.path.split(fn)[1])[0] + graphicsSystem = '' if graphicsSystem is None else "pg.QtGui.QApplication.setGraphicsSystem('%s')" % graphicsSystem + code = """ +try: + %s + import initExample + import pyqtgraph as pg + %s + import %s + 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) +except: + print("test failed") + raise + +""" % (import1, graphicsSystem, import2) + + if sys.platform.startswith('win'): + process = subprocess.Popen([exe], stdin=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE) + process.stdin.write(code.encode('UTF-8')) + process.stdin.close() + else: + process = subprocess.Popen(['exec %s -i' % (exe)], shell=True, stdin=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE) + process.stdin.write(code.encode('UTF-8')) + process.stdin.close() ##? + output = '' + fail = False + while True: + c = process.stdout.read(1).decode() + output += c + #sys.stdout.write(c) + #sys.stdout.flush() + if output.endswith('test complete'): + break + if output.endswith('test failed'): + fail = True + break + time.sleep(1) + process.kill() + #res = process.communicate() + res = (process.stdout.read(), process.stderr.read()) + + if fail or 'exception' in res[1].decode().lower() or 'error' in res[1].decode().lower(): + print('.' * (50-len(name)) + 'FAILED') + print(res[0].decode()) + print(res[1].decode()) + else: + print('.' * (50-len(name)) + 'passed')