diff --git a/.github/workflows/qt_viz_tests.yml b/.github/workflows/qt_viz_tests.yml index 8f38dc68..ce7b196b 100644 --- a/.github/workflows/qt_viz_tests.yml +++ b/.github/workflows/qt_viz_tests.yml @@ -10,7 +10,7 @@ on: - cron: "0 4 * * *" jobs: - flake: + style: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -21,22 +21,22 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - python -m pip install flake8 - - name: Lint with flake8 - run: flake8 + python -m pip install ruff + - name: Lint with ruff + run: ruff . pytest: strategy: fail-fast: false matrix: os: [ubuntu, windows, macos] mne: [main, maint/1.3] - opengl: ['[opengl]'] + opengl: ['opengl'] python: ['3.11'] name: [matrix] include: - os: ubuntu mne: main - opengl: '[opengl]' + opengl: 'opengl' python: '3.8' name: old 3.8 - os: ubuntu @@ -51,7 +51,7 @@ jobs: name: no opengl - os: ubuntu mne: maint/1.0 - opengl: '[opengl]' + opengl: 'opengl' python: '3.9' name: old name: pytest ${{ matrix.name }} / ${{ matrix.os }} / MNE ${{ matrix.mne }} @@ -60,15 +60,15 @@ jobs: MNE_LOGGING_LEVEL: 'warning' MKL_NUM_THREADS: '1' PYTHONUNBUFFERED: '1' - DISPLAY: ':99.0' MNE_BRANCH: ${{ matrix.mne }} - PIP_OPTION: ${{ matrix.opengl }} PYTHON_VERSION: ${{ matrix.python }} defaults: run: shell: bash steps: - uses: actions/checkout@v3 + with: + fetch-depth: 0 - name: Set up Python uses: actions/setup-python@v4 with: @@ -79,7 +79,12 @@ jobs: python -m pip install --upgrade pip git clone -b ${MNE_BRANCH} --single-branch --branch main https://github.com/mne-tools/mne-python.git ../mne-python python -m pip install -qe ../mne-python - python -m pip install -ve .${PIP_OPTION} -r requirements.txt -r requirements_testing.txt PyQt5 + if [[ "${{ matrix.opengl }}" == "opengl" ]]; then + PIP_OPTION="[opengl,tests]" + else + PIP_OPTION="[tests]" + fi + python -m pip install -ve .${PIP_OPTION} PyQt5 - shell: bash -el {0} run: ./tools/get_testing_version.sh name: 'Get testing version' @@ -91,22 +96,10 @@ jobs: name: 'Cache testing data' - run: python -c 'import mne; print(mne.datasets.testing.data_path(verbose=True))' name: 'Download testing data' - - run: | - set -e - git clone --depth 1 https://github.com/pyvista/gl-ci-helpers.git - powershell gl-ci-helpers/appveyor/install_opengl.ps1 - name: Setup OpenGL on Windows - if: runner.os == 'Windows' - - run: | - curl --remote-name https://raw.githubusercontent.com/mne-tools/mne-python/main/tools/setup_xvfb.sh - bash setup_xvfb.sh - name: Setup xvfb on Linux - working-directory: ../mne-python - if: runner.os == 'Linux' - - run: | - set -e - sudo apt install mesa-utils - glxinfo | grep enderer + - uses: pyvista/setup-headless-display-action@main + with: + qt: true + - run: glxinfo | grep enderer name: Check OpenGL working-directory: ../mne-python if: runner.os == 'Linux' && contains(matrix.opengl, 'opengl') @@ -129,19 +122,19 @@ jobs: matrix: os: [ubuntu] mne: [main] - opengl: ['[opengl]'] + opengl: [opengl] qt: [PyQt5, PyQt6, PySide2, PySide6] python: ['3.10'] # When going to 3.11, PySide2 should be removed or special-cased name: [matrix] include: - os: macos mne: main - opengl: '[opengl]' + opengl: 'opengl' qt: PySide6 python: '3.11' - os: windows mne: main - opengl: '[opengl]' + opengl: 'opengl' qt: PySide6 python: '3.11' name: ${{ matrix.qt }} / ${{ matrix.os }} @@ -151,7 +144,6 @@ jobs: MKL_NUM_THREADS: '1' PYTHONUNBUFFERED: '1' MNE_BRANCH: ${{ matrix.mne }} - PIP_OPTION: ${{ matrix.opengl }} PYTHON_VERSION: ${{ matrix.python }} QT_LIB: ${{ matrix.qt }} defaults: @@ -159,6 +151,8 @@ jobs: shell: bash steps: - uses: actions/checkout@v3 + with: + fetch-depth: 0 - name: Set up Python uses: actions/setup-python@v4 with: @@ -175,7 +169,12 @@ jobs: else QT_LIB_INSTALL="$QT_LIB" fi - python -m pip install -ve .${PIP_OPTION} -r requirements.txt -r requirements_testing.txt $QT_LIB_INSTALL + if [[ "${{ matrix.opengl }}" == "opengl" ]]; then + PIP_OPTION="[opengl,tests]" + else + PIP_OPTION="[tests]" + fi + python -m pip install -ve .${PIP_OPTION} ${QT_LIB_INSTALL} - shell: bash -el {0} run: ./tools/get_testing_version.sh name: 'Get testing version' @@ -190,9 +189,6 @@ jobs: - uses: pyvista/setup-headless-display-action@main with: qt: true - - run: sudo apt install -yq libegl1 - name: Install EGL - if: runner.os == 'Linux' - name: Start Qt on its own run: LD_DEBUG=libs python -c "from ${QT_LIB}.QtWidgets import QApplication, QWidget; app = QApplication([]); import matplotlib; matplotlib.use('QtAgg'); import matplotlib.pyplot as plt; plt.figure()" - name: Check Qt diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 88a064a7..9a913cd6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,25 +1,39 @@ -name: Upload Python Package +# Upload a Python Package using Twine when a release is created +name: Build on: release: types: [published] + push: + branches: + - main + pull_request: + branches: + - main + +permissions: + contents: read jobs: - deploy: + package: runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 - - name: Install dependencies - run: | - python -m pip install --upgrade pip - python -m pip install --upgrade setuptools wheel twine - - name: Build and publish - env: - TWINE_USERNAME: __token__ - TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} - run: | - python setup.py sdist bdist_wheel - twine check dist/* - twine upload dist/* + - uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.10' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install build twine + - name: Build package + run: python -m build --sdist --wheel + - name: Check package + run: twine check --strict dist/* + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + user: __token__ + password: ${{ secrets.PYPI_PASSWORD }} + if: github.event_name == 'release' diff --git a/mne_qt_browser/_version.py b/mne_qt_browser/_version.py index 042af8a5..58c6fb37 100644 --- a/mne_qt_browser/_version.py +++ b/mne_qt_browser/_version.py @@ -1,2 +1,10 @@ """The version number.""" -__version__ = '0.5.dev0' + +try: + from importlib.metadata import version + __version__ = version("mne_qt_browser") +except Exception: + try: + from ._version import __version__ + except ImportError: + __version__ = '0.0.0' diff --git a/mne_qt_browser/tests/test_speed.py b/mne_qt_browser/tests/test_speed.py index 480da562..80a3a214 100644 --- a/mne_qt_browser/tests/test_speed.py +++ b/mne_qt_browser/tests/test_speed.py @@ -11,7 +11,6 @@ import numpy as np import pytest from qtpy.QtCore import QTimer -from qtpy.QtWidgets import QApplication import mne from mne_qt_browser.figure import MNEQtBrowser @@ -118,15 +117,12 @@ def _initiate_hscroll(self, *, store, request): pytest.param({}, id='defaults'), ]) def test_scroll_speed_raw(raw_orig, benchmark_param, store, - pg_backend, request): + pg_backend, request, qapp): """Test the speed of a parameter.""" # Remove spaces and get params with values - app = QApplication.instance() - if app is None: - app = QApplication(sys.argv) fig = raw_orig.plot(duration=5, n_channels=40, show=False, block=False, **benchmark_param) - _Benchmark(fig, app, store, request) + _Benchmark(fig, qapp, store, request) @pytest.mark.benchmark @@ -142,11 +138,7 @@ def test_scroll_speed_raw(raw_orig, benchmark_param, store, pytest.param({}, id='defaults'), ]) def test_scroll_speed_epochs_unicolor(raw_orig, benchmark_param, store, - pg_backend, request): - app = QApplication.instance() - if app is None: - app = QApplication(sys.argv) - + pg_backend, request, qapp): events = np.full((50, 3), [0, 0, 1]) events[:, 0] = np.arange(0, len(raw_orig), len(raw_orig) / 50) \ + raw_orig.first_samp @@ -155,7 +147,7 @@ def test_scroll_speed_epochs_unicolor(raw_orig, benchmark_param, store, epochs.info._unlocked = True fig = epochs.plot(show=False, block=False, **benchmark_param) - _Benchmark(fig, app, store, request) + _Benchmark(fig, qapp, store, request) @pytest.mark.benchmark @@ -171,12 +163,7 @@ def test_scroll_speed_epochs_unicolor(raw_orig, benchmark_param, store, pytest.param({}, id='defaults'), ]) def test_scroll_speed_epochs_multicolor(raw_orig, benchmark_param, store, - pg_backend, request): - from qtpy.QtWidgets import QApplication - app = QApplication.instance() - if app is None: - app = QApplication(sys.argv) - + pg_backend, request, qapp): events = np.full((50, 3), [0, 0, 1]) events[:, 0] = np.arange(0, len(raw_orig), len(raw_orig) / 50) \ + raw_orig.first_samp @@ -204,4 +191,4 @@ def test_scroll_speed_epochs_multicolor(raw_orig, benchmark_param, store, fig = epochs.plot(show=False, block=False, epoch_colors=epoch_colors, **benchmark_param) - _Benchmark(fig, app, store, request) + _Benchmark(fig, qapp, store, request) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..473c6dd9 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,70 @@ +[project] +name = "mne-qt-browser" +description = "A new backend based on pyqtgraph for the 2D-Data-Browser in MNE-Python" +readme = "README.md" +requires-python = ">=3.8" +license = {file = "LICENSE"} +keywords = ["science", "neuroscience", "psychology"] +authors = [ + {name = "Martin Schulz", email = "dev@earthman-music.de"}, +] +classifiers = [ + "Intended Audience :: Science/Research", + "Programming Language :: Python" +] +dependencies = [ + "importlib_metadata; python_version < '3.8'", + "packaging", + "setuptools >=65", + "numpy", + "scipy", + "matplotlib", + "qtpy", + "scooby", + "mne>=1.0", + "pyqtgraph>=0.12.3", + "colorspacious", + "pyopengl; platform_system=='Darwin'", + "darkdetect", + "qdarkstyle", +] +dynamic = ["version"] + +[project.optional-dependencies] +opengl = [ + "pyopengl", +] +tests = [ + "pytest", + "pytest-qt", + "pytest-cov", + "pytest-timeout", + "scikit-learn", + "pytest-harvest", + "pytest-error-for-skips", + "sphinx-gallery", +] + +[project.urls] +homepage = "https://mne.tools/mne-bids-pipeline" +repository = "https://github.com/mne-tools/mne-bids-pipeline" +changelog = "http://github.com/mne-tools/mne-qt-browser/releases" + +[build-system] +requires = ["setuptools>=65", "setuptools_scm[toml]>=6.2", "wheel"] +build-backend = "setuptools.build_meta" + +[tool.setuptools_scm] +tag_regex = "^(?Pv)?(?P[0-9.]+)(?P.*)?$" +version_scheme = "release-branch-semver" +write_to = "mne_qt_browser/_version.py" + +[tool.setuptools.packages.find] +exclude = ["false"] # on CircleCI this folder appears during pip install -ve. for an unknown reason + +[tool.pytest.ini_options] +addopts = "-ra --cov-report= --tb=short --junit-xml=junit-results.xml --capture=sys --durations=10" +testpaths = [ + "mne_qt_browser", +] +junit_family = "xunit2" diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 8af67f0f..00000000 --- a/requirements.txt +++ /dev/null @@ -1,12 +0,0 @@ -# Basic dependencies for browser -numpy -scipy -matplotlib -qtpy -scooby -mne>=1.0 -pyqtgraph>=0.12.3 -colorspacious -pyopengl; platform_system=="Darwin" -darkdetect -qdarkstyle diff --git a/requirements_testing.txt b/requirements_testing.txt deleted file mode 100644 index 597c73a3..00000000 --- a/requirements_testing.txt +++ /dev/null @@ -1,10 +0,0 @@ -pytest -pytest-qt -pytest-cov -pytest-timeout -pooch -tqdm -scikit-learn # for testing ICA -pytest-harvest -pytest-error-for-skips -https://github.com/sphinx-gallery/sphinx-gallery/zipball/master # for testing scrapers diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 52e58a12..00000000 --- a/setup.cfg +++ /dev/null @@ -1,7 +0,0 @@ -[tool:pytest] -addopts = - -ra --cov-report= --tb=short --junit-xml=junit-results.xml --capture=sys -junit_family = xunit2 - -[flake8] -exclude = mne_qt_browser/icons/resources.py \ No newline at end of file diff --git a/setup.py b/setup.py deleted file mode 100644 index 213b9db7..00000000 --- a/setup.py +++ /dev/null @@ -1,53 +0,0 @@ -import pathlib - -from setuptools import setup - - -def parse_requirements_file(fname): - requirements = list() - with open(fname, 'r') as fid: - for line in fid: - req = line.strip() - if req.startswith('#'): - continue - # strip end-of-line comments - req = req.split('#', maxsplit=1)[0].strip() - requirements.append(req) - return requirements - - -readme = (pathlib.Path(__file__).parent / "README.md").read_text() - -version = None -with open(pathlib.Path('mne_qt_browser') / '_version.py', 'r') as fid: - for line in (line.strip() for line in fid): - if line.startswith('__version__'): - version = line.split('=')[1].strip().strip('\'') - break -if version is None: - raise RuntimeError('Could not determine version') - -setup(name='mne-qt-browser', - version=version, - maintainer='Martin Schulz', - maintainer_email='dev@earthman-music.de', - description='A new backend based on pyqtgraph for the 2D-Data-Browser ' - 'in MNE-Python.', - long_description=readme, - long_description_content_type='text/markdown', - license='License :: OSI Approved :: BSD License', - url='https://github.com/mne-tools/mne-qt-browser', - download_url='https://github.com/mne-tools/mne-qt-browser/archive/refs' - f'/tags/v{version}.tar.gz', - project_urls={'Bug Tracker': - 'https://github.com/mne-tools/mne-qt-browser/issues'}, - classifiers=['Programming Language :: Python :: 3', - 'License :: OSI Approved :: BSD License', - 'Operating System :: OS Independent'], - packages=['mne_qt_browser'], - include_package_data=True, - install_requires=parse_requirements_file('requirements.txt'), - extras_require={ - 'opengl': ['pyopengl'], - }, - )