Merge pull request #1474 from j9ac9k/migrate-to-github-actions

Migrate To Github Actions
This commit is contained in:
Kyle Sunden 2020-12-23 00:32:55 -06:00 committed by GitHub
commit d3049e41d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 339 additions and 426 deletions

55
.github/workflows/codeql-analysis.yml vendored Normal file
View File

@ -0,0 +1,55 @@
name: analyze pyqtgraph
on: pull_request
jobs:
analyze:
name: analyze
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
fetch-depth: 2
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: Install Dependencies
run: |
python -m pip install --upgrade pip
pip install PyQt5 numpy scipy six
echo "CODEQL_PYTHON=$(which python)" >> $GITHUB_ENV
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: 'python'
# Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
queries: +security-and-quality
setup-python-dependencies: false
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

166
.github/workflows/main.yml vendored Normal file
View File

@ -0,0 +1,166 @@
name: test pyqtgraph
on: [push, pull_request]
jobs:
test:
runs-on: ${{ matrix.os }}
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
qt-lib: [pyqt5, pyside2]
python-version: [3.7, 3.8, 3.9]
include:
- python-version: "3.7"
qt-version: "~=5.12.0"
numpy-version: "~=1.17.0"
- python-version: "3.8"
qt-version: "~=5.15.0"
numpy-version: "~=1.19.0"
- python-version: "3.9"
qt-version: ""
numpy-version: ""
steps:
- uses: actions/checkout@v2
- name: Setup Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
# Semantic version range syntax or exact version of a Python version
python-version: ${{ matrix.python-version }}
- name: "Install Windows-Mesa OpenGL DLL"
if: runner.os == 'Windows'
run: |
curl -LJO https://github.com/pal1000/mesa-dist-win/releases/download/19.2.7/mesa3d-19.2.7-release-msvc.7z
7z x mesa3d-19.2.7-release-msvc.7z
cd x64
xcopy opengl32.dll C:\windows\system32\mesadrv.dll*
xcopy opengl32.dll C:\windows\syswow64\mesadrv.dll*
REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\MSOGL" /v DLL /t REG_SZ /d "mesadrv.dll" /f
REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\MSOGL" /v DriverVersion /t REG_DWORD /d 1 /f
REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\MSOGL" /v Flags /t REG_DWORD /d 1 /f
REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\MSOGL" /v Version /t REG_DWORD /d 2 /f
REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\MSOGL" /v DLL /t REG_SZ /d "mesadrv.dll" /f
REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\MSOGL" /v DriverVersion /t REG_DWORD /d 1 /f
REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\MSOGL" /v Flags /t REG_DWORD /d 1 /f
REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\MSOGL" /v Version /t REG_DWORD /d 2 /f
shell: cmd
- name: Install Dependencies
run: |
pip install --upgrade pip
pip install ${{ matrix.qt-lib }}${{ matrix.qt-version }} numpy${{ matrix.numpy-version }} scipy pyopengl h5py six matplotlib
pip install .
pip install pytest pytest-cov pytest-xdist coverage
- name: "Install Linux VirtualDisplay"
if: runner.os == 'Linux'
run: |
sudo apt-get install -y libxkbcommon-x11-0 x11-utils
sudo apt-get install --no-install-recommends -y libyaml-dev libegl1-mesa libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0
pip install pytest-xvfb
- name: 'Debug Info'
run: |
echo python location: `which python`
echo python version: `python --version`
echo pytest location: `which pytest`
echo installed packages
pip list
echo pyqtgraph system info
python -c "import pyqtgraph as pg; pg.systemInfo()"
shell: bash
env:
QT_DEBUG_PLUGINS: 1
- name: 'XVFB Display Info'
run: |
xvfb-run --server-args="-screen 0, 1920x1200x24 -ac +extension GLX +render -noreset" python -c "from pyqtgraph.opengl.glInfo import GLTest"
xvfb-run --server-args="-screen 0, 1920x1200x24 -ac +extension GLX +render -noreset" python -m pyqtgraph.util.get_resolution
if: runner.os == 'Linux'
- name: 'Display Info'
run: |
python -c "from pyqtgraph.opengl.glInfo import GLTest"
python -m pyqtgraph.util.get_resolution
if: runner.os != 'Linux'
- name: Run Tests
run: |
mkdir $SCREENSHOT_DIR
pytest . -v \
-n auto \
--junitxml=junit/test-results.xml \
--cov pyqtgraph --cov-report=xml --cov-report=html
shell: bash
- name: Upload Screenshots
uses: actions/upload-artifact@v2
with:
name: Screenshots (Python ${{ matrix.python-version }} - Qt-Bindings ${{ matrix.qt-lib }} - OS ${{ matrix.os }})
path: $SCREENSHOT_DIR
if-no-files-found: ignore
- name: Upload Unit Test Results
if: always()
uses: actions/upload-artifact@v2
with:
name: Unit Test Results (Python ${{ matrix.python-version }} - Qt-Bindings ${{ matrix.qt-lib }} - OS ${{ matrix.os }})
path: junit/test-results.xml
env:
SCREENSHOT_DIR: ./screenshots
build-docs:
name: build docs
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Python 3.9
uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: Install Dependencies
run: |
cd doc
python -m pip install -r requirements.txt
- name: Build Documentation
run: |
cd doc
make html SPHINXOPTS='-W -v'
- name: Upload Build Docs
uses: actions/upload-artifact@v2
with:
name: html-docs
path: |
doc/build/html
linting:
name: check linting
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Python 3.9
uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: "Install Dependencies"
run: |
pip install flake8
- name: "Check Linting"
run: |
python -m flake8 .
build-wheel:
name: build wheel
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Python 3.9
uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: Build Wheel
run: |
python -m pip install setuptools wheel
python setup.py bdist_wheel
- name: Archive pyqtgraph wheel
uses: actions/upload-artifact@v2
with:
name: wheel
path: |
dist

View File

@ -1,10 +1,14 @@
[![Build Status](https://pyqtgraph.visualstudio.com/pyqtgraph/_apis/build/status/pyqtgraph.pyqtgraph?branchName=master)](https://pyqtgraph.visualstudio.com/pyqtgraph/_build/latest?definitionId=17&branchName=master)
[![Documentation Status](https://readthedocs.org/projects/pyqtgraph/badge/?version=latest)](https://pyqtgraph.readthedocs.io/en/latest/?badge=latest)
PyQtGraph PyQtGraph
========= =========
[![PyPi](https://img.shields.io/pypi/v/pyqtgraph.svg)](https://pypi.org/project/pyqtgraph/)
[![conda-forge](https://img.shields.io/conda/vn/conda-forge/pyqtgraph.svg)](https://anaconda.org/conda-forge/pyqtgraph)
[![Build Status](https://github.com/pyqtgraph/pyqtgraph/workflows/main/badge.svg)](https://github.com/pyqtgraph/pyqtgraph/workflows/main/badge.svg)
[![CodeQL Status](https://github.com/pyqtgraph/pyqtgraph/workflows/codeql-analysis/badge.svg)](https://github.com/pyqtgraph/pyqtgraph/workflows/codeql-analysis/badge.svg)
[![Documentation Status](https://readthedocs.org/projects/pyqtgraph/badge/?version=latest)](https://pyqtgraph.readthedocs.io/en/latest/?badge=latest)
[![Total alerts](https://img.shields.io/lgtm/alerts/g/pyqtgraph/pyqtgraph.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/pyqtgraph/pyqtgraph/alerts/)
[![Language grade: Python](https://img.shields.io/lgtm/grade/python/g/pyqtgraph/pyqtgraph.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/pyqtgraph/pyqtgraph/context:python)
A pure-Python graphics library for PyQt5/PySide2 A pure-Python graphics library for PyQt5/PySide2
Copyright 2020 Luke Campagnola, University of North Carolina at Chapel Hill Copyright 2020 Luke Campagnola, University of North Carolina at Chapel Hill
@ -24,21 +28,20 @@ pyqtgraph has adopted [NEP 29](https://numpy.org/neps/nep-0029-deprecation_polic
This project supports: This project supports:
* All minor versions of Python released 42 months prior to the project, and at minimum the two latest minor versions. * All minor versions of Python released 42 months prior to the project, and at minimum the two latest minor versions.
* All minor versions of numpy released in the 24 months prior to the project, and at minimum the last three minor versions. * All minor versions of numpy released in the 24 months prior to the project, and at minimum the last three minor versions.
* All minor versions of Qt 5 currently supported by upstream Qt (Note, Qt 6 support is not yet implemented) * All minor versions of Qt 5 currently supported by upstream Qt (Note, Qt 6 support is not yet implemented)
Currently this means: Currently this means:
* Python 3.7+ * Python 3.7+
* Qt 5.12, 5.15 * Qt 5.12-5.15
* Required * Required
* PyQt5, or PySide2 * PyQt5 or PySide2
* `numpy` 1.17+ * `numpy` 1.17+
* Optional * Optional
* `scipy` for image processing * `scipy` for image processing
* `pyopengl` for 3D graphics * `pyopengl` for 3D graphics
* `pyopengl` on macOS Big Sur only works with python 3.9.1+
* `hdf5` for large hdf5 binary format support * `hdf5` for large hdf5 binary format support
Qt Bindings Test Matrix Qt Bindings Test Matrix
@ -46,12 +49,12 @@ Qt Bindings Test Matrix
The following table represents the python environments we test in our CI system. Our CI system uses Ubuntu 18.04, Windows Server 2019, and macOS 10.15 base images. The following table represents the python environments we test in our CI system. Our CI system uses Ubuntu 18.04, Windows Server 2019, and macOS 10.15 base images.
| Qt-Bindings | Python 3.6 | Python 3.7 | Python 3.8 | | Qt-Bindings | Python 3.7 | Python 3.8 | Python 3.9 |
| :------------- | :----------------: | :----------------: | :----------------: | | :------------- | :----------------: | :----------------: | :----------------: |
| PyQt5-5.9 | :white_check_mark: | :x: | :x: | | PySide2-5.12 | :white_check_mark: | :x: | :x: |
| PySide2-5.13 | :x: | :white_check_mark: | :x: | | PyQt5-5.12 | :white_check_mark: | :x: | :x: |
| PyQt5-Latest | :x: | :x: | :white_check_mark: | | PySide2-5.15 | :x: | :white_check_mark: | :white_check_mark: |
| PySide2-Latest | :x: | :x: | :white_check_mark: | | PyQt5-5.15 | :x: | :white_check_mark: | :white_check_mark: |
Support Support
------- -------

View File

@ -1,113 +0,0 @@
trigger:
branches:
include:
- '*' # Build for all branches if they have a azure-pipelines.yml file.
tags:
include:
- 'v*' # Ensure that we are building for tags starting with 'v' (Official Versions)
# Build only for PRs for master branch
pr:
autoCancel: true
branches:
include:
- master
- develop
variables:
OFFICIAL_REPO: 'pyqtgraph/pyqtgraph'
DEFAULT_MERGE_BRANCH: 'master'
disable.coverage.autogenerate: 'true'
stages:
- stage: pre_build
jobs:
- job: check_diff_size
pool:
vmImage: 'Ubuntu 18.04'
steps:
- bash: |
git config --global advice.detachedHead false
mkdir ~/repo-clone && cd ~/repo-clone
git init
git remote add -t $(Build.SourceBranchName) origin $(Build.Repository.Uri)
git remote add -t ${DEFAULT_MERGE_BRANCH} upstream https://github.com/${OFFICIAL_REPO}.git
git fetch origin $(Build.SourceBranchName)
git fetch upstream ${DEFAULT_MERGE_BRANCH}
git checkout $(Build.SourceBranchName)
MERGE_SIZE=`du -s . | sed -e "s/\t.*//"`
echo -e "Merge Size ${MERGE_SIZE}"
git checkout ${DEFAULT_MERGE_BRANCH}
TARGET_SIZE=`du -s . | sed -e "s/\t.*//"`
echo -e "Target Size ${TARGET_SIZE}"
if [ "${MERGE_SIZE}" != "${TARGET_SIZE}" ]; then
SIZE_DIFF=`expr \( ${MERGE_SIZE} - ${TARGET_SIZE} \)`;
else
SIZE_DIFF=0;
fi;
echo -e "Estimated content size difference = ${SIZE_DIFF} kB" &&
test ${SIZE_DIFF} -lt 100;
displayName: 'Diff Size Check'
- job: "style_check"
pool:
vmImage: "Ubuntu 18.04"
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: 3.7
- bash: |
pip install flake8
python setup.py style
displayName: 'flake8 check'
- job: "build_docs"
pool:
vmImage: 'Ubuntu 18.04'
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: 3.8
- script: |
cd doc
python -m pip install -r requirements.txt
make html SPHINXOPTS='-W -v'
displayName: "Build docs"
- stage: build
dependsOn: []
jobs:
- job: "build_wheel"
pool:
vmImage: 'Ubuntu 18.04'
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: 3.8
- script: |
python -m pip install setuptools wheel
python setup.py bdist_wheel --universal
displayName: "Build Python Wheel"
continueOnError: false
- publish: dist
artifact: wheel
- stage: test
displayName: "Test Suite"
dependsOn: build
jobs:
- template: azure-test-template.yml
parameters:
name: linux
vmImage: 'Ubuntu 18.04'
- template: azure-test-template.yml
parameters:
name: windows
vmImage: 'windows-2019'
- template: azure-test-template.yml
parameters:
name: macOS
vmImage: 'macOS-10.15'

View File

@ -1,208 +0,0 @@
# Azure Pipelines CI job template for PyDM Tests
# https://docs.microsoft.com/en-us/azure/devops/pipelines/languages/anaconda?view=azure-devops
parameters:
name: ''
vmImage: ''
jobs:
- job: ${{ parameters.name }}
pool:
vmImage: ${{ parameters.vmImage }}
strategy:
matrix:
Python36-PyQt5-5.9:
python.version: "3.6"
qt.bindings: "pyqt"
install.method: "conda"
Python37-PySide2-5.13:
python.version: "3.7"
qt.bindings: "pyside2"
install.method: "conda"
Python38-PyQt5-Latest:
python.version: '3.8'
qt.bindings: "PyQt5"
install.method: "pip"
Python38-PySide2-Latest:
python.version: '3.8'
qt.bindings: "PySide2"
install.method: "pip"
steps:
- task: DownloadPipelineArtifact@2
inputs:
source: 'current'
artifact: wheel
path: 'dist'
- task: ScreenResolutionUtility@1
inputs:
displaySettings: 'specific'
width: '1920'
height: '1080'
condition: eq(variables['agent.os'], 'Windows_NT' )
- task: UsePythonVersion@0
inputs:
versionSpec: $(python.version)
condition: eq(variables['install.method'], 'pip')
- script: |
curl -LJO https://github.com/pal1000/mesa-dist-win/releases/download/19.1.0/mesa3d-19.1.0-release-msvc.exe
7z x mesa3d-19.1.0-release-msvc.exe
cd x64
xcopy opengl32.dll C:\windows\system32\mesadrv.dll*
xcopy opengl32.dll C:\windows\syswow64\mesadrv.dll*
REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\MSOGL" /v DLL /t REG_SZ /d "mesadrv.dll" /f
REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\MSOGL" /v DriverVersion /t REG_DWORD /d 1 /f
REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\MSOGL" /v Flags /t REG_DWORD /d 1 /f
REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\MSOGL" /v Version /t REG_DWORD /d 2 /f
REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\MSOGL" /v DLL /t REG_SZ /d "mesadrv.dll" /f
REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\MSOGL" /v DriverVersion /t REG_DWORD /d 1 /f
REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\MSOGL" /v Flags /t REG_DWORD /d 1 /f
REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\MSOGL" /v Version /t REG_DWORD /d 2 /f
displayName: "Install Windows-Mesa OpenGL DLL"
condition: eq(variables['agent.os'], 'Windows_NT')
- bash: |
if [ $(agent.os) == 'Linux' ]
then
echo "##vso[task.prependpath]$CONDA/bin"
elif [ $(agent.os) == 'Darwin' ]
then
sudo chown -R $USER $CONDA
echo "##vso[task.prependpath]$CONDA/bin"
elif [ $(agent.os) == 'Windows_NT' ]
then
echo "##vso[task.prependpath]$CONDA/Scripts"
else
echo 'Just what OS are you using?'
fi
displayName: 'Add Conda To $PATH'
condition: eq(variables['install.method'], 'conda' )
continueOnError: false
- bash: |
if [ $(install.method) == "conda" ]
then
conda update --all --yes --quiet
conda config --env --set always_yes true
if [ $(python.version) == '2.7' ]
then
conda config --set restore_free_channel true
fi
if [ $(qt.bindings) == "pyside2" ] || ([ $(qt.bindings) == 'pyside' ] && [ $(agent.os) == 'Darwin' ])
then
conda config --prepend channels conda-forge
fi
conda create --name test-environment-$(python.version) python=$(python.version) --yes --quiet
source activate test-environment-$(python.version)
conda info
if [ $(qt.bindings) == "pyside2" ]
then
conda install $(qt.bindings) --yes --quiet --strict-channel-priority
else
conda install $(qt.bindings) --yes --quiet
fi
conda install numpy scipy pyopengl h5py six --yes --quiet
pip install matplotlib
else
pip install $(qt.bindings) numpy scipy pyopengl h5py six matplotlib
fi
pip install pytest pytest-cov coverage pytest-xdist
if [ $(python.version) == "2.7" ]
then
pip install pytest-faulthandler==1.6.0
export PYTEST_ADDOPTS="--faulthandler-timeout=15"
else
pip install pytest pytest-cov coverage
fi
displayName: "Install Dependencies"
- bash: |
if [ $(install.method) == "conda" ]
then
source activate test-environment-$(python.version)
fi
python -m pip install --no-index --find-links=dist pyqtgraph
displayName: 'Install Wheel'
- bash: |
sudo apt-get install -y libxkbcommon-x11-dev
# workaround for QTBUG-84489
sudo apt-get install -y libxcb-xfixes0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0
if [ $(install.method) == "conda" ]
then
source activate test-environment-$(python.version)
fi
if [ $(python.version) == "2.7" ]
then
pip install PyVirtualDisplay==0.2.5 pytest-xvfb==1.2.0
else
pip install pytest-xvfb
fi
displayName: "Virtual Display Setup"
condition: eq(variables['agent.os'], 'Linux' )
- bash: |
export QT_DEBUG_PLUGINS=1
if [ $(install.method) == "conda" ]
then
source activate test-environment-$(python.version)
fi
echo python location: `which python`
echo python version: `python --version`
echo pytest location: `which pytest`
echo installed packages
pip list
echo pyqtgraph system info
python -c "import pyqtgraph as pg; pg.systemInfo()"
echo display information
if [ $(agent.os) == 'Linux' ]
then
export DISPLAY=:99.0
Xvfb :99 -screen 0 1920x1200x24 -ac +extension GLX +render -noreset &
sleep 3
fi
python -m pyqtgraph.util.get_resolution
echo openGL information
python -c "from pyqtgraph.opengl.glInfo import GLTest"
displayName: 'Debug Info'
continueOnError: false
- bash: |
if [ $(install.method) == "conda" ]
then
source activate test-environment-$(python.version)
fi
mkdir -p "$SCREENSHOT_DIR"
# echo "If Screenshots are generated, they may be downloaded from:"
# echo "https://dev.azure.com/pyqtgraph/pyqtgraph/_apis/build/builds/$(Build.BuildId)/artifacts?artifactName=Screenshots&api-version=5.0"
pytest . -v \
-n 1 \
--junitxml=junit/test-results.xml \
--cov pyqtgraph --cov-report=xml --cov-report=html
displayName: 'Unit tests'
env:
AZURE: 1
SCREENSHOT_DIR: $(Build.ArtifactStagingDirectory)/screenshots
- task: PublishBuildArtifacts@1
displayName: 'Publish Screenshots'
condition: failed()
inputs:
pathtoPublish: $(Build.ArtifactStagingDirectory)/screenshots
artifactName: Screenshots
- task: PublishTestResults@2
condition: succeededOrFailed()
inputs:
testResultsFiles: '**/test-*.xml'
testRunTitle: 'Test Results for $(agent.os) - $(python.version) - $(qt.bindings) - $(install.method)'
publishRunAttachments: true
- task: PublishCodeCoverageResults@1
inputs:
codeCoverageTool: Cobertura
summaryFileLocation: '$(System.DefaultWorkingDirectory)/**/coverage.xml'
reportDirectory: '$(System.DefaultWorkingDirectory)/**/htmlcov'

View File

@ -1,4 +1,6 @@
import keyword
import os import os
import re
import sys import sys
import subprocess import subprocess
import pyqtgraph as pg import pyqtgraph as pg
@ -104,7 +106,7 @@ examples = OrderedDict([
# based on https://github.com/art1415926535/PyQt5-syntax-highlighting # based on https://github.com/art1415926535/PyQt5-syntax-highlighting
QRegExp = QtCore.QRegExp QRegularExpression = QtCore.QRegularExpression
QFont = QtGui.QFont QFont = QtGui.QFont
QColor = QtGui.QColor QColor = QtGui.QColor
@ -208,55 +210,45 @@ class PythonHighlighter(QSyntaxHighlighter):
"""Syntax highlighter for the Python language. """Syntax highlighter for the Python language.
""" """
# Python keywords # Python keywords
keywords = [ keywords = keyword.kwlist
'and', 'assert', 'break', 'class', 'continue', 'def',
'del', 'elif', 'else', 'except', 'exec', 'finally',
'for', 'from', 'global', 'if', 'import', 'in',
'is', 'lambda', 'not', 'or', 'pass', 'print',
'raise', 'return', 'try', 'while', 'yield',
'None', 'True', 'False', 'async', 'await',
]
# Python operators # Python operators
operators = [ operators = [
'=', r'=',
# Comparison # Comparison
'==', '!=', '<', '<=', '>', '>=', r'==', r'!=', r'<', r'<=', r'>', r'>=',
# Arithmetic # Arithmetic
'\+', '-', '\*', '/', '//', '\%', '\*\*', r'\+', r"-", r'\*', r'/', r'//', r'%', r'\*\*',
# In-place # In-place
'\+=', '-=', '\*=', '/=', '\%=', r'\+=', r'-=', r'\*=', r'/=', r'\%=',
# Bitwise # Bitwise
'\^', '\|', '\&', '\~', '>>', '<<', r'\^', r'\|', r'&', r'~', r'>>', r'<<',
] ]
# Python braces # Python braces
braces = [ braces = [
'\{', '\}', '\(', '\)', '\[', '\]', r'\{', r'\}', r'\(', r'\)', r'\[', r'\]',
] ]
def __init__(self, document): def __init__(self, document):
QSyntaxHighlighter.__init__(self, document) QSyntaxHighlighter.__init__(self, document)
# Multi-line strings (expression, flag, style) # Multi-line strings (expression, flag, style)
# FIXME: The triple-quotes in these two lines will mess up the self.tri_single = (QRegularExpression("'''"), 1, 'string2')
# syntax highlighting from this point onward self.tri_double = (QRegularExpression('"""'), 2, 'string2')
self.tri_single = (QRegExp("'''"), 1, 'string2')
self.tri_double = (QRegExp('"""'), 2, 'string2')
rules = [] rules = []
# Keyword, operator, and brace rules # Keyword, operator, and brace rules
rules += [(r'\b%s\b' % w, 0, 'keyword') rules += [(r'\b%s\b' % w, 0, 'keyword')
for w in PythonHighlighter.keywords] for w in PythonHighlighter.keywords]
rules += [(r'%s' % o, 0, 'operator') rules += [(o, 0, 'operator')
for o in PythonHighlighter.operators] for o in PythonHighlighter.operators]
rules += [(r'%s' % b, 0, 'brace') rules += [(b, 0, 'brace')
for b in PythonHighlighter.braces] for b in PythonHighlighter.braces]
# All other rules # All other rules
rules += [ rules += [
# 'self' # 'self'
(r'\bself\b', 0, 'self'), (r'\bself\b', 0, 'self'),
@ -277,12 +269,8 @@ class PythonHighlighter(QSyntaxHighlighter):
# From '#' until a newline # From '#' until a newline
(r'#[^\n]*', 0, 'comment'), (r'#[^\n]*', 0, 'comment'),
] ]
self.rules = rules
# Build a QRegExp for each pattern
self.rules = [(QRegExp(pat), index, fmt)
for (pat, index, fmt) in rules]
@property @property
def styles(self): def styles(self):
@ -294,16 +282,14 @@ class PythonHighlighter(QSyntaxHighlighter):
""" """
# Do other syntax formatting # Do other syntax formatting
for expression, nth, format in self.rules: for expression, nth, format in self.rules:
index = expression.indexIn(text, 0)
format = self.styles[format] format = self.styles[format]
while index >= 0: for n, match in enumerate(re.finditer(expression, text)):
# We actually want the index of the nth match if n < nth:
index = expression.pos(nth) continue
length = len(expression.cap(nth)) start = match.start()
self.setFormat(index, length, format) length = match.end() - start
index = expression.indexIn(text, index + length) self.setFormat(start, length, format)
self.setCurrentBlockState(0) self.setCurrentBlockState(0)
# Do multi-line strings # Do multi-line strings
@ -312,11 +298,16 @@ class PythonHighlighter(QSyntaxHighlighter):
in_multiline = self.match_multiline(text, *self.tri_double) in_multiline = self.match_multiline(text, *self.tri_double)
def match_multiline(self, text, delimiter, in_state, style): def match_multiline(self, text, delimiter, in_state, style):
"""Do highlighting of multi-line strings. ``delimiter`` should be a """Do highlighting of multi-line strings.
``QRegExp`` for triple-single-quotes or triple-double-quotes, and
``in_state`` should be a unique integer to represent the corresponding =========== ==========================================================
state changes when inside those strings. Returns True if we're still delimiter (QRegularExpression) for triple-single-quotes or
inside a multi-line string when this function is finished. triple-double-quotes
in_state (int) to represent the corresponding state changes when
inside those strings. Returns True if we're still inside a
multi-line string when this function is finished.
style (str) representation of the kind of style to use
=========== ==========================================================
""" """
# If inside triple-single quotes, start at 0 # If inside triple-single quotes, start at 0
if self.previousBlockState() == in_state: if self.previousBlockState() == in_state:
@ -324,17 +315,19 @@ class PythonHighlighter(QSyntaxHighlighter):
add = 0 add = 0
# Otherwise, look for the delimiter on this line # Otherwise, look for the delimiter on this line
else: else:
start = delimiter.indexIn(text) match = delimiter.match(text)
start = match.capturedStart()
# Move past this match # Move past this match
add = delimiter.matchedLength() add = match.capturedLength()
# As long as there's a delimiter match on this line... # As long as there's a delimiter match on this line...
while start >= 0: while start >= 0:
# Look for the ending delimiter # Look for the ending delimiter
end = delimiter.indexIn(text, start + add) match = delimiter.match(text, start + add)
end = match.capturedEnd()
# Ending delimiter on this line? # Ending delimiter on this line?
if end >= add: if end >= add:
length = end - start + add + delimiter.matchedLength() length = end - start + add + match.capturedLength()
self.setCurrentBlockState(0) self.setCurrentBlockState(0)
# No; multi-line string # No; multi-line string
else: else:
@ -343,7 +336,8 @@ class PythonHighlighter(QSyntaxHighlighter):
# Apply formatting # Apply formatting
self.setFormat(start, length, self.styles[style]) self.setFormat(start, length, self.styles[style])
# Look for the next match # Look for the next match
start = delimiter.indexIn(text, start + length) match = delimiter.match(text, start + length)
start = match.capturedStart()
# Return True if still inside a multi-line string, False otherwise # Return True if still inside a multi-line string, False otherwise
if self.currentBlockState() == in_state: if self.currentBlockState() == in_state:

View File

@ -10,6 +10,7 @@ import importlib
import itertools import itertools
import pytest import pytest
import os, sys import os, sys
import platform
import subprocess import subprocess
import time import time
if __name__ == "__main__" and (__package__ is None or __package__==''): if __name__ == "__main__" and (__package__ is None or __package__==''):
@ -69,75 +70,83 @@ conditionalExamples = {
) )
), ),
'GLVolumeItem.py': exceptionCondition( 'GLVolumeItem.py': exceptionCondition(
not(sys.platform == "darwin" and not(platform.system() == "Darwin" and
sys.version_info[0] == 2 and tuple(map(int, platform.mac_ver()[0].split("."))) >= (10, 16) and
(frontends[Qt.PYQT4] or frontends[Qt.PYSIDE])), (sys.version_info <= (3, 8, 7) or
(sys.version_info >= (3, 9) and sys.version_info < (3, 9, 1)))),
reason=( reason=(
"glClear does not work on macOS + Python2.7 + Qt4: ", "pyopenGL cannot find openGL libray on big sur: "
"https://github.com/pyqtgraph/pyqtgraph/issues/939" "https://github.com/python/cpython/pull/21241"
) )
), ),
'GLIsosurface.py': exceptionCondition( 'GLIsosurface.py': exceptionCondition(
not(sys.platform == "darwin" and not(platform.system() == "Darwin" and
sys.version_info[0] == 2 and tuple(map(int, platform.mac_ver()[0].split("."))) >= (10, 16) and
(frontends[Qt.PYQT4] or frontends[Qt.PYSIDE])), (sys.version_info <= (3, 8, 7) or
(sys.version_info >= (3, 9) and sys.version_info < (3, 9, 1)))),
reason=( reason=(
"glClear does not work on macOS + Python2.7 + Qt4: ", "pyopenGL cannot find openGL libray on big sur: "
"https://github.com/pyqtgraph/pyqtgraph/issues/939" "https://github.com/python/cpython/pull/21241"
) )
), ),
'GLSurfacePlot.py': exceptionCondition( 'GLSurfacePlot.py': exceptionCondition(
not(sys.platform == "darwin" and not(platform.system() == "Darwin" and
sys.version_info[0] == 2 and tuple(map(int, platform.mac_ver()[0].split("."))) >= (10, 16) and
(frontends[Qt.PYQT4] or frontends[Qt.PYSIDE])), (sys.version_info <= (3, 8, 7) or
(sys.version_info >= (3, 9) and sys.version_info < (3, 9, 1)))),
reason=( reason=(
"glClear does not work on macOS + Python2.7 + Qt4: ", "pyopenGL cannot find openGL libray on big sur: "
"https://github.com/pyqtgraph/pyqtgraph/issues/939" "https://github.com/python/cpython/pull/21241"
) )
), ),
'GLScatterPlotItem.py': exceptionCondition( 'GLScatterPlotItem.py': exceptionCondition(
not(sys.platform == "darwin" and not(platform.system() == "Darwin" and
sys.version_info[0] == 2 and tuple(map(int, platform.mac_ver()[0].split("."))) >= (10, 16) and
(frontends[Qt.PYQT4] or frontends[Qt.PYSIDE])), (sys.version_info <= (3, 8, 7) or
(sys.version_info >= (3, 9) and sys.version_info < (3, 9, 1)))),
reason=( reason=(
"glClear does not work on macOS + Python2.7 + Qt4: ", "pyopenGL cannot find openGL libray on big sur: "
"https://github.com/pyqtgraph/pyqtgraph/issues/939" "https://github.com/python/cpython/pull/21241"
) )
), ),
'GLshaders.py': exceptionCondition( 'GLshaders.py': exceptionCondition(
not(sys.platform == "darwin" and not(platform.system() == "Darwin" and
sys.version_info[0] == 2 and tuple(map(int, platform.mac_ver()[0].split("."))) >= (10, 16) and
(frontends[Qt.PYQT4] or frontends[Qt.PYSIDE])), (sys.version_info <= (3, 8, 7) or
(sys.version_info >= (3, 9) and sys.version_info < (3, 9, 1)))),
reason=( reason=(
"glClear does not work on macOS + Python2.7 + Qt4: ", "pyopenGL cannot find openGL libray on big sur: "
"https://github.com/pyqtgraph/pyqtgraph/issues/939" "https://github.com/python/cpython/pull/21241"
) )
), ),
'GLLinePlotItem.py': exceptionCondition( 'GLLinePlotItem.py': exceptionCondition(
not(sys.platform == "darwin" and not(platform.system() == "Darwin" and
sys.version_info[0] == 2 and tuple(map(int, platform.mac_ver()[0].split("."))) >= (10, 16) and
(frontends[Qt.PYQT4] or frontends[Qt.PYSIDE])), (sys.version_info <= (3, 8, 7) or
(sys.version_info >= (3, 9) and sys.version_info < (3, 9, 1)))),
reason=( reason=(
"glClear does not work on macOS + Python2.7 + Qt4: ", "pyopenGL cannot find openGL libray on big sur: "
"https://github.com/pyqtgraph/pyqtgraph/issues/939" "https://github.com/python/cpython/pull/21241"
) )
), ),
'GLMeshItem.py': exceptionCondition( 'GLMeshItem.py': exceptionCondition(
not(sys.platform == "darwin" and not(platform.system() == "Darwin" and
sys.version_info[0] == 2 and tuple(map(int, platform.mac_ver()[0].split("."))) >= (10, 16) and
(frontends[Qt.PYQT4] or frontends[Qt.PYSIDE])), (sys.version_info <= (3, 8, 7) or
(sys.version_info >= (3, 9) and sys.version_info < (3, 9, 1)))),
reason=( reason=(
"glClear does not work on macOS + Python2.7 + Qt4: ", "pyopenGL cannot find openGL libray on big sur: "
"https://github.com/pyqtgraph/pyqtgraph/issues/939" "https://github.com/python/cpython/pull/21241"
) )
), ),
'GLImageItem.py': exceptionCondition( 'GLImageItem.py': exceptionCondition(
not(sys.platform == "darwin" and not(platform.system() == "Darwin" and
sys.version_info[0] == 2 and tuple(map(int, platform.mac_ver()[0].split("."))) >= (10, 16) and
(frontends[Qt.PYQT4] or frontends[Qt.PYSIDE])), (sys.version_info <= (3, 8, 7) or
(sys.version_info >= (3, 9) and sys.version_info < (3, 9, 1)))),
reason=( reason=(
"glClear does not work on macOS + Python2.7 + Qt4: ", "pyopenGL cannot find openGL libray on big sur: "
"https://github.com/pyqtgraph/pyqtgraph/issues/939" "https://github.com/python/cpython/pull/21241"
) )
) )
} }

View File

@ -38,7 +38,7 @@ SI_PREFIXES_ASCII = 'yzafpnum kMGTPEZY'
SI_PREFIX_EXPONENTS = dict([(SI_PREFIXES[i], (i-8)*3) for i in range(len(SI_PREFIXES))]) SI_PREFIX_EXPONENTS = dict([(SI_PREFIXES[i], (i-8)*3) for i in range(len(SI_PREFIXES))])
SI_PREFIX_EXPONENTS['u'] = -6 SI_PREFIX_EXPONENTS['u'] = -6
FLOAT_REGEX = re.compile(r'(?P<number>[+-]?((((\d+(\.\d*)?)|(\d*\.\d+))([eE][+-]?\d+)?)|((?i)(nan)|(inf))))\s*((?P<siPrefix>[u' + SI_PREFIXES + r']?)(?P<suffix>\w.*))?$') FLOAT_REGEX = re.compile(r'(?P<number>[+-]?((((\d+(\.\d*)?)|(\d*\.\d+))([eE][+-]?\d+)?)|((?i:nan)|(inf))))\s*((?P<siPrefix>[u' + SI_PREFIXES + r']?)(?P<suffix>\w.*))?$')
INT_REGEX = re.compile(r'(?P<number>[+-]?\d+)\s*(?P<siPrefix>[u' + SI_PREFIXES + r']?)(?P<suffix>.*)$') INT_REGEX = re.compile(r'(?P<number>[+-]?\d+)\s*(?P<siPrefix>[u' + SI_PREFIXES + r']?)(?P<suffix>.*)$')

View File

@ -212,7 +212,7 @@ def assertImageApproved(image, standardFile, message=None, **kwargs):
else: else:
if os.getenv('TRAVIS') is not None: if os.getenv('TRAVIS') is not None:
saveFailedTest(image, stdImage, standardFile, upload=True) saveFailedTest(image, stdImage, standardFile, upload=True)
elif os.getenv('AZURE') is not None: elif os.getenv('CI') is not None:
standardFile = os.path.join(os.getenv("SCREENSHOT_DIR", "screenshots"), standardFile) standardFile = os.path.join(os.getenv("SCREENSHOT_DIR", "screenshots"), standardFile)
saveFailedTest(image, stdImage, standardFile) saveFailedTest(image, stdImage, standardFile)
print(graphstate) print(graphstate)
@ -509,7 +509,7 @@ def getTestDataRepo():
if not os.path.isdir(parentPath): if not os.path.isdir(parentPath):
os.makedirs(parentPath) os.makedirs(parentPath)
if os.getenv('TRAVIS') is not None or os.getenv('AZURE') is not None: 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 # Create a shallow clone of the test-data repository (to avoid
# downloading more data than is necessary) # downloading more data than is necessary)
os.makedirs(dataPath) os.makedirs(dataPath)

View File

@ -1,6 +1,7 @@
import tempfile, os, sys, shutil, time import tempfile, os, sys, shutil, time
import pyqtgraph as pg import pyqtgraph as pg
import pyqtgraph.reload import pyqtgraph.reload
import pytest
pgpath = os.path.join(os.path.dirname(pg.__file__), '..') pgpath = os.path.join(os.path.dirname(pg.__file__), '..')
@ -41,7 +42,11 @@ def remove_cache(mod):
if os.path.isdir(cachedir): if os.path.isdir(cachedir):
shutil.rmtree(cachedir) shutil.rmtree(cachedir)
@pytest.mark.skipif(
pg.Qt.QT_LIB == "PySide2"
and pg.Qt.PySide2.__version__.startswith("5.15")
and sys.version_info > (3, 9),
reason="Unknown Issue")
def test_reload(): def test_reload():
py3 = sys.version_info >= (3,) py3 = sys.version_info >= (3,)

View File

@ -1,7 +1,7 @@
from ..Qt import QtGui, QtCore, QT_LIB from ..Qt import QtGui, QtCore, QT_LIB
import matplotlib import matplotlib
if QT_LIB != 'PyQt5': if QT_LIB not in ['PyQt5', "PySide2"]:
if QT_LIB == 'PySide': if QT_LIB == 'PySide':
matplotlib.rcParams['backend.qt4']='PySide' matplotlib.rcParams['backend.qt4']='PySide'

View File

@ -16,4 +16,6 @@ filterwarnings =
# py36/pyside2_512 specific issue # py36/pyside2_512 specific issue
ignore:split\(\) requires a non-empty pattern match\.:FutureWarning ignore:split\(\) requires a non-empty pattern match\.:FutureWarning
# pyqtgraph specific warning we want to ignore during testing # pyqtgraph specific warning we want to ignore during testing
ignore:Visible window deleted. To prevent this, store a reference to the window object. ignore:Visible window deleted. To prevent this, store a reference to the window object.
# xvfb warnings
ignore:Unknown config option:pytest.PytestConfigWarning

View File

@ -379,7 +379,7 @@ def getGitVersion(tagPrefix):
'describe', 'describe',
'--tags', '--tags',
'--dirty', '--dirty',
'--match=%s*'%tagPrefix]).strip().decode('utf-8') '--match="%s*"'%tagPrefix]).strip().decode('utf-8')
# chop off prefix # chop off prefix
assert v.startswith(tagPrefix) assert v.startswith(tagPrefix)