Merge branch 'ericdill-split-main' into develop

This commit is contained in:
Luke Campagnola 2015-07-12 17:15:18 -05:00
commit 8285045422
7 changed files with 154 additions and 115 deletions

3
.gitignore vendored
View File

@ -99,3 +99,6 @@ generated/
MANIFEST MANIFEST
deb_build deb_build
rtr.cvs rtr.cvs
# pytest parallel
.coverage*

View File

@ -17,6 +17,10 @@ pyqtgraph-0.9.11 [unreleased]
- Dock titles can be changed after creation - Dock titles can be changed after creation
- Added Dock.sigClosed - Added Dock.sigClosed
Maintenance:
- Add examples to unit tests
pyqtgraph-0.9.10 pyqtgraph-0.9.10
Fixed installation issues with more recent pip versions. Fixed installation issues with more recent pip versions.

View File

@ -49,3 +49,12 @@ Please use the following guidelines when preparing changes:
QObject subclasses that implement new signals should also describe QObject subclasses that implement new signals should also describe
these in a similar table. these in a similar table.
* Setting up a test environment.
Tests for a module should ideally cover all code in that module,
i.e., statement coverage should be at 100%.
To measure the test coverage, install py.test, pytest-cov and pytest-xdist.
Then run 'py.test --cov -n 4' to run the test suite with coverage on 4 cores.

View File

@ -1,14 +1,121 @@
import sys, os import sys, os
import pyqtgraph as pg
if __name__ == "__main__" and (__package__ is None or __package__==''): if __name__ == "__main__" and (__package__ is None or __package__==''):
parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, parent_dir) sys.path.insert(0, parent_dir)
import examples import examples
__package__ = "examples" __package__ = "examples"
import pyqtgraph as pg
import subprocess
from pyqtgraph.python2_3 import basestring
from pyqtgraph.Qt import QtGui, USE_PYSIDE, USE_PYQT5
from .utils import buildFileList, testFile, run, path, examples
from .utils import buildFileList, testFile, path, examples
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
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_()
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -1,14 +1,32 @@
from __future__ import print_function, division, absolute_import from __future__ import print_function, division, absolute_import
from pyqtgraph import Qt from pyqtgraph import Qt
from . import utils from examples import utils
import importlib
import itertools
import pytest
files = utils.buildFileList(utils.examples) files = utils.buildFileList(utils.examples)
import pytest frontends = {Qt.PYQT4: False, Qt.PYSIDE: False}
# frontends = {Qt.PYQT4: False, Qt.PYQT5: False, Qt.PYSIDE: False}
# sort out which of the front ends are available
for frontend in frontends.keys():
try:
importlib.import_module(frontend)
frontends[frontend] = True
except ImportError:
pass
@pytest.mark.parametrize("f", files) @pytest.mark.parametrize(
def test_examples(f): "frontend, f", itertools.product(sorted(list(frontends.keys())), files))
def test_examples(frontend, f):
# Test the examples with whatever the current QT_LIB front # Test the examples with whatever the current QT_LIB front
# end is # end is
utils.testFile(f[0], f[1], utils.sys.executable, Qt.QT_LIB) print('frontend = %s. f = %s' % (frontend, f))
if not frontends[frontend]:
pytest.skip('{} is not installed. Skipping tests'.format(frontend))
utils.testFile(f[0], f[1], utils.sys.executable, frontend)
if __name__ == "__main__":
pytest.cmdline.main()

View File

@ -4,17 +4,8 @@ import time
import os import os
import sys import sys
from pyqtgraph.pgcollections import OrderedDict from pyqtgraph.pgcollections import OrderedDict
from pyqtgraph.Qt import QtGui, USE_PYSIDE, USE_PYQT5
from pyqtgraph.python2_3 import basestring 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__)) path = os.path.abspath(os.path.dirname(__file__))
@ -96,103 +87,6 @@ examples = OrderedDict([
('Custom Flowchart Nodes', 'FlowchartCustomNode.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): def buildFileList(examples, files=None):
if files == None: if files == None:

View File

@ -523,6 +523,10 @@ class PlotDataItem(GraphicsObject):
#y = y[::ds] #y = y[::ds]
if self.opts['fftMode']: if self.opts['fftMode']:
x,y = self._fourierTransform(x, y) x,y = self._fourierTransform(x, y)
# Ignore the first bin for fft data if we have a logx scale
if self.opts['logMode'][0]:
x=x[1:]
y=y[1:]
if self.opts['logMode'][0]: if self.opts['logMode'][0]:
x = np.log10(x) x = np.log10(x)
if self.opts['logMode'][1]: if self.opts['logMode'][1]: