Repository: ComPWA/tensorwaves (language: python)

Issue:
ci: avoid callbacks if unspecified
Previously, if no callback was specified in the optimizer constructor, an empty CallbackList would be created and on_optimize_end etc were always called. This is (theoretically) slower.

Some other improvements:
- Use [`attrs` next-generation API](https://www.attrs.org/en/stable/api.html#next-gen) (see also https://github.com/ComPWA/compwa-org/issues/90).
- Avoid creating stream on creation of Loadable callback.
- Fail pytest on warnings (this helped fishing out the above bug)
ci: avoid callbacks if unspecified
Previously, if no callback was specified in the optimizer constructor, an empty CallbackList would be created and on_optimize_end etc were always called. This is (theoretically) slower.

Some other improvements:
- Use [`attrs` next-generation API](https://www.attrs.org/en/stable/api.html#next-gen) (see also https://github.com/ComPWA/compwa-org/issues/90).
- Avoid creating stream on creation of Loadable callback.
- Fail pytest on warnings (this helped fishing out the above bug)
fix: write callback output to separate files
Integration tests have become unstable since #349, see e.g. https://github.com/ComPWA/tensorwaves/actions/runs/1504632721, because the callback output is written to the same file when using `optimized_lambdify` / `_backend_lambdify`.


Discussion / hints:

Fix patch:
diff --git a/.constraints/py3.6.txt b/.constraints/py3.6.txt
index e0b017d2..13084fd3 100644
--- a/.constraints/py3.6.txt
+++ b/.constraints/py3.6.txt
@@ -124,7 +124,7 @@ nbconvert==6.0.7
 nbdime==3.1.1
 nbformat==5.1.3
 nbmake==1.0
-nest-asyncio==1.5.1
+nest-asyncio==1.5.4
 nodeenv==1.6.0
 notebook==6.4.6
 numba==0.53.1
diff --git a/.constraints/py3.7.txt b/.constraints/py3.7.txt
index 26db4abc..cee8537f 100644
--- a/.constraints/py3.7.txt
+++ b/.constraints/py3.7.txt
@@ -73,8 +73,8 @@ iminuit==2.8.4
 importlib-metadata==4.2.0
 importlib-resources==5.4.0
 iniconfig==1.1.1
-ipykernel==6.5.1
-ipython==7.30.0
+ipykernel==6.6.0
+ipython==7.30.1
 ipython-genutils==0.2.0
 ipywidgets==7.6.5
 isort==5.10.1
@@ -123,7 +123,7 @@ nbconvert==6.3.0
 nbdime==3.1.1
 nbformat==5.1.3
 nbmake==1.0
-nest-asyncio==1.5.1
+nest-asyncio==1.5.4
 nodeenv==1.6.0
 notebook==6.4.6
 numba==0.54.1
diff --git a/.constraints/py3.8.txt b/.constraints/py3.8.txt
index d8487725..eb284d35 100644
--- a/.constraints/py3.8.txt
+++ b/.constraints/py3.8.txt
@@ -72,8 +72,8 @@ iminuit==2.8.4
 importlib-metadata==4.8.2
 importlib-resources==5.4.0
 iniconfig==1.1.1
-ipykernel==6.5.1
-ipython==7.30.0
+ipykernel==6.6.0
+ipython==7.30.1
 ipython-genutils==0.2.0
 ipywidgets==7.6.5
 isort==5.10.1
@@ -122,7 +122,7 @@ nbconvert==6.3.0
 nbdime==3.1.1
 nbformat==5.1.3
 nbmake==1.0
-nest-asyncio==1.5.1
+nest-asyncio==1.5.4
 nodeenv==1.6.0
 notebook==6.4.6
 numba==0.54.1
diff --git a/.constraints/py3.9.txt b/.constraints/py3.9.txt
index 58bb28e2..513983a5 100644
--- a/.constraints/py3.9.txt
+++ b/.constraints/py3.9.txt
@@ -71,8 +71,8 @@ imagesize==1.3.0
 iminuit==2.8.4
 importlib-metadata==4.8.2
 iniconfig==1.1.1
-ipykernel==6.5.1
-ipython==7.30.0
+ipykernel==6.6.0
+ipython==7.30.1
 ipython-genutils==0.2.0
 ipywidgets==7.6.5
 isort==5.10.1
@@ -121,7 +121,7 @@ nbconvert==6.3.0
 nbdime==3.1.1
 nbformat==5.1.3
 nbmake==1.0
-nest-asyncio==1.5.1
+nest-asyncio==1.5.4
 nodeenv==1.6.0
 notebook==6.4.6
 numba==0.54.1
diff --git a/.cspell.json b/.cspell.json
index ae2abf9b..df06cc11 100644
--- a/.cspell.json
+++ b/.cspell.json
@@ -121,6 +121,7 @@
         "autoupdate",
         "axhline",
         "axvline",
+        "bdist",
         "cano",
         "celltoolbar",
         "cmin",
@@ -187,6 +188,7 @@
         "phsp",
         "precommit",
         "prefactor",
+        "prereleased",
         "pwa's",
         "py's",
         "pygments",
@@ -199,6 +201,7 @@
         "rightarrow",
         "rtfd",
         "scipy",
+        "sdist",
         "seealso",
         "sharex",
         "sharey",
diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml
index b0864a5f..54338422 100644
--- a/.github/workflows/cd.yml
+++ b/.github/workflows/cd.yml
@@ -1,5 +1,3 @@
-# cspell:ignore bdist noreply prereleased sdist
-
 name: CD
 
 on:
@@ -10,16 +8,27 @@ on:
 
 jobs:
   push:
-    name: Push to stable branch
+    name: Push to version branches
     if: startsWith(github.ref, 'refs/tags')
     runs-on: ubuntu-20.04
     steps:
       - uses: actions/checkout@master
-      - name: Push to stable branch
+      - name: Configure Git credentials
         run: |
           git config --global user.name "GitHub Action"
           git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
-          git push origin HEAD:refs/heads/stable -f
+      - name: Push to stable branch
+        run: |
+          git push origin HEAD:refs/heads/stable
+      - name: Push to matching minor version branch
+        env:
+          TAG: ${{ github.ref_name }}
+        run: |
+          re='^([0-9]+)\.([0-9]+)\.[0-9]+'
+          if [[ $TAG =~ $re ]]; then
+            MINOR_VERSION_BRANCH="${BASH_REMATCH[1]}.${BASH_REMATCH[2]}.x"
+            git push origin HEAD:refs/heads/$MINOR_VERSION_BRANCH
+          fi
 
   pypi:
     name: Publish to PyPI
@@ -31,7 +40,7 @@ jobs:
       - name: Set up Python
         uses: actions/setup-python@v2
         with:
-          python-version: 3.8
+          python-version: "3.8"
       - name: Install dependencies
         run: |
           python -m pip install --upgrade pip
diff --git a/.github/workflows/requirements-pr.yml b/.github/workflows/requirements-pr.yml
index f768ea7c..ba72e003 100644
--- a/.github/workflows/requirements-pr.yml
+++ b/.github/workflows/requirements-pr.yml
@@ -7,8 +7,30 @@ on:
       - epic/*
 
 jobs:
+  diff:
+    name: Check dependency changes
+    if: github.event.pull_request.head.repo.full_name == github.repository
+    runs-on: ubuntu-20.04
+    steps:
+      - uses: actions/checkout@v2
+        with:
+          fetch-depth: 0
+      - name: Determine dependency changes
+        run: |
+          DIFF="$(git diff origin/main --color -- .constraints .pre-commit-config.yaml setup.cfg)"
+          echo ::set-output name=diff::"${DIFF}"
+        id: diff
+    outputs:
+      diff: ${{ steps.diff.outputs.diff }}
+
   pip-constraints:
-    name: Update pip constraints files
+    name: Update pip constraints
+    needs: diff
+    if: >
+      github.event.pull_request.head.repo.full_name == github.repository &&
+      needs.diff.outputs.diff != ''
+    # Only run if PR does not come from a fork
+    # https://docs.github.com/en/actions/security-guides/encrypted-secrets#using-encrypted-secrets-in-a-workflow
     runs-on: ubuntu-20.04
     strategy:
       fail-fast: false
@@ -20,40 +42,29 @@ jobs:
           - "3.9"
     steps:
       - uses: actions/checkout@v2
-        with:
-          fetch-depth: 0
-      - name: Check if there are dependency changes
-        run: |
-          DIFF="$(git diff origin/main --color -- .constraints setup.cfg)"
-          echo ::set-output name=diff::"${DIFF}"
-        id: diff
       - uses: ComPWA/update-pip-constraints@main
-        if: steps.diff.outputs.diff != ''
         with:
           python-version: ${{ matrix.python-version }}
 
   pre-commit:
     name: pre-commit autoupdate
+    needs: diff
+    if: >
+      github.event.pull_request.head.repo.full_name == github.repository &&
+      needs.diff.outputs.diff != ''
     runs-on: ubuntu-20.04
     steps:
       - uses: actions/checkout@v2
-        with:
-          fetch-depth: 0
-      - name: Check if there are changes to pre-commit config
-        run: |
-          DIFF="$(git diff origin/main --color -- .pre-commit-config.yaml)"
-          echo ::set-output name=diff::"${DIFF}"
-        id: diff
       - uses: ComPWA/update-pre-commit@main
-        if: steps.diff.outputs.diff != ''
 
   push:
     name: Push changes
-    if: github.event.pull_request.head.repo.full_name == github.repository
-    # Only run if PR does not come from a fork
-    # https://docs.github.com/en/actions/security-guides/encrypted-secrets#using-encrypted-secrets-in-a-workflow
+    if: >
+      github.event.pull_request.head.repo.full_name == github.repository &&
+      needs.diff.outputs.diff != ''
     runs-on: ubuntu-20.04
     needs:
+      - diff
       - pip-constraints
       - pre-commit
     steps:
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index ff29beba..27df9441 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -40,7 +40,7 @@ repos:
       - id: trailing-whitespace
 
   - repo: https://github.com/ComPWA/repo-maintenance
-    rev: 0.0.89
+    rev: 0.0.92
     hooks:
       - id: check-dev-files
         args:
@@ -63,7 +63,7 @@ repos:
       - id: blacken-docs
 
   - repo: https://github.com/streetsidesoftware/cspell-cli
-    rev: v5.6.10
+    rev: v5.6.11
     hooks:
       - id: cspell
 
@@ -126,7 +126,7 @@ repos:
       - id: pydocstyle
 
   - repo: https://github.com/ComPWA/mirrors-pyright
-    rev: v1.1.190
+    rev: v1.1.191
     hooks:
       - id: pyright
 
diff --git a/tox.ini b/tox.ini
index 14ed3f81..83b8f9db 100644
--- a/tox.ini
+++ b/tox.ini
@@ -129,7 +129,7 @@ commands =
         --cov-report=xml \
         --cov=tensorwaves
 
-[testenv:testnb]
+[testenv:nb]
 description =
     Run all notebooks with pytest
 allowlist_externals =


Test patch:
diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml
index a877d96d..9f0f7a0d 100644
--- a/.github/workflows/ci-tests.yml
+++ b/.github/workflows/ci-tests.yml
@@ -17,7 +17,7 @@ jobs:
     strategy:
       matrix:
         os: [ubuntu-20.04]
-        python-version: [3.7]
+        python-version: ["3.7"]
     steps:
       - uses: actions/checkout@master
       - name: Set up Python ${{ matrix.python-version }}
@@ -46,40 +46,17 @@ jobs:
     name: Unit tests
     runs-on: ${{ matrix.os }}
     strategy:
+      fail-fast: false
       matrix:
         os:
           - ubuntu-20.04
-        python-version: [3.6, 3.7, 3.8, 3.9]
+        python-version: ["3.6", "3.7", "3.8", "3.9"]
         exclude:
           - os: ubuntu-20.04 # coverage job
-            python-version: 3.7
-    steps:
-      - uses: actions/checkout@v2
-      - name: Set up Python ${{ matrix.python-version }}
-        uses: actions/setup-python@v2
-        with:
-          python-version: ${{ matrix.python-version }}
-      - name: Install dependencies
-        run: |
-          python -m pip install --upgrade pip
-          pip install -c .constraints/py${{ matrix.python-version }}.txt -e .[test]
-      - name: Run unit tests and doctests with pytest
-        env:
-          CUDA_VISIBLE_DEVICES: "-1"
-        run: pytest -n auto
-      - uses: actions/upload-artifact@v2
-        if: ${{ always() }}
-        with:
-          name: test_output_${{ matrix.os }}_${{ matrix.python-version }}
-          path: tests/output
-
-  pytest-macos:
-    name: Unit tests (MacOS)
-    runs-on: ${{ matrix.os }}
-    strategy:
-      matrix:
-        os: [macos-11]
-        python-version: [3.7]
+            python-version: "3.7"
+        include:
+          - os: macos-11
+            python-version: "3.7"
     steps:
       - uses: actions/checkout@v2
       - name: Set up Python ${{ matrix.python-version }}
diff --git a/pytest.ini b/pytest.ini
index 63964cc4..bc152f43 100644
--- a/pytest.ini
+++ b/pytest.ini
@@ -17,6 +17,7 @@ filterwarnings =
     ignore:Passing a schema to Validator.iter_errors is deprecated.*:DeprecationWarning
     ignore:invalid value encountered in log.*:RuntimeWarning
     ignore:invalid value encountered in sqrt:RuntimeWarning
+    ignore:numpy.ufunc size changed, may indicate binary incompatibility.*:RuntimeWarning
 norecursedirs =
     _build
 markers =