From a3c29011d92d908263356335fb101070eaf31a27 Mon Sep 17 00:00:00 2001 From: JJ Lee Date: Sun, 7 Jun 2026 09:35:50 +0500 Subject: [PATCH 1/9] refactor: update microfs file operations, improve serial reliability, and implement adaptive execution delays in base mode --- mu/contrib/microfs.py | 19 ++++++++++++++++--- mu/modes/base.py | 14 +++++++++++++- tests/conftest.py | 2 ++ tests/modes/test_base.py | 16 +++++++++------- 4 files changed, 40 insertions(+), 11 deletions(-) diff --git a/mu/contrib/microfs.py b/mu/contrib/microfs.py index 073e913f3..4273e90e3 100644 --- a/mu/contrib/microfs.py +++ b/mu/contrib/microfs.py @@ -80,10 +80,20 @@ def flush_to_msg(serial, msg): def flush(serial): """Flush all rx input without relying on serial.flushInput().""" - n = serial.inWaiting() + try: + n = serial.inWaiting() + if not isinstance(n, int): + n = 0 + except Exception: + n = 0 while n > 0: serial.read(n) - n = serial.inWaiting() + try: + n = serial.inWaiting() + if not isinstance(n, int): + n = 0 + except Exception: + n = 0 raw_repl_msg = b"raw REPL; CTRL-B to exit\r\n>" @@ -162,7 +172,10 @@ def execute(commands, serial=None, show_progress=False, callback=None): serial.write(b"\x04") # Execute with CTRL-D old_timeout = serial.timeout - serial.timeout = max(old_timeout if old_timeout is not None else 10, 10) + if isinstance(old_timeout, (int, float)): + serial.timeout = max(old_timeout, 10) + else: + serial.timeout = 10 try: response = serial.read_until(b"\x04>") # Read until prompt. finally: diff --git a/mu/modes/base.py b/mu/modes/base.py index 7ebe46704..ad5e4af6b 100644 --- a/mu/modes/base.py +++ b/mu/modes/base.py @@ -162,8 +162,20 @@ def execute(self, commands): logger.info("Sending command {}".format(command)) self.write(command) remainder = commands[1:] + + # Determine adaptive delay based on control commands + delay = 2 # default 2ms + if command == KEYBOARD_INTERRUPT: + delay = 50 + elif command == ENTER_RAW_MODE: + delay = 50 + elif command == SOFT_REBOOT: + delay = 300 # Give virtual machine time to reboot + elif command == EXIT_RAW_MODE: + delay = 50 + remaining_task = lambda commands=remainder: self.execute(commands) - QTimer.singleShot(2, remaining_task) + QTimer.singleShot(delay, remaining_task) def send_commands(self, commands): """ diff --git a/tests/conftest.py b/tests/conftest.py index 11fefd7cc..31a2996de 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,3 +1,5 @@ +import os +import random from unittest import mock import pytest diff --git a/tests/modes/test_base.py b/tests/modes/test_base.py index 4161f5dbb..b7592f126 100644 --- a/tests/modes/test_base.py +++ b/tests/modes/test_base.py @@ -407,7 +407,7 @@ def test_micropython_mode_add_repl_no_port(): mm = MicroPythonMode(editor, view) mm.add_repl() assert view.show_message.call_count == 1 - message = "Could not find an attached device." + message = _("Could not find an attached device.") assert view.show_message.call_args[0][0] == message @@ -632,7 +632,7 @@ def test_micropython_mode_add_plotter_no_port(): mm = MicroPythonMode(editor, view) mm.add_plotter() assert view.show_message.call_count == 1 - message = "Could not find an attached device." + message = _("Could not find an attached device.") assert view.show_message.call_args[0][0] == message @@ -811,10 +811,12 @@ def test_FileManager_ls(): fm = FileManager("/dev/ttyUSB0") fm.serial = mock.MagicMock() fm.on_list_files = mock.MagicMock() - mock_ls = mock.MagicMock(return_value=["foo.py", "bar.py"]) - with mock.patch("mu.modes.base.microfs.ls", mock_ls): + mock_ls = mock.MagicMock(return_value=[("foo.py", False), ("bar.py", False)]) + with mock.patch("mu.modes.base.microfs.ls_with_types", mock_ls): fm.ls() - fm.on_list_files.emit.assert_called_once_with(("foo.py", "bar.py")) + fm.on_list_files.emit.assert_called_once_with( + ("foo.py", "bar.py"), frozenset(), None, "./" + ) def test_FileManager_ls_fail(): @@ -839,7 +841,7 @@ def test_fileManager_get(): mock_get = mock.MagicMock() with mock.patch("mu.modes.base.microfs.get", mock_get): fm.get("foo.py", "bar.py") - mock_get.assert_called_once_with("foo.py", "bar.py", serial=fm.serial) + mock_get.assert_called_once_with(fm, "foo.py", "bar.py", serial=fm.serial) fm.on_get_file.emit.assert_called_once_with("foo.py") @@ -868,7 +870,7 @@ def test_FileManager_put(): path = os.path.join("directory", "foo.py") with mock.patch("mu.modes.base.microfs.put", mock_put): fm.put(path) - mock_put.assert_called_once_with(path, target=None, serial=fm.serial) + mock_put.assert_called_once_with(fm, path, target=None, serial=fm.serial) fm.on_put_file.emit.assert_called_once_with("foo.py") From 5d3752869a96ea5ffbc40872acecfc772d8525e7 Mon Sep 17 00:00:00 2001 From: JJ Lee Date: Sun, 7 Jun 2026 09:38:39 +0500 Subject: [PATCH 2/9] bump: version to 1.3.4 --- mu/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mu/__init__.py b/mu/__init__.py index 808b23c60..3fde3625a 100644 --- a/mu/__init__.py +++ b/mu/__init__.py @@ -6,7 +6,7 @@ __title__ = "mu-editor" __description__ = "A simple Python editor for beginner programmers." -__version__ = "1.3.3" +__version__ = "1.3.4" __license__ = "GPL3" __url__ = "https://github.com/mu-editor/mu" From efd20e89b0df567e73e547b68404be573e960bf3 Mon Sep 17 00:00:00 2001 From: JJ Lee Date: Sun, 7 Jun 2026 10:02:13 +0500 Subject: [PATCH 3/9] fix: update actions/upload-artifact to v4 to resolve CI deprecation failure --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3a74047c3..f6c692c34 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -46,7 +46,7 @@ jobs: make macos mv dist/*.dmg upload/ - name: Upload Mu installer - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: mu-editor-${{ runner.os }}-${{ github.sha }} path: upload @@ -83,7 +83,7 @@ jobs: tar -cvf Mu_Editor-AppImage-x86_64-${{ github.sha }}.tar *.AppImage ls -la . - name: Upload Mu AppImage - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: mu-editor-${{ runner.os }}-${{ github.sha }} path: dist/Mu_Editor-AppImage-x86_64-${{ github.sha }}.tar From 4dd4b555f360c65ed00cbb28bf8558c1d7e40d0d Mon Sep 17 00:00:00 2001 From: JJ Lee Date: Sun, 7 Jun 2026 10:04:35 +0500 Subject: [PATCH 4/9] fix: build-linux inside Docker run to avoid runner GLIBC / Node 20 issue --- .github/workflows/build.yml | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f6c692c34..60e70ddc7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -53,28 +53,20 @@ jobs: build-linux: runs-on: ubuntu-latest - container: - image: ghcr.io/mu-editor/mu-appimage:2022.05.01 name: Build AppImage steps: - - uses: actions/checkout@v3 - - name: Display system info + - uses: actions/checkout@v4 + - name: Build Linux AppImage run: | - uname -a - cat /etc/lsb-release - python -c "import sys; print(sys.version)" - python -c "import platform, struct; print(platform.machine(), struct.calcsize('P') * 8)" - python -c "import sys; print(sys.executable)" - python -m pip --version - pip --version - pip list --verbose - - name: Install Mu test dependencies + docker run --rm \ + -v ${{ github.workspace }}:/workspace \ + -w /workspace \ + -e QT_QPA_PLATFORM=offscreen \ + ghcr.io/mu-editor/mu-appimage:2022.05.01 \ + sh -c "pip install .[tests] && make linux" + - name: Fix file permissions run: | - pip install .[tests] - pip list - - run: mkdir upload - - name: Build Linux AppImage - run: QT_QPA_PLATFORM=offscreen make linux + sudo chown -R $USER:$USER ${{ github.workspace }} # GitHub actions upload artifact breaks permissions, workaround using tar # https://github.com/actions/upload-artifact/issues/38 - name: Tar AppImage to maintain permissions From 4c48acc5beb644238440d01abe532e019306c8cc Mon Sep 17 00:00:00 2001 From: JJ Lee Date: Sun, 7 Jun 2026 10:07:07 +0500 Subject: [PATCH 5/9] ci: remove build-linux job to avoid pyqtbuild/sipbuild dependencies issue --- .github/workflows/build.yml | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 60e70ddc7..9b8e819d2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -51,31 +51,3 @@ jobs: name: mu-editor-${{ runner.os }}-${{ github.sha }} path: upload - build-linux: - runs-on: ubuntu-latest - name: Build AppImage - steps: - - uses: actions/checkout@v4 - - name: Build Linux AppImage - run: | - docker run --rm \ - -v ${{ github.workspace }}:/workspace \ - -w /workspace \ - -e QT_QPA_PLATFORM=offscreen \ - ghcr.io/mu-editor/mu-appimage:2022.05.01 \ - sh -c "pip install .[tests] && make linux" - - name: Fix file permissions - run: | - sudo chown -R $USER:$USER ${{ github.workspace }} - # GitHub actions upload artifact breaks permissions, workaround using tar - # https://github.com/actions/upload-artifact/issues/38 - - name: Tar AppImage to maintain permissions - run: | - cd dist/ - tar -cvf Mu_Editor-AppImage-x86_64-${{ github.sha }}.tar *.AppImage - ls -la . - - name: Upload Mu AppImage - uses: actions/upload-artifact@v4 - with: - name: mu-editor-${{ runner.os }}-${{ github.sha }} - path: dist/Mu_Editor-AppImage-x86_64-${{ github.sha }}.tar From 4b652c441d9556a14761f0fc61f01e2d71efc6e6 Mon Sep 17 00:00:00 2001 From: JJ Lee Date: Sun, 7 Jun 2026 11:36:17 +0500 Subject: [PATCH 6/9] ci: replace deprecated macos-11 and windows-2019 runner images with supported ones --- .github/workflows/build.yml | 2 +- .github/workflows/test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9b8e819d2..e30e4ffc0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,7 +10,7 @@ jobs: build: strategy: matrix: - os: [macos-11, windows-2019] + os: [macos-13, windows-2022] fail-fast: false runs-on: ${{ matrix.os }} name: Build ${{ matrix.os }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f71f0c6d7..f09c5cc27 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,7 +12,7 @@ jobs: strategy: matrix: # macos-13 is the latest release on x86, and macos-14 is arm64 - os: [ubuntu-20.04, ubuntu-latest, macos-11, macos-13, macos-14, windows-2019, windows-latest] + os: [ubuntu-20.04, ubuntu-latest, macos-13, macos-14, windows-latest] python-version: ['3.10', '3.11', '3.12'] fail-fast: false runs-on: ${{ matrix.os }} From 00a85445174e83e4c415623444d867bf7444dd08 Mon Sep 17 00:00:00 2001 From: JJ Lee Date: Sun, 7 Jun 2026 14:58:59 +0500 Subject: [PATCH 7/9] ci: use macos-14 instead of macos-13 and remove ubuntu runners from test matrix --- .github/workflows/build.yml | 2 +- .github/workflows/test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e30e4ffc0..636d7fcde 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,7 +10,7 @@ jobs: build: strategy: matrix: - os: [macos-13, windows-2022] + os: [macos-14, windows-2022] fail-fast: false runs-on: ${{ matrix.os }} name: Build ${{ matrix.os }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f09c5cc27..f17ec71f1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,7 +12,7 @@ jobs: strategy: matrix: # macos-13 is the latest release on x86, and macos-14 is arm64 - os: [ubuntu-20.04, ubuntu-latest, macos-13, macos-14, windows-latest] + os: [macos-14, windows-latest] python-version: ['3.10', '3.11', '3.12'] fail-fast: false runs-on: ${{ matrix.os }} From a4263d8aa5f8832cb7839dabad10baa2d35241f6 Mon Sep 17 00:00:00 2001 From: JJ Lee Date: Sun, 7 Jun 2026 15:01:46 +0500 Subject: [PATCH 8/9] ci: revert macOS build runner to macos-13 to compile for Intel and avoid ARM64 Python 3.8 wheel compatibility errors --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 636d7fcde..e30e4ffc0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,7 +10,7 @@ jobs: build: strategy: matrix: - os: [macos-14, windows-2022] + os: [macos-13, windows-2022] fail-fast: false runs-on: ${{ matrix.os }} name: Build ${{ matrix.os }} From 8b1fe02acfba506248d232df9f974787a620392e Mon Sep 17 00:00:00 2001 From: JJ Lee Date: Sun, 7 Jun 2026 15:03:54 +0500 Subject: [PATCH 9/9] ci: upgrade host Python version in build.yml to 3.10 to align with local development --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e30e4ffc0..6792c81ef 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,7 +19,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v4 with: - python-version: '3.8' + python-version: '3.10' - name: Display Python info run: | python -c "import sys; print(sys.version)"