Move and Update test-data repo into pyqtgraph repo

To reduce complexity, and make it easier to add more images and tests,
the images in the `test-data` repository should be merged with the main
repository.  Furthermore, we can remove a lot of the subprocess work in
the image_testing.py file, as we no longer need to have it interact with
git.

The images are not the same.  Images were regenerated with Qt6, and now
have proper big and little endian handling thanks to @pijyoi

Second commit is a slightly modified variant of
2e135ab282d6007b34a3854921be54d0e9efb241 authored by @pijyoi
it is to convert qimages to RGBA8888 for testing.  Image
files were regenerated images for the big/little handling

Fixed issue with bogus test from test_NonUniformImage and generated a
new image
This commit is contained in:
Ogi Moore 2021-05-27 21:57:07 -07:00
parent e29f86578f
commit a6971c768d
127 changed files with 125 additions and 332 deletions

View File

@ -40,11 +40,6 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Checkout test-data
uses: actions/checkout@v2
with:
repository: pyqtgraph/test-data
path: .pyqtgraph/test-data
- name: Setup Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
@ -106,7 +101,7 @@ jobs:
- name: Run Tests
run: |
mkdir $SCREENSHOT_DIR
pytest pyqtgraph examples -v \
pytest tests examples -v \
--junitxml pytest.xml \
shell: bash
- name: Upload Screenshots

View File

@ -1511,17 +1511,10 @@ def makeQImage(imgData, alpha=None, copy=True, transpose=True):
return ndarray_to_qimage(imgData, imgFormat)
def imageToArray(img, copy=False, transpose=True):
"""
Convert a QImage into numpy array. The image must have format RGB32, ARGB32, or ARGB32_Premultiplied.
By default, the image is not copied; changes made to the array will appear in the QImage as well (beware: if
the QImage is collected before the array, there may be trouble).
The array will have shape (width, height, (b,g,r,a)).
"""
fmt = img.format()
img_ptr = img.bits()
def qimage_to_ndarray(qimg):
img_ptr = qimg.bits()
if QT_LIB.startswith('PyQt'):
if hasattr(img_ptr, 'setsize'): # PyQt sip.voidptr
# sizeInBytes() was introduced in Qt 5.10
# however PyQt5 5.12 will fail with:
# "TypeError: QImage.sizeInBytes() is a private method"
@ -1529,14 +1522,37 @@ def imageToArray(img, copy=False, transpose=True):
# PyQt5 5.15, PySide2 5.12, PySide2 5.15
try:
# 64-bits size
nbytes = img.sizeInBytes()
nbytes = qimg.sizeInBytes()
except (TypeError, AttributeError):
# 32-bits size
nbytes = img.byteCount()
nbytes = qimg.byteCount()
img_ptr.setsize(nbytes)
arr = np.frombuffer(img_ptr, dtype=np.ubyte)
arr = arr.reshape(img.height(), img.width(), 4)
depth = qimg.depth()
if depth in (8, 24, 32):
dtype = np.uint8
nchan = depth // 8
elif depth in (16, 64):
dtype = np.uint16
nchan = depth // 16
else:
raise ValueError("Unsupported Image Type")
shape = qimg.height(), qimg.width()
if nchan != 1:
shape = shape + (nchan,)
return np.frombuffer(img_ptr, dtype=dtype).reshape(shape)
def imageToArray(img, copy=False, transpose=True):
"""
Convert a QImage into numpy array. The image must have format RGB32, ARGB32, or ARGB32_Premultiplied.
By default, the image is not copied; changes made to the array will appear in the QImage as well (beware: if
the QImage is collected before the array, there may be trouble).
The array will have shape (width, height, (b,g,r,a)).
"""
arr = qimage_to_ndarray(img)
fmt = img.format()
if fmt == img.Format_RGB32:
arr[...,3] = 255

View File

@ -4,7 +4,7 @@ xvfb_height = 1080
# use this due to some issues with ndarray reshape errors on CI systems
xvfb_colordepth = 24
xvfb_args=-ac +extension GLX +render
faulthandler_timeout = 30
faulthandler_timeout = 60
filterwarnings =
# re-enable standard library warnings

View File

@ -5,7 +5,7 @@ import pytest
from pyqtgraph.Qt import QtCore, QtGui, QtTest
import numpy as np
import pyqtgraph as pg
from pyqtgraph.tests import assertImageApproved, TransposedImageItem
from tests.image_testing import assertImageApproved, TransposedImageItem
try:
import cupy
except ImportError:

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
import pyqtgraph as pg
from pyqtgraph.Qt import QtGui, QtCore, QtTest
from pyqtgraph.tests import mouseDrag, mouseMove
from tests.ui_testing import mouseDrag, mouseMove
pg.mkQApp()

View File

@ -2,7 +2,7 @@ import numpy as np
import pyqtgraph as pg
from pyqtgraph.Qt import QtTest
from pyqtgraph.graphicsItems.NonUniformImage import NonUniformImage
from pyqtgraph.tests import assertImageApproved
from tests.image_testing import assertImageApproved
from pyqtgraph.colormap import ColorMap
import pyqtgraph.functions as fn
import pytest
@ -93,7 +93,7 @@ def test_NonUniformImage_colormap():
image = NonUniformImage(x, y, Z, border=fn.mkPen('g'))
cmap = ColorMap(pos=[0.0, 1.0], color=[(0.0, 0.0, 0.0, 1.0), (1.0, 1.0, 1.0, 1.0)])
cmap = ColorMap(pos=[0.0, 1.0], color=[(0, 0, 0), (255, 255, 255)])
image.setColorMap(cmap)
viewbox.addItem(image)

View File

@ -1,6 +1,6 @@
import numpy as np
import pyqtgraph as pg
from pyqtgraph.tests import assertImageApproved
from tests.image_testing import assertImageApproved
def test_PlotCurveItem():

View File

@ -3,9 +3,10 @@ import sys
import numpy as np
import pytest
import pyqtgraph as pg
import platform
from pyqtgraph.Qt import QtCore, QtGui, QtTest
from pyqtgraph.tests import assertImageApproved, mouseMove, mouseDrag, mouseClick, TransposedImageItem, resizeWindow
import pytest
from tests.image_testing import assertImageApproved
from tests.ui_testing import mouseMove, mouseDrag, mouseClick, resizeWindow
app = pg.mkQApp()
pg.setConfigOption("mouseRateLimit", 0)
@ -39,17 +40,20 @@ def test_getArrayRegion_axisorder():
def check_getArrayRegion(roi, name, testResize=True, transpose=False):
# on windows, edges corner pixels seem to be slightly different from other platforms
# giving a pxCount=2 for a fudge factor
if isinstance(roi, (pg.ROI, pg.RectROI)) and platform.system() == "Windows":
pxCount = 2
else:
pxCount=-1
initState = roi.getState()
#win = pg.GraphicsLayoutWidget()
win = pg.GraphicsView()
win.show()
resizeWindow(win, 200, 400)
# Don't use Qt's layouts for testing--these generate unpredictable results.
#vb1 = win.addViewBox()
#win.nextRow()
#vb2 = win.addViewBox()
# Don't use Qt's layouts for testing--these generate unpredictable results.
# Instead, place the viewboxes manually
vb1 = pg.ViewBox()
win.scene().addItem(vb1)
@ -97,7 +101,7 @@ def check_getArrayRegion(roi, name, testResize=True, transpose=False):
vb2.enableAutoRange(True, True)
app.processEvents()
assertImageApproved(win, name+'/roi_getarrayregion', 'Simple ROI region selection.')
assertImageApproved(win, name+'/roi_getarrayregion', 'Simple ROI region selection.', pxCount=pxCount)
with pytest.raises(TypeError):
roi.setPos(0, False)
@ -106,38 +110,33 @@ def check_getArrayRegion(roi, name, testResize=True, transpose=False):
rgn = roi.getArrayRegion(data, img1, axes=(1, 2))
img2.setImage(rgn[0, ..., 0])
app.processEvents()
assertImageApproved(win, name+'/roi_getarrayregion_halfpx', 'Simple ROI region selection, 0.5 pixel shift.')
assertImageApproved(win, name+'/roi_getarrayregion_halfpx', 'Simple ROI region selection, 0.5 pixel shift.', pxCount=pxCount)
roi.setAngle(45)
roi.setPos([3, 0])
rgn = roi.getArrayRegion(data, img1, axes=(1, 2))
img2.setImage(rgn[0, ..., 0])
app.processEvents()
assertImageApproved(win, name+'/roi_getarrayregion_rotate', 'Simple ROI region selection, rotation.')
assertImageApproved(win, name+'/roi_getarrayregion_rotate', 'Simple ROI region selection, rotation.', pxCount=pxCount)
if testResize:
roi.setSize([60, 60])
rgn = roi.getArrayRegion(data, img1, axes=(1, 2))
img2.setImage(rgn[0, ..., 0])
app.processEvents()
assertImageApproved(win, name+'/roi_getarrayregion_resize', 'Simple ROI region selection, resized.')
assertImageApproved(win, name+'/roi_getarrayregion_resize', 'Simple ROI region selection, resized.', pxCount=pxCount)
img1.setPos(0, img1.height())
img1.setTransform(QtGui.QTransform().scale(1, -1).rotate(20), True)
rgn = roi.getArrayRegion(data, img1, axes=(1, 2))
img2.setImage(rgn[0, ..., 0])
app.processEvents()
assertImageApproved(win, name+'/roi_getarrayregion_img_trans', 'Simple ROI region selection, image transformed.')
assertImageApproved(win, name+'/roi_getarrayregion_img_trans', 'Simple ROI region selection, image transformed.', pxCount=pxCount)
vb1.invertY()
rgn = roi.getArrayRegion(data, img1, axes=(1, 2))
img2.setImage(rgn[0, ..., 0])
app.processEvents()
# on windows, one edge of one ROI handle is shifted slightly; letting this slide with pxCount=10
if pg.Qt.QT_LIB in {'PyQt4', 'PySide'}:
pxCount = 10
else:
pxCount=-1
assertImageApproved(win, name+'/roi_getarrayregion_inverty', 'Simple ROI region selection, view inverted.', pxCount=pxCount)
roi.setState(initState)
@ -146,7 +145,7 @@ def check_getArrayRegion(roi, name, testResize=True, transpose=False):
rgn = roi.getArrayRegion(data, img1, axes=(1, 2))
img2.setImage(rgn[0, ..., 0])
app.processEvents()
assertImageApproved(win, name+'/roi_getarrayregion_anisotropic', 'Simple ROI region selection, image scaled anisotropically.')
assertImageApproved(win, name+'/roi_getarrayregion_anisotropic', 'Simple ROI region selection, image scaled anisotropically.', pxCount=pxCount)
# allow the roi to be re-used
roi.scene().removeItem(roi)

View File

@ -3,68 +3,32 @@
"""
Procedure for unit-testing with images:
1. Run unit tests at least once; this initializes a git clone of
pyqtgraph/test-data in ~/.pyqtgraph.
2. Run individual test scripts with the PYQTGRAPH_AUDIT environment variable set:
Run individual test scripts with the PYQTGRAPH_AUDIT environment variable set:
$ PYQTGRAPH_AUDIT=1 python pyqtgraph/graphicsItems/tests/test_PlotCurveItem.py
Any failing tests will display the test results, standard image, and the
differences between the two. If the test result is bad, then press (f)ail.
If the test result is good, then press (p)ass and the new image will be
saved to the test-data directory.
To check all test results regardless of whether the test failed, set the
environment variable PYQTGRAPH_AUDIT_ALL=1.
3. After adding or changing test images, create a new commit:
$ cd ~/.pyqtgraph/test-data
$ git add ...
$ git commit -a
4. Look up the most recent tag name from the `testDataTag` global variable
below. Increment the tag name by 1 and create a new tag in the test-data
repository:
$ git tag test-data-NNN
$ git push --tags origin master
This tag is used to ensure that each pyqtgraph commit is linked to a specific
commit in the test-data repository. This makes it possible to push new
commits to the test-data repository without interfering with existing
tests, and also allows unit tests to continue working on older pyqtgraph
versions.
Any failing tests will display the test results, standard image, and the
differences between the two. If the test result is bad, then press (f)ail.
If the test result is good, then press (p)ass and the new image will be
saved to the test-data directory.
To check all test results regardless of whether the test failed, set the
environment variable PYQTGRAPH_AUDIT_ALL=1.
"""
# This is the name of a tag in the test-data repository that this version of
# pyqtgraph should be tested against. When adding or changing test images,
# create and push a new tag and update this variable. To test locally, begin
# by creating the tag in your ~/.pyqtgraph/test-data repository.
testDataTag = 'test-data-8'
import time
import os
import sys
import inspect
import base64
import subprocess as sp
import warnings
import numpy as np
if sys.version[0] >= '3':
import http.client as httplib
import urllib.parse as urllib
else:
import httplib
import urllib
from ..Qt import QtGui, QtCore, QtTest, QT_LIB
from .. import functions as fn
from .. import GraphicsLayoutWidget
from .. import ImageItem, TextItem
from pathlib import Path
from pyqtgraph.Qt import QtGui, QtCore
from pyqtgraph import functions as fn
from pyqtgraph import GraphicsLayoutWidget
from pyqtgraph import ImageItem, TextItem
tester = None
@ -101,6 +65,21 @@ def getTester():
return tester
def getImageFromWidget(widget):
# just to be sure the widget size is correct (new window may be resized):
QtGui.QApplication.processEvents()
qimg = QtGui.QImage(widget.size(), QtGui.QImage.Format.Format_ARGB32)
qimg.fill(QtCore.Qt.GlobalColor.transparent)
painter = QtGui.QPainter(qimg)
widget.render(painter)
painter.end()
qimg = qimg.convertToFormat(QtGui.QImage.Format.Format_RGBA8888)
return fn.qimage_to_ndarray(qimg).copy()
def assertImageApproved(image, standardFile, message=None, **kwargs):
"""Check that an image test result matches a pre-approved standard.
@ -108,10 +87,6 @@ def assertImageApproved(image, standardFile, message=None, **kwargs):
to compare the images and decide whether to fail the test or save the new
image as the standard.
This function will automatically clone the test-data repository into
~/.pyqtgraph/test-data. However, it is up to the user to ensure this repository
is kept up to date and to commit/push new images after they are saved.
Run the test with the environment variable PYQTGRAPH_AUDIT=1 to bring up
the auditing GUI.
@ -131,43 +106,28 @@ def assertImageApproved(image, standardFile, message=None, **kwargs):
comparison (see ``assertImageMatch()``).
"""
if isinstance(image, QtGui.QWidget):
w = image
# just to be sure the widget size is correct (new window may be resized):
# just to be sure the widget size is correct (new window may be resized):
QtGui.QApplication.processEvents()
graphstate = scenegraphState(w, standardFile)
qimg = QtGui.QImage(w.size(), QtGui.QImage.Format.Format_ARGB32)
qimg.fill(QtCore.Qt.GlobalColor.transparent)
painter = QtGui.QPainter(qimg)
w.render(painter)
painter.end()
image = fn.imageToArray(qimg, copy=False, transpose=False)
# the standard images seem to have their Red and Blue swapped
if sys.byteorder == 'little':
# transpose B,G,R,A to R,G,B,A
image = image[..., [2, 1, 0, 3]]
else:
# transpose A,R,G,B to A,B,G,R
image = image[..., [0, 3, 2, 1]]
graphstate = scenegraphState(image, standardFile)
image = getImageFromWidget(image)
if message is None:
code = inspect.currentframe().f_back.f_code
message = "%s::%s" % (code.co_filename, code.co_name)
# Make sure we have a test data repo available, possibly invoking git
dataPath = getTestDataRepo()
# Make sure we have a test data repo available
dataPath = getTestDataDirectory()
# Read the standard image if it exists
stdFileName = os.path.join(dataPath, standardFile + '.png')
if not os.path.isfile(stdFileName):
stdImage = None
else:
pxm = QtGui.QPixmap()
pxm.load(stdFileName)
stdImage = fn.imageToArray(pxm.toImage(), copy=True, transpose=False)
qimg = QtGui.QImage(stdFileName)
qimg = qimg.convertToFormat(QtGui.QImage.Format.Format_RGBA8888)
stdImage = fn.qimage_to_ndarray(qimg).copy()
del qimg
# If the test image does not match, then we go to audit if requested.
try:
@ -191,18 +151,13 @@ def assertImageApproved(image, standardFile, message=None, **kwargs):
image = fn.downsample(image, sr[0], axis=(0, 1)).astype(image.dtype)
assertImageMatch(image, stdImage, **kwargs)
if bool(os.getenv('PYQTGRAPH_PRINT_TEST_STATE', False)):
print(graphstate)
if os.getenv('PYQTGRAPH_AUDIT_ALL') == '1':
raise Exception("Image test passed, but auditing due to PYQTGRAPH_AUDIT_ALL evnironment variable.")
except Exception:
if stdFileName in gitStatus(dataPath):
print("\n\nWARNING: unit test failed against modified standard "
"image %s.\nTo revert this file, run `cd %s; git checkout "
"%s`\n" % (stdFileName, dataPath, standardFile))
if os.getenv('PYQTGRAPH_AUDIT') == '1' or os.getenv('PYQTGRAPH_AUDIT_ALL') == '1':
sys.excepthook(*sys.exc_info())
getTester().test(image, stdImage, message)
@ -210,20 +165,18 @@ def assertImageApproved(image, standardFile, message=None, **kwargs):
print('Saving new standard image to "%s"' % stdFileName)
if not os.path.isdir(stdPath):
os.makedirs(stdPath)
img = fn.makeQImage(image, alpha=True, transpose=False)
img.save(stdFileName)
qimg = fn.ndarray_to_qimage(image, QtGui.QImage.Format.Format_RGBA8888)
qimg.save(stdFileName)
del qimg
else:
if stdImage is None:
raise Exception("Test standard %s does not exist. Set "
"PYQTGRAPH_AUDIT=1 to add this image." % stdFileName)
else:
if os.getenv('TRAVIS') is not None:
saveFailedTest(image, stdImage, standardFile, upload=True)
elif os.getenv('CI') is not None:
standardFile = os.path.join(os.getenv("SCREENSHOT_DIR", "screenshots"), standardFile)
saveFailedTest(image, stdImage, standardFile)
print(graphstate)
raise
if os.getenv('CI') is not None:
standardFile = os.path.join(os.getenv("SCREENSHOT_DIR", "screenshots"), standardFile)
saveFailedTest(image, stdImage, standardFile)
print(graphstate)
raise
def assertImageMatch(im1, im2, minCorr=None, pxThreshold=50.,
@ -249,8 +202,8 @@ def assertImageMatch(im1, im2, minCorr=None, pxThreshold=50.,
pxThreshold : float
Minimum value difference at which two pixels are considered different
pxCount : int or None
Maximum number of pixels that may differ. Default is 0 for Qt4 and
1% of image size for Qt5.
Maximum number of pixels that may differ. Default is 0, on Windows some
tests have a value of 2.
maxPxDiff : float or None
Maximum allowed difference between pixels
avgPxDiff : float or None
@ -264,12 +217,7 @@ def assertImageMatch(im1, im2, minCorr=None, pxThreshold=50.,
assert im1.dtype == im2.dtype
if pxCount == -1:
if QT_LIB in {'PyQt5', 'PySide2', 'PySide6', 'PyQt6'}:
# Qt5 generates slightly different results; relax the tolerance
# until test images are updated.
pxCount = int(im1.shape[0] * im1.shape[1] * 0.01)
else:
pxCount = 0
pxCount = 0
diff = im1.astype(float) - im2.astype(float)
if imgDiff is not None:
@ -292,9 +240,7 @@ def assertImageMatch(im1, im2, minCorr=None, pxThreshold=50.,
assert corr >= minCorr
def saveFailedTest(data, expect, filename, upload=False):
"""Upload failed test images to web server to allow CI test debugging.
"""
def saveFailedTest(data, expect, filename):
# concatenate data, expect, and diff into a single image
ds = data.shape
es = expect.shape
@ -310,7 +256,7 @@ def saveFailedTest(data, expect, filename, upload=False):
diff = makeDiffImage(data, expect)
img[2:2+diff.shape[0], -diff.shape[1]-2:-2] = diff
png = makePng(img)
png = makePng(data) # change `img` to `data` to save just the failed image
directory = os.path.dirname(filename)
if not os.path.isdir(directory):
os.makedirs(directory)
@ -318,38 +264,15 @@ def saveFailedTest(data, expect, filename, upload=False):
png_file.write(png)
print("\nImage comparison failed. Test result: %s %s Expected result: "
"%s %s" % (data.shape, data.dtype, expect.shape, expect.dtype))
if upload:
uploadFailedTest(filename, png)
def uploadFailedTest(filename, png):
commit = runSubprocess(['git', 'rev-parse', 'HEAD'])
name = filename.split(os.path.sep)
name.insert(-1, commit.strip())
filename = os.path.sep.join(name)
host = 'data.pyqtgraph.org'
conn = httplib.HTTPConnection(host)
req = urllib.urlencode({'name': filename,
'data': base64.b64encode(png)})
conn.request('POST', '/upload.py', req)
response = conn.getresponse().read()
conn.close()
print("Uploaded to: \nhttp://%s/data/%s" % (host, filename))
if not response.startswith(b'OK'):
print("WARNING: Error uploading data to %s" % host)
print(response)
def makePng(img):
"""Given an array like (H, W, 4), return a PNG-encoded byte string.
"""
io = QtCore.QBuffer()
qim = fn.makeQImage(img.transpose(1, 0, 2), alpha=False)
qim = fn.ndarray_to_qimage(img, QtGui.QImage.Format.Format_RGBX8888)
qim.save(io, 'PNG')
png = bytes(io.data().data())
return png
return bytes(io.data().data())
def makeDiffImage(im1, im2):
@ -467,155 +390,18 @@ class ImageTester(QtGui.QWidget):
def getTestDataRepo():
"""Return the path to a git repository with the required commit checked
out.
If the repository does not exist, then it is cloned from
https://github.com/pyqtgraph/test-data. If the repository already exists
then the required commit is checked out.
"""
global testDataTag
if os.getenv("CI"):
dataPath = os.path.join(os.environ["GITHUB_WORKSPACE"], '.pyqtgraph', 'test-data')
else:
dataPath = os.path.join(os.path.expanduser('~'), '.pyqtgraph', 'test-data')
gitPath = 'https://github.com/pyqtgraph/test-data'
gitbase = gitCmdBase(dataPath)
if os.path.isdir(dataPath):
# Already have a test-data repository to work with.
# Get the commit ID of testDataTag. Do a fetch if necessary.
try:
tagCommit = gitCommitId(dataPath, testDataTag)
except NameError:
cmd = gitbase + ['fetch', '--tags', 'origin']
print(' '.join(cmd))
sp.check_call(cmd)
try:
tagCommit = gitCommitId(dataPath, testDataTag)
except NameError:
raise Exception("Could not find tag '%s' in test-data repo at"
" %s" % (testDataTag, dataPath))
except Exception:
if not os.path.exists(os.path.join(dataPath, '.git')):
raise Exception("Directory '%s' does not appear to be a git "
"repository. Please remove this directory." %
dataPath)
else:
raise
# If HEAD is not the correct commit, then do a checkout
if gitCommitId(dataPath, 'HEAD') != tagCommit:
print("Checking out test-data tag '%s'" % testDataTag)
sp.check_call(gitbase + ['checkout', testDataTag])
else:
print("Attempting to create git clone of test data repo in %s.." %
dataPath)
parentPath = os.path.split(dataPath)[0]
if not os.path.isdir(parentPath):
os.makedirs(parentPath)
if os.getenv('TRAVIS') is not None or os.getenv('CI') is not None:
# Create a shallow clone of the test-data repository (to avoid
# downloading more data than is necessary)
os.makedirs(dataPath)
cmds = [
gitbase + ['init'],
gitbase + ['remote', 'add', 'origin', gitPath],
gitbase + ['fetch', '--tags', 'origin', testDataTag,
'--depth=1'],
gitbase + ['checkout', '-b', 'master', 'FETCH_HEAD'],
]
else:
# Create a full clone
cmds = [['git', 'clone', gitPath, dataPath]]
for cmd in cmds:
print(' '.join(cmd))
rval = sp.check_call(cmd)
if rval == 0:
continue
raise RuntimeError("Test data path '%s' does not exist and could "
"not be created with git. Please create a git "
"clone of %s at this path." %
(dataPath, gitPath))
return dataPath
warnings.warn(
"Test data data repo has been merged with the main repo"
"use getTestDataDirectory() instead, this method will be removed"
"in a future version of pyqtgraph",
DeprecationWarning, stacklevel=2
)
return getTestDataDirectory()
def gitCmdBase(path):
return ['git', '--git-dir=%s/.git' % path, '--work-tree=%s' % path]
def gitStatus(path):
"""Return a string listing all changes to the working tree in a git
repository.
"""
cmd = gitCmdBase(path) + ['status', '--porcelain']
return runSubprocess(cmd, stderr=None, universal_newlines=True)
def gitCommitId(path, ref):
"""Return the commit id of *ref* in the git repository at *path*.
"""
cmd = gitCmdBase(path) + ['show', ref]
try:
output = runSubprocess(cmd, stderr=None, universal_newlines=True)
except sp.CalledProcessError:
print(cmd)
raise NameError("Unknown git reference '%s'" % ref)
commit = output.split('\n')[0]
assert commit[:7] == 'commit '
return commit[7:]
def runSubprocess(command, return_code=False, **kwargs):
"""Run command using subprocess.Popen
Similar to subprocess.check_output(), which is not available in 2.6.
Run command and wait for command to complete. If the return code was zero
then return, otherwise raise CalledProcessError.
By default, this will also add stdout= and stderr=subproces.PIPE
to the call to Popen to suppress printing to the terminal.
Parameters
----------
command : list of str
Command to run as subprocess (see subprocess.Popen documentation).
**kwargs : dict
Additional kwargs to pass to ``subprocess.Popen``.
Returns
-------
stdout : str
Stdout returned by the process.
"""
# code adapted with permission from mne-python
use_kwargs = dict(stderr=None, stdout=sp.PIPE)
use_kwargs.update(kwargs)
p = sp.Popen(command, **use_kwargs)
output = p.communicate()[0]
# communicate() may return bytes, str, or None depending on the kwargs
# passed to Popen(). Convert all to unicode str:
output = '' if output is None else output
output = output.decode('utf-8') if isinstance(output, bytes) else output
if p.returncode != 0:
print(output)
err_fun = sp.CalledProcessError.__init__
if 'output' in inspect.getfullargspec(err_fun).args:
raise sp.CalledProcessError(p.returncode, command, output)
else:
raise sp.CalledProcessError(p.returncode, command)
return output
def getTestDataDirectory():
dataPath = Path(__file__).absolute().parent / "images"
return dataPath.as_posix()
def scenegraphState(view, name):
@ -632,7 +418,7 @@ def scenegraphState(view, name):
def itemState(root):
state = str(root) + '\n'
from .. import ViewBox
from pyqtgraph import ViewBox
state += 'bounding rect: ' + str(root.boundingRect()) + '\n'
if isinstance(root, ViewBox):
state += "view range: " + str(root.viewRange()) + '\n'
@ -647,7 +433,7 @@ def transformStr(t):
def indent(s, pfx):
return '\n'.join([pfx+line for line in s.split('\n')])
return '\n'.join(pfx+line for line in s.split('\n'))
class TransposedImageItem(ImageItem):

Binary file not shown.

After

Width:  |  Height:  |  Size: 622 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 660 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 670 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 718 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 671 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 749 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 647 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 622 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 656 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 668 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 885 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 788 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 547 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 770 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Some files were not shown because too many files have changed in this diff Show More