diff --git a/.github/workflows/code.yml b/.github/workflows/code.yml new file mode 100644 index 00000000..b5b5b0bc --- /dev/null +++ b/.github/workflows/code.yml @@ -0,0 +1,111 @@ +name: Unit Tests & Code Coverage + +on: + # Triggers the workflow on push or pull request events but only for the main branch + push: + branches: + - main + pull_request: + branches: + - main + workflow_dispatch: # allow manual triggering + +defaults: + run: + shell: bash -l {0} + +jobs: + lint: + name: Code style + runs-on: ubuntu-latest + + steps: + - name: Checkout the repository + uses: actions/checkout@v4 + + # TODO: + # - uses: actions/setup-python@v5 + # with: + # python-version: "3.12" + + # - name: Run ruff + # uses: davidslusser/actions_python_ruff@v1.0.1 + # with: + # python_version: "3.12" + + tests: + name: Python ${{ matrix.python-version }} + runs-on: ubuntu-latest + needs: lint + strategy: + matrix: + python-version: + # - "3.13" # not yet + - "3.12" + - "3.11" + - "3.10" + - "3.9" + - "3.8" + max-parallel: 5 + env: + DISPLAY: ":99.0" + + steps: + - name: Checkout the repository + uses: actions/checkout@v4 + + - name: Set timezone + uses: szenius/set-timezone@v2.0 + with: + timezoneLinux: "America/Chicago" + + - name: Install OS libraries to test Linux PyQt apps + run: | + sudo apt update -y + sudo apt install -y \ + libxcb-icccm4 \ + libxcb-image0 \ + libxcb-keysyms1 \ + libxcb-randr0 \ + libxcb-render-util0 \ + libxcb-xinerama0 \ + libxcb-xfixes0 \ + libxkbcommon-x11-0 \ + x11-utils \ + xvfb + + - name: Create Python ${{ matrix.python-version }} environment + uses: mamba-org/setup-micromamba@v1 + with: + cache-environment: true + cache-environment-key: env-key-${{ matrix.python-version }} + condarc: | + channel-priority: flexible + environment-file: env.yml + environment-name: anaconda-test-env-py-${{ matrix.python-version }} + create-args: >- + coveralls + pytest + pytest-cov + pytest-qt + pytest-xvfb + python=${{ matrix.python-version }} + setuptools-scm + + - name: Initial diagnostics + run: | + micromamba info + micromamba list + conda config --show-sources + conda config --show + micromamba env list + printenv | sort + + - name: Install this package + shell: bash -l {0} + run: pip install --no-deps -e . + + - name: Run tests with pytest + shell: bash -l {0} + run: | + xvfb-run pytest -vvv . diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml new file mode 100644 index 00000000..0c225569 --- /dev/null +++ b/.github/workflows/pypi.yml @@ -0,0 +1,56 @@ +name: Publish Python 🐍 distributions 📦 to PyPI and TestPyPI + +on: + # Triggers the workflow on push events but only for the main branch + push: + branches: + - main + tags: + - "*" # all tags + +jobs: + pypi: + name: Build and publish Python 🐍 distributions 📦 to PyPI and TestPyPI + runs-on: ubuntu-latest + + steps: + - name: Checkout this project + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install pypa/build + run: >- + python -m + pip install + build + --user + - name: Build a binary wheel and a source tarball + run: >- + python -m + build + --sdist + --wheel + --outdir dist/ + . + + - name: Install twine + run: >- + python -m + pip install + twine + + - name: Check package metadata + run: >- + twine check dist/* + + - name: Publish distribution 📦 to PyPI + if: startsWith(github.ref, 'refs/tags') + uses: pypa/gh-action-pypi-publish@release/v1 + with: + user: __token__ + password: ${{ secrets.PYPI_API_TOKEN }} + verbose: true diff --git a/mdaviz/tests/__init__.py b/mdaviz/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/mdaviz/tests/test_aboutdialog.py b/mdaviz/tests/test_aboutdialog.py new file mode 100644 index 00000000..6b41e99e --- /dev/null +++ b/mdaviz/tests/test_aboutdialog.py @@ -0,0 +1,20 @@ +from PyQt5 import QtWidgets + +from .. import aboutdialog + + +def test_about_starts(qtbot): + """About dialog should start with no errors.""" + + class SetStatusWidget(QtWidgets.QWidget): + """Test class with setStatus() method.""" + + def setStatus(self, status): + pass + + fake_main_window = SetStatusWidget() + + dialog = aboutdialog.AboutDialog(fake_main_window) + qtbot.addWidget(dialog) + dialog.show() + assert dialog is not None diff --git a/mdaviz/tests/test_app.py b/mdaviz/tests/test_app.py new file mode 100644 index 00000000..4e51148e --- /dev/null +++ b/mdaviz/tests/test_app.py @@ -0,0 +1,26 @@ +from contextlib import nullcontext as does_not_raise + +# TODO: (below) from PyQt5 import QtWidgets + +from ..mainwindow import MainWindow + +# FIXME: gui starts and waits for user to close it +# def test_app(qtbot): +# """mdaviz app should start with no errors.""" +# from .. import app + +# gui = app.gui() +# assert gui is not None + + +def test_app_startup(qtbot): + """Repeat the steps here that start the GUI, don't wait for user.""" + with does_not_raise(): + # FIXME: dumps core + # app = QtWidgets.QApplication([]) + # assert app is not None + + main_window = MainWindow() + assert main_window is not None + # main_window.setStatus("Application started ...") + # main_window.show()