From 7f98c159537c13e5c433d8bef2952d8c9a3045e8 Mon Sep 17 00:00:00 2001 From: tieu-sys Date: Fri, 15 May 2026 12:27:17 +0200 Subject: [PATCH 1/4] fix(tests): always use virtual port in delete tests on macOS Opening a real port does not add to the port count, breaking the +1 assertion on macOS where system MIDI ports already exist --- .gitignore | 7 +++++++ tests/test_delete.py | 16 ++++++++-------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 50d68973..6d6c2d7f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,10 @@ # Python bytecode *.py[cod] __pycache__ +.python-version + +# UV +uv.lock # Cython output src/_rtmidi.cpp @@ -51,3 +55,6 @@ rtmidi/version.py # Geany project python-rtmidi.geany + +# Darwin +.DS_Store diff --git a/tests/test_delete.py b/tests/test_delete.py index 6542b84e..c59441c8 100644 --- a/tests/test_delete.py +++ b/tests/test_delete.py @@ -22,10 +22,10 @@ def test_midiin_delete(self): print("output ports initially:") print(ports_init) - if midiin_ports: - self.midiin.open_port(0) - else: - self.midiin.open_virtual_port("My virtual output") + # Always use a virtual port so a new port is guaranteed to appear in the list. + # Opening a real port does not add to the port count, which breaks the +1 assertion + # on macOS where system MIDI ports already exist. + self.midiin.open_virtual_port("My virtual output") ports_before = self.midiout.get_ports() @@ -50,10 +50,10 @@ def test_midiout_delete(self): print("Input ports initially:") print(ports_init) - if midiout_ports: - self.midiout.open_port(0) - else: - self.midiout.open_virtual_port("My virtual output") + # Always use a virtual port so a new port is guaranteed to appear in the list. + # Opening a real port does not add to the port count, which breaks the +1 assertion + # on macOS where system MIDI ports already exist. + self.midiout.open_virtual_port("My virtual output") ports_before = self.midiin.get_ports() From 3b25e586c821a9a633da9ae158c18b871e1ddd29 Mon Sep 17 00:00:00 2001 From: tieu-sys Date: Fri, 15 May 2026 13:54:35 +0200 Subject: [PATCH 2/4] fix: make UnsupportedOperationError a subclass of NotImplementedError --- src/_rtmidi.pyx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/_rtmidi.pyx b/src/_rtmidi.pyx index 00c9e5ca..7074dbb9 100644 --- a/src/_rtmidi.pyx +++ b/src/_rtmidi.pyx @@ -320,10 +320,11 @@ class NoDevicesError(SystemError): type = ERR_NO_DEVICES_FOUND -class UnsupportedOperationError(RtMidiError, RuntimeError): +class UnsupportedOperationError(RtMidiError, NotImplementedError): """Raised if a method is not supported by the low-level API. - Also derives from ``RuntimeError``. + Also derives from ``NotImplementedError`` (which itself is a subclass of + ``RuntimeError``), so existing code catching ``RuntimeError`` is unaffected. """ pass From 404bda8d7215a46eaad8e79a0623d492e2d5b12e Mon Sep 17 00:00:00 2001 From: tieu-sys Date: Fri, 15 May 2026 13:56:52 +0200 Subject: [PATCH 3/4] ci: add workflow_dispatch to allow manual build triggering --- .github/workflows/push_to_master.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/push_to_master.yml b/.github/workflows/push_to_master.yml index f7f0115f..1cda3dcd 100644 --- a/.github/workflows/push_to_master.yml +++ b/.github/workflows/push_to_master.yml @@ -4,6 +4,7 @@ on: push: branches: - master + workflow_dispatch: jobs: build_sdist: From dd90aa7834ee7a93e2a8b74d08038f5e9b0bef8e Mon Sep 17 00:00:00 2001 From: tieu-sys Date: Fri, 15 May 2026 14:02:25 +0200 Subject: [PATCH 4/4] ci: remove workflow_dispatch to allow manual build triggering --- .github/workflows/push_to_master.yml | 110 +++++++++++++-------------- 1 file changed, 53 insertions(+), 57 deletions(-) diff --git a/.github/workflows/push_to_master.yml b/.github/workflows/push_to_master.yml index 1cda3dcd..4b37d085 100644 --- a/.github/workflows/push_to_master.yml +++ b/.github/workflows/push_to_master.yml @@ -4,36 +4,34 @@ on: push: branches: - master - workflow_dispatch: jobs: build_sdist: name: Build sdist runs-on: ubuntu-latest steps: + - uses: actions/checkout@v4 + with: + submodules: true - - uses: actions/checkout@v4 - with: - submodules: true + - name: Install ninja + run: pipx install ninja - - name: Install ninja - run: pipx install ninja + - name: Install alsa deps + run: sudo apt-get install libasound2-dev - - name: Install alsa deps - run: sudo apt-get install libasound2-dev + - name: Build sdist + run: pipx run build --sdist - - name: Build sdist - run: pipx run build --sdist + - name: Check metadata + run: pipx run twine check --strict dist/* - - name: Check metadata - run: pipx run twine check --strict dist/* - - - name: Upload sdist - uses: actions/upload-artifact@v4 - with: - name: sdist - path: dist/*.tar.gz - compression-level: 0 + - name: Upload sdist + uses: actions/upload-artifact@v4 + with: + name: sdist + path: dist/*.tar.gz + compression-level: 0 build_wheels: name: Build wheels on ${{ matrix.os }} @@ -43,30 +41,29 @@ jobs: matrix: os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, macos-latest] steps: - - - uses: actions/checkout@v4 - with: - submodules: true - - - uses: ilammy/msvc-dev-cmd@v1 - if: matrix.os == 'windows-latest' - - - name: Build wheels - uses: pypa/cibuildwheel@v2.22 - env: - # Skip trying to test arm64 builds on Intel Macs - CIBW_TEST_SKIP: "*-macosx_arm64 *-macosx_universal2:arm64" - - - name: Verify clean directory - run: git diff --exit-code - shell: bash - - - name: Upload wheels - uses: actions/upload-artifact@v4 - with: - name: bdist-${{ matrix.os }} - path: wheelhouse/*.whl - compression-level: 0 + - uses: actions/checkout@v4 + with: + submodules: true + + - uses: ilammy/msvc-dev-cmd@v1 + if: matrix.os == 'windows-latest' + + - name: Build wheels + uses: pypa/cibuildwheel@v2.22 + env: + # Skip trying to test arm64 builds on Intel Macs + CIBW_TEST_SKIP: "*-macosx_arm64 *-macosx_universal2:arm64" + + - name: Verify clean directory + run: git diff --exit-code + shell: bash + + - name: Upload wheels + uses: actions/upload-artifact@v4 + with: + name: bdist-${{ matrix.os }} + path: wheelhouse/*.whl + compression-level: 0 upload_pypi: needs: [build_wheels, build_sdist] @@ -74,17 +71,16 @@ jobs: environment: PyPI release if: github.ref == 'refs/heads/develop' steps: - - - uses: actions/download-artifact@v4 - with: - path: dist - merge-multiple: true - - - name: Publish distribution to Test PyPI - uses: pypa/gh-action-pypi-publish@release/v1 - with: - skip_existing: true - user: __token__ - password: ${{ secrets.TEST_PYPI_API_TOKEN }} - repository_url: https://test.pypi.org/legacy/ - verify-metadata: false + - uses: actions/download-artifact@v4 + with: + path: dist + merge-multiple: true + + - name: Publish distribution to Test PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + skip_existing: true + user: __token__ + password: ${{ secrets.TEST_PYPI_API_TOKEN }} + repository_url: https://test.pypi.org/legacy/ + verify-metadata: false