From 893c5140bdb283b4b16628fdfa244e6fcf6b0d15 Mon Sep 17 00:00:00 2001 From: Brad Barnett <127794626+bdbarnett@users.noreply.github.com> Date: Tue, 3 Nov 2026 16:18:47 -0600 Subject: [PATCH 1/2] Docstrings: Google sections and single-backtick cross-references --- cli/src/mpftp/__init__.py | 4 ++-- cli/src/mpftp/ble.py | 4 ++-- cli/src/mpftp/cli.py | 4 ++-- cli/src/mpftp/config.py | 4 ++-- cli/src/mpftp/espusb.py | 4 ++-- cli/src/mpftp/panel.py | 2 +- cli/src/mpftp/sidecar.py | 4 ++-- cli/src/mpftp/uf2.py | 2 +- cli/src/mpftp/webrepl.py | 4 ++-- 9 files changed, 16 insertions(+), 16 deletions(-) diff --git a/cli/src/mpftp/__init__.py b/cli/src/mpftp/__init__.py index 11d5239..9378f63 100644 --- a/cli/src/mpftp/__init__.py +++ b/cli/src/mpftp/__init__.py @@ -1,8 +1,8 @@ """mpftp — MicroPython and CircuitPython board tools. Importing this package has no side effects: nothing is spawned, no socket is -opened, and no file is written. Entry points live in :mod:`mpftp.cli`, -:mod:`mpftp.sidecar` and :mod:`mpftp.firmware`. +opened, and no file is written. Entry points live in `mpftp.cli`, +`mpftp.sidecar` and `mpftp.firmware`. """ from __future__ import annotations diff --git a/cli/src/mpftp/ble.py b/cli/src/mpftp/ble.py index f77e42b..028fc5e 100644 --- a/cli/src/mpftp/ble.py +++ b/cli/src/mpftp/ble.py @@ -2,8 +2,8 @@ The board runs ``bledev.repl`` (pydevices' ``bledev`` package), which serves the REPL over the Nordic UART service behind a password, the way WebREPL does -over Wi-Fi. :class:`BleSerial` dresses that link up as a pyserial port and -:func:`open_transport` hands it to mpremote's ``SerialTransport``, so exec, +over Wi-Fi. `BleSerial` dresses that link up as a pyserial port and +`open_transport` hands it to mpremote's ``SerialTransport``, so exec, raw REPL, interrupt and every ``fs_*`` operation work unchanged. When the board also serves files (``bledev.filetransfer``, CircuitPython's BLE diff --git a/cli/src/mpftp/cli.py b/cli/src/mpftp/cli.py index 3ff94a3..8892dc0 100755 --- a/cli/src/mpftp/cli.py +++ b/cli/src/mpftp/cli.py @@ -167,7 +167,7 @@ def _die(msg: str, code: int = 1) -> None: def find_rpc_entry() -> Optional[dict[str, Any]]: """Full registry entry for the live extension RPC, if any. - Same preference order as :func:`find_rpc_addr`, but keeps whatever + Same preference order as `find_rpc_addr`, but keeps whatever diagnostic fields (``editor``, ``pid``, ``updatedAt``) came with it — `find_rpc_addr` throws those away, which is fine for connecting but not for telling a caller *whose* session they resolved to (mpftp#21). @@ -273,7 +273,7 @@ def stream_debug_tee( (re)appear, and ``duration`` counts from the last time it opened (each ``debug_tee_open`` notify; ``hard-reset --monitor``, mpftp#60). - Unlike :meth:`call` + ``debug_tee_start`` (which stops the moment the + Unlike `call` + ``debug_tee_start`` (which stops the moment the CLI returns and closes the private sidecar, so the tee died with it), this keeps the session alive so the sidecar's tee loop keeps writing ``log_path`` and emitting ``debug_tee_data`` the whole time. diff --git a/cli/src/mpftp/config.py b/cli/src/mpftp/config.py index 358e63e..9d07033 100644 --- a/cli/src/mpftp/config.py +++ b/cli/src/mpftp/config.py @@ -13,7 +13,7 @@ 5. The built-in default Layers 1 and 2 belong to the caller: pass what you were given to -:func:`resolve` as ``override``, and this module supplies the rest. +`resolve` as ``override``, and this module supplies the rest. """ from __future__ import annotations @@ -190,7 +190,7 @@ def update(patch: dict[str, Any]) -> dict[str, Any]: """Merge ``patch`` into the file and return the stored result. Only the file layer is touched; environment and defaults are not persisted, - so writing back what :func:`load` returned would not bake them in. + so writing back what `load` returned would not bake them in. """ stored = validate(read_file()) for name, value in patch.items(): diff --git a/cli/src/mpftp/espusb.py b/cli/src/mpftp/espusb.py index a579145..1c57748 100644 --- a/cli/src/mpftp/espusb.py +++ b/cli/src/mpftp/espusb.py @@ -18,9 +18,9 @@ ``Get-PnpDevice | Restart-PnpDevice``, and there is no ``Restart-PnpDevice`` in Windows PowerShell -- so it failed on every device, reported LastTaskResult 1, and was indistinguishable from a board that refused to come back. That cost a -night's unattended flashing. :func:`task_state` exists so a caller can tell +night's unattended flashing. `task_state` exists so a caller can tell "the recovery is not installed" from "the board did not make it", and -:func:`recovery_available` is the one-line question to ask first. +`recovery_available` is the one-line question to ask first. """ from __future__ import annotations diff --git a/cli/src/mpftp/panel.py b/cli/src/mpftp/panel.py index 688b60e..d9dda99 100644 --- a/cli/src/mpftp/panel.py +++ b/cli/src/mpftp/panel.py @@ -4,7 +4,7 @@ (``extension/media/ftp.js``). That script talks to its host with ``postMessage({type: ...})`` and redraws from the ``state`` and ``status`` messages it gets back. In VS Code the host is ``FtpViewProvider.ts``; here it -is :class:`PanelHost`, a port of that class's message handling, so the two +is `PanelHost`, a port of that class's message handling, so the two hosts behave the same way: * board operations go to the shared sidecar (``SidecarRelay.request``); diff --git a/cli/src/mpftp/sidecar.py b/cli/src/mpftp/sidecar.py index 459fa9e..e507edb 100644 --- a/cli/src/mpftp/sidecar.py +++ b/cli/src/mpftp/sidecar.py @@ -372,7 +372,7 @@ def exec_follow( Streams the board's bytes through mpremote's ``data_consumer`` hook rather than letting ``follow`` accumulate them in a local its timeout discards; a - timeout then raises :class:`FollowTimeoutError` carrying the partial text. + timeout then raises `FollowTimeoutError` carrying the partial text. ``timeout`` is how long the script may print nothing before the follow gives up; ``None`` waits until it ends. mpremote's ``exec`` has no way to @@ -4626,7 +4626,7 @@ def debug_tee_start( catches the boot banner. ``dtr`` raises DTR (RTS stays low) for a native TinyUSB CDC port, - which sends nothing without it; see :func:`console_wants_dtr`. + which sends nothing without it; see `console_wants_dtr`. """ import time diff --git a/cli/src/mpftp/uf2.py b/cli/src/mpftp/uf2.py index 7850b3f..b197c49 100644 --- a/cli/src/mpftp/uf2.py +++ b/cli/src/mpftp/uf2.py @@ -152,7 +152,7 @@ def parse_uf2(path: Path, max_blocks: int = 0) -> dict: Returns ``{"blocks", "families", "family_names", "payload_bytes", "target_start", "target_end", "warnings"}``. - Raises :class:`Uf2Error` for anything structurally wrong -- a truncated + Raises `Uf2Error` for anything structurally wrong -- a truncated file, bad magic, or a block count that disagrees with the header. Checking this up front matters because the bootloader's response to a bad image is to ignore it in silence, which is indistinguishable from a failed copy. diff --git a/cli/src/mpftp/webrepl.py b/cli/src/mpftp/webrepl.py index b9ece1e..5c80fbf 100644 --- a/cli/src/mpftp/webrepl.py +++ b/cli/src/mpftp/webrepl.py @@ -2,8 +2,8 @@ A WebREPL session is a WebSocket whose text frames carry the REPL's byte stream (``extmod/modwebrepl.c`` hands them to ``os.dupterm``). That is the -same stream a USB serial port carries, so :class:`WebSocketSerial` dresses the -socket up as a pyserial port and :func:`open_transport` hands it to mpremote's +same stream a USB serial port carries, so `WebSocketSerial` dresses the +socket up as a pyserial port and `open_transport` hands it to mpremote's ``SerialTransport``. Raw REPL, raw-paste, exec and every ``fs_*`` operation then work unchanged. The design is described in ``docs/how-it-works/wifi-and-bluetooth.md``. From 4137e5072ef08907a848073199120f28c3ca3337 Mon Sep 17 00:00:00 2001 From: Brad Barnett <127794626+bdbarnett@users.noreply.github.com> Date: Tue, 3 Nov 2026 16:18:48 -0600 Subject: [PATCH 2/2] Licence headers on every Python file --- cli/src/mpftp/__init__.py | 4 ++++ cli/src/mpftp/__main__.py | 4 ++++ cli/src/mpftp/ble.py | 4 ++++ cli/src/mpftp/boards.py | 4 ++++ cli/src/mpftp/cli.py | 4 ++++ cli/src/mpftp/config.py | 4 ++++ cli/src/mpftp/conpty.py | 4 ++++ cli/src/mpftp/desktop_host.py | 4 ++++ cli/src/mpftp/emu.py | 4 ++++ cli/src/mpftp/espusb.py | 4 ++++ cli/src/mpftp/firmware.py | 4 ++++ cli/src/mpftp/firmware_build.py | 4 ++++ cli/src/mpftp/firmware_download.py | 4 ++++ cli/src/mpftp/hold.py | 4 ++++ cli/src/mpftp/mdns.py | 4 ++++ cli/src/mpftp/package_search.py | 4 ++++ cli/src/mpftp/panel.py | 4 ++++ cli/src/mpftp/parentwatch.py | 4 ++++ cli/src/mpftp/pwa.py | 4 ++++ cli/src/mpftp/rawpaste.py | 4 ++++ cli/src/mpftp/sidecar.py | 4 ++++ cli/src/mpftp/uf2.py | 4 ++++ cli/src/mpftp/webflash.py | 4 ++++ cli/src/mpftp/webrepl.py | 4 ++++ cli/src/mpftp/wifiboard.py | 4 ++++ cli/tests/fake_circuitpython.py | 4 ++++ cli/tests/test_app_image_offset.py | 4 ++++ cli/tests/test_binary_roundtrip.py | 4 ++++ cli/tests/test_ble.py | 4 ++++ cli/tests/test_circuitpy_drive_match.py | 4 ++++ cli/tests/test_circuitpython.py | 4 ++++ cli/tests/test_clean.py | 4 ++++ cli/tests/test_config.py | 4 ++++ cli/tests/test_connect_deadline.py | 4 ++++ cli/tests/test_cp_connect_time.py | 4 ++++ cli/tests/test_detect.py | 4 ++++ cli/tests/test_discovery.py | 4 ++++ cli/tests/test_dunder_main.py | 4 ++++ cli/tests/test_engine_python.py | 4 ++++ cli/tests/test_error_envelope.py | 4 ++++ cli/tests/test_esp_usb_restart.py | 4 ++++ cli/tests/test_firmware_build.py | 4 ++++ cli/tests/test_firmware_download.py | 4 ++++ cli/tests/test_follow_timeout.py | 4 ++++ cli/tests/test_hash_file.py | 4 ++++ cli/tests/test_helpers.py | 4 ++++ cli/tests/test_hold.py | 4 ++++ cli/tests/test_idf_version.py | 4 ++++ cli/tests/test_list_ports.py | 4 ++++ cli/tests/test_mip.py | 4 ++++ cli/tests/test_monitor_capture.py | 4 ++++ cli/tests/test_mpy_compile.py | 4 ++++ cli/tests/test_package_search.py | 4 ++++ cli/tests/test_panel.py | 4 ++++ cli/tests/test_parentwatch.py | 4 ++++ cli/tests/test_partition_table.py | 4 ++++ cli/tests/test_probe.py | 4 ++++ cli/tests/test_put.py | 4 ++++ cli/tests/test_pwa.py | 4 ++++ cli/tests/test_rawpaste.py | 4 ++++ cli/tests/test_read_ahead.py | 4 ++++ cli/tests/test_read_file_checked.py | 4 ++++ cli/tests/test_readonly_drive.py | 4 ++++ cli/tests/test_repl_connect_prompt.py | 4 ++++ cli/tests/test_repl_quiet_transfer.py | 4 ++++ cli/tests/test_reset_monitor.py | 4 ++++ cli/tests/test_resolve_python.py | 4 ++++ cli/tests/test_romfs.py | 4 ++++ cli/tests/test_rpc_discovery.py | 4 ++++ cli/tests/test_rtc.py | 4 ++++ cli/tests/test_s2_rom_usb.py | 4 ++++ cli/tests/test_serial_recovery.py | 4 ++++ cli/tests/test_session_sidecars.py | 4 ++++ cli/tests/test_sidecar_job.py | 4 ++++ cli/tests/test_sidecar_runs_this_mpftp.py | 4 ++++ cli/tests/test_stray_output.py | 4 ++++ cli/tests/test_subprocess_stdin.py | 4 ++++ cli/tests/test_transfer_progress.py | 4 ++++ cli/tests/test_uf2.py | 4 ++++ cli/tests/test_uf2_flash.py | 4 ++++ cli/tests/test_vendor_pins.py | 4 ++++ cli/tests/test_version_flag.py | 4 ++++ cli/tests/test_watch_repl.py | 4 ++++ cli/tests/test_webflash.py | 4 ++++ cli/tests/test_webrepl.py | 4 ++++ cli/tests/test_wifi_access.py | 4 ++++ cli/tests/test_wslenv.py | 4 ++++ docs/conf.py | 4 ++++ extension/python/mpftp_launch.py | 4 ++++ scripts/check_versions.py | 4 ++++ tools/ble_bench.py | 4 ++++ tools/ble_gate.py | 4 ++++ tools/test_cli_workflows.py | 4 ++++ 93 files changed, 372 insertions(+) diff --git a/cli/src/mpftp/__init__.py b/cli/src/mpftp/__init__.py index 9378f63..05ef62a 100644 --- a/cli/src/mpftp/__init__.py +++ b/cli/src/mpftp/__init__.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """mpftp — MicroPython and CircuitPython board tools. Importing this package has no side effects: nothing is spawned, no socket is diff --git a/cli/src/mpftp/__main__.py b/cli/src/mpftp/__main__.py index ad92c26..8f02e90 100644 --- a/cli/src/mpftp/__main__.py +++ b/cli/src/mpftp/__main__.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """``python -m mpftp`` — the CLI, or the local PWA with no arguments. ``python -m mpftp ...`` behaves exactly like the ``mpftp`` diff --git a/cli/src/mpftp/ble.py b/cli/src/mpftp/ble.py index 028fc5e..ef9288c 100644 --- a/cli/src/mpftp/ble.py +++ b/cli/src/mpftp/ble.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """Reach a board over Bluetooth Low Energy: ``-d ble://NAME``. The board runs ``bledev.repl`` (pydevices' ``bledev`` package), which serves diff --git a/cli/src/mpftp/boards.py b/cli/src/mpftp/boards.py index 7e8463f..be8867b 100644 --- a/cli/src/mpftp/boards.py +++ b/cli/src/mpftp/boards.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """Boards mpftp can reach over Wi-Fi, and their WebREPL passwords. Remembered boards live in ``~/.mpftp/config.json`` under ``wifiBoards``, diff --git a/cli/src/mpftp/cli.py b/cli/src/mpftp/cli.py index 8892dc0..3e7931f 100755 --- a/cli/src/mpftp/cli.py +++ b/cli/src/mpftp/cli.py @@ -1,4 +1,8 @@ #!/usr/bin/env python3 +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """ mpftp CLI — agent-friendly front-end to the mpftp sidecar / extension RPC. diff --git a/cli/src/mpftp/config.py b/cli/src/mpftp/config.py index 9d07033..e39b986 100644 --- a/cli/src/mpftp/config.py +++ b/cli/src/mpftp/config.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """``~/.mpftp/config.json`` — one settings file for every mpftp frontend. JSON rather than TOML so the file looks like every other tool config a coding diff --git a/cli/src/mpftp/conpty.py b/cli/src/mpftp/conpty.py index 6e0e894..f07c9cb 100644 --- a/cli/src/mpftp/conpty.py +++ b/cli/src/mpftp/conpty.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """A Windows program inside a pseudo console (ConPTY), for ``mpftp hold``. Standard library only (ctypes). Windows-only: imported by the hold pump when diff --git a/cli/src/mpftp/desktop_host.py b/cli/src/mpftp/desktop_host.py index 78808ad..7a84a62 100644 --- a/cli/src/mpftp/desktop_host.py +++ b/cli/src/mpftp/desktop_host.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """ mpftp desktop host: the PWA's relay without the web server. diff --git a/cli/src/mpftp/emu.py b/cli/src/mpftp/emu.py index 376d9d0..031f3b0 100644 --- a/cli/src/mpftp/emu.py +++ b/cli/src/mpftp/emu.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """ The desktop app's emulator as a board: ``emu://``. diff --git a/cli/src/mpftp/espusb.py b/cli/src/mpftp/espusb.py index 1c57748..750831d 100644 --- a/cli/src/mpftp/espusb.py +++ b/cli/src/mpftp/espusb.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """No-UAC recovery for an ESP32 wedged on its own USB, or a CH343 port that answers "Incorrect function" (mpftp#31). diff --git a/cli/src/mpftp/firmware.py b/cli/src/mpftp/firmware.py index 5981192..47572dd 100644 --- a/cli/src/mpftp/firmware.py +++ b/cli/src/mpftp/firmware.py @@ -1,4 +1,8 @@ #!/usr/bin/env python3 +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """ mpftp firmware engine — build MicroPython (or CircuitPython-compatible) firmware with micropython-pydevices' ``build_mp.py``, and flash it. diff --git a/cli/src/mpftp/firmware_build.py b/cli/src/mpftp/firmware_build.py index 05bff0b..5433c9c 100644 --- a/cli/src/mpftp/firmware_build.py +++ b/cli/src/mpftp/firmware_build.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """Firmware builds through micropython-pydevices' ``build_mp.py``. ``mpftp firmware build`` doesn't run ``make`` itself. It finds a diff --git a/cli/src/mpftp/firmware_download.py b/cli/src/mpftp/firmware_download.py index c4fa995..6f7eea7 100644 --- a/cli/src/mpftp/firmware_download.py +++ b/cli/src/mpftp/firmware_download.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """ Official firmware: a catalog of boards, the images each one has, and the download. diff --git a/cli/src/mpftp/hold.py b/cli/src/mpftp/hold.py index 2bd2616..c41942a 100644 --- a/cli/src/mpftp/hold.py +++ b/cli/src/mpftp/hold.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """``mpftp hold``: keep one board's friendly REPL open between commands. Every other mpftp command opens a connection, enters the raw REPL with a diff --git a/cli/src/mpftp/mdns.py b/cli/src/mpftp/mdns.py index e0686a9..cf3b651 100644 --- a/cli/src/mpftp/mdns.py +++ b/cli/src/mpftp/mdns.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """Find a board by its ``.local`` name: a minimal mDNS client. MicroPython's esp32 port answers mDNS A queries for ``network.hostname()`` diff --git a/cli/src/mpftp/package_search.py b/cli/src/mpftp/package_search.py index 9ec05c6..a96e96a 100644 --- a/cli/src/mpftp/package_search.py +++ b/cli/src/mpftp/package_search.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """Find a package without knowing its exact name. One search across the three places a board's packages come from: diff --git a/cli/src/mpftp/panel.py b/cli/src/mpftp/panel.py index d9dda99..d10f4eb 100644 --- a/cli/src/mpftp/panel.py +++ b/cli/src/mpftp/panel.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """The File Transfer panel's host for the browser interface (``python -m mpftp``). The browser page runs the VS Code extension's own panel script diff --git a/cli/src/mpftp/parentwatch.py b/cli/src/mpftp/parentwatch.py index 361aa61..1daf715 100644 --- a/cli/src/mpftp/parentwatch.py +++ b/cli/src/mpftp/parentwatch.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """End this process when the one that started it ends, however it ends. The desktop app starts ``mpftp.desktop_host``, which starts diff --git a/cli/src/mpftp/pwa.py b/cli/src/mpftp/pwa.py index 888a6cf..4584d24 100644 --- a/cli/src/mpftp/pwa.py +++ b/cli/src/mpftp/pwa.py @@ -1,4 +1,8 @@ #!/usr/bin/env python3 +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """ mpftp local PWA — a loopback-only web UI (file transfer + REPL) for a MicroPython/CircuitPython board, served entirely with the standard library. diff --git a/cli/src/mpftp/rawpaste.py b/cli/src/mpftp/rawpaste.py index 526bc0d..a229577 100644 --- a/cli/src/mpftp/rawpaste.py +++ b/cli/src/mpftp/rawpaste.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """Raw-paste over serial, one flow-control window in flight. Raw-paste mode (``Ctrl-E A Ctrl-A``) lets the host run ahead of the board: the diff --git a/cli/src/mpftp/sidecar.py b/cli/src/mpftp/sidecar.py index e507edb..f48acb3 100644 --- a/cli/src/mpftp/sidecar.py +++ b/cli/src/mpftp/sidecar.py @@ -1,4 +1,8 @@ #!/usr/bin/env python3 +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """ mpftp sidecar — long-lived mpremote session for VS Code / Cursor. diff --git a/cli/src/mpftp/uf2.py b/cli/src/mpftp/uf2.py index b197c49..c0808a9 100644 --- a/cli/src/mpftp/uf2.py +++ b/cli/src/mpftp/uf2.py @@ -1,4 +1,8 @@ #!/usr/bin/env python3 +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """ UF2 support for the mpftp firmware engine: file validation, bootloader-volume discovery, and the copy-and-verify flash itself. diff --git a/cli/src/mpftp/webflash.py b/cli/src/mpftp/webflash.py index f2f66c1..fce4a0e 100644 --- a/cli/src/mpftp/webflash.py +++ b/cli/src/mpftp/webflash.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """ Flashing a board from the browser interface (``python -m mpftp``). diff --git a/cli/src/mpftp/webrepl.py b/cli/src/mpftp/webrepl.py index 5c80fbf..3c1bae7 100644 --- a/cli/src/mpftp/webrepl.py +++ b/cli/src/mpftp/webrepl.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """Reach a board over Wi-Fi through MicroPython's WebREPL. A WebREPL session is a WebSocket whose text frames carry the REPL's byte diff --git a/cli/src/mpftp/wifiboard.py b/cli/src/mpftp/wifiboard.py index 80e98ad..666a314 100644 --- a/cli/src/mpftp/wifiboard.py +++ b/cli/src/mpftp/wifiboard.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """What mpftp says to a board about Wi-Fi: identity, boot.py, power save. Pure functions and board-side snippets, so the sidecar stays a caller and the diff --git a/cli/tests/fake_circuitpython.py b/cli/tests/fake_circuitpython.py index c75ea04..08da7b6 100644 --- a/cli/tests/fake_circuitpython.py +++ b/cli/tests/fake_circuitpython.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """A serial port that answers the way a CircuitPython 11 board does. The detail that matters for connect time is how CircuitPython changes REPL diff --git a/cli/tests/test_app_image_offset.py b/cli/tests/test_app_image_offset.py index f4e6c8d..ba61988 100644 --- a/cli/tests/test_app_image_offset.py +++ b/cli/tests/test_app_image_offset.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """An application image written at the bootloader offset boot-loops the board. mpftp#67: ``micropython.bin`` flashed with ``--artifact`` on the P4 went to diff --git a/cli/tests/test_binary_roundtrip.py b/cli/tests/test_binary_roundtrip.py index ea809d6..75a2cc1 100644 --- a/cli/tests/test_binary_roundtrip.py +++ b/cli/tests/test_binary_roundtrip.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """get, put, cp and hash keep every byte of a binary file (null bytes included). A model file (.espdl) is full of zeros and every other byte value. The board diff --git a/cli/tests/test_ble.py b/cli/tests/test_ble.py index 69116ff..8c899fa 100644 --- a/cli/tests/test_ble.py +++ b/cli/tests/test_ble.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """ble:// devices: addresses, passwords, the bledev.repl login and file transfer. No radio and no bleak: the "board" answers what BleSerial writes, the way diff --git a/cli/tests/test_circuitpy_drive_match.py b/cli/tests/test_circuitpy_drive_match.py index b7ff551..7c1735e 100644 --- a/cli/tests/test_circuitpy_drive_match.py +++ b/cli/tests/test_circuitpy_drive_match.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """Which CIRCUITPY drive belongs to the connected board (mpftp#169).""" from __future__ import annotations diff --git a/cli/tests/test_circuitpython.py b/cli/tests/test_circuitpython.py index 535d453..5bfc791 100644 --- a/cli/tests/test_circuitpython.py +++ b/cli/tests/test_circuitpython.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """Unit tests for CircuitPython serial helpers (no board required).""" from __future__ import annotations diff --git a/cli/tests/test_clean.py b/cli/tests/test_clean.py index 8a2cf5e..c080f62 100644 --- a/cli/tests/test_clean.py +++ b/cli/tests/test_clean.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """mpftp clean --dry-run: board debris cleanup (mpftp#17). No board required.""" from __future__ import annotations diff --git a/cli/tests/test_config.py b/cli/tests/test_config.py index 64b298c..e1c1363 100644 --- a/cli/tests/test_config.py +++ b/cli/tests/test_config.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """Unit tests for mpftp.config: ~/.mpftp/config.json (no board needed).""" from __future__ import annotations diff --git a/cli/tests/test_connect_deadline.py b/cli/tests/test_connect_deadline.py index 29dc872..6a42c32 100644 --- a/cli/tests/test_connect_deadline.py +++ b/cli/tests/test_connect_deadline.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """A board that floods output forever must not hold connect indefinitely (mpftp#193). mpremote's timeouts run between bytes, so continuous output defeats them. diff --git a/cli/tests/test_cp_connect_time.py b/cli/tests/test_cp_connect_time.py index b2c2642..a62c11e 100644 --- a/cli/tests/test_cp_connect_time.py +++ b/cli/tests/test_cp_connect_time.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """Connecting to CircuitPython does not wait out timeouts (mpftp#155). CircuitPython rebuilds its VM on every switch between the friendly and the raw diff --git a/cli/tests/test_detect.py b/cli/tests/test_detect.py index 444dcc2..10fe98b 100644 --- a/cli/tests/test_detect.py +++ b/cli/tests/test_detect.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """Unit tests for the firmware Detect parsers / matcher (no hardware). Sample esptool text is taken from the fixture campaign (ESP32-P4, ESP32-S3 diff --git a/cli/tests/test_discovery.py b/cli/tests/test_discovery.py index 1c053f1..e5c3705 100644 --- a/cli/tests/test_discovery.py +++ b/cli/tests/test_discovery.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """Firmware path discovery: MicroPython + generic SDK trees.""" from __future__ import annotations diff --git a/cli/tests/test_dunder_main.py b/cli/tests/test_dunder_main.py index ddec5d4..11b17fc 100644 --- a/cli/tests/test_dunder_main.py +++ b/cli/tests/test_dunder_main.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """``python -m mpftp``: no args launches the PWA, any args go to the CLI (mpftp#11 phase 11).""" from __future__ import annotations diff --git a/cli/tests/test_engine_python.py b/cli/tests/test_engine_python.py index c2d6576..dc2a928 100644 --- a/cli/tests/test_engine_python.py +++ b/cli/tests/test_engine_python.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """The firmware engine runs under the python that runs the CLI. Picking the first ``python3`` on PATH found the system's python, which has no diff --git a/cli/tests/test_error_envelope.py b/cli/tests/test_error_envelope.py index b071674..7dccba0 100644 --- a/cli/tests/test_error_envelope.py +++ b/cli/tests/test_error_envelope.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """Structured {"ok": false, "error", "hint"} failures instead of bare text or a confusing "Expecting value" JSONDecodeError (mpftp#15).""" diff --git a/cli/tests/test_esp_usb_restart.py b/cli/tests/test_esp_usb_restart.py index 92f1d2e..598584a 100644 --- a/cli/tests/test_esp_usb_restart.py +++ b/cli/tests/test_esp_usb_restart.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """The no-UAC ESP32 USB recovery: what it accepts, and what it refuses (mpftp#31). The privileged half of this recovery runs as SYSTEM, so the only thing an diff --git a/cli/tests/test_firmware_build.py b/cli/tests/test_firmware_build.py index 2bd6f74..6ea2876 100644 --- a/cli/tests/test_firmware_build.py +++ b/cli/tests/test_firmware_build.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """`mpftp firmware build` runs micropython-pydevices' build_mp.py (mpftp#75). Every test here runs against a fake build_mp.py: a script with the same diff --git a/cli/tests/test_firmware_download.py b/cli/tests/test_firmware_download.py index 6220f6c..db33e5a 100644 --- a/cli/tests/test_firmware_download.py +++ b/cli/tests/test_firmware_download.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """The official firmware catalog (mpftp.firmware_download). No network: micropython.org's board index is a trimmed copy in fixtures/, and diff --git a/cli/tests/test_follow_timeout.py b/cli/tests/test_follow_timeout.py index 7bb9a19..af97f47 100644 --- a/cli/tests/test_follow_timeout.py +++ b/cli/tests/test_follow_timeout.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """``run --follow`` used to discard everything the board printed when the follow hit its quiet timeout, so a script that printed twenty lines and then hung looked identical to one that never started (mpftp#25). The partial output diff --git a/cli/tests/test_hash_file.py b/cli/tests/test_hash_file.py index 58cfdf9..bd6e5d1 100644 --- a/cli/tests/test_hash_file.py +++ b/cli/tests/test_hash_file.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """Verification hashes on the board, CircuitPython included (mpftp#183).""" import hashlib diff --git a/cli/tests/test_helpers.py b/cli/tests/test_helpers.py index 1b5c94f..b9826b7 100644 --- a/cli/tests/test_helpers.py +++ b/cli/tests/test_helpers.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """Unit tests that do not require a board.""" from __future__ import annotations diff --git a/cli/tests/test_hold.py b/cli/tests/test_hold.py index ca3b2cd..0598d52 100644 --- a/cli/tests/test_hold.py +++ b/cli/tests/test_hold.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """``mpftp hold``: a REPL kept open across commands. The parsing tests pin down how a reply is cut out of a stream the app also diff --git a/cli/tests/test_idf_version.py b/cli/tests/test_idf_version.py index a404c13..820397d 100644 --- a/cli/tests/test_idf_version.py +++ b/cli/tests/test_idf_version.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """ESP-IDF version / docs URL parsing from ports/esp32/README.md.""" from __future__ import annotations diff --git a/cli/tests/test_list_ports.py b/cli/tests/test_list_ports.py index 339f026..bb8cb6c 100644 --- a/cli/tests/test_list_ports.py +++ b/cli/tests/test_list_ports.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """The Connect dialog lists boards, not the UARTs Linux always creates (mpftp#179).""" import os diff --git a/cli/tests/test_mip.py b/cli/tests/test_mip.py index cee8a42..c55b08e 100644 --- a/cli/tests/test_mip.py +++ b/cli/tests/test_mip.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """mip install --index (mpftp#18): the RPC already took an index, the CLI just never asked for one.""" from __future__ import annotations diff --git a/cli/tests/test_monitor_capture.py b/cli/tests/test_monitor_capture.py index 6ec258d..3d0d27a 100644 --- a/cli/tests/test_monitor_capture.py +++ b/cli/tests/test_monitor_capture.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """``mpftp monitor``: a bounded read-only console capture. The capture itself is covered by watch-repl's shape; what is easy to get diff --git a/cli/tests/test_mpy_compile.py b/cli/tests/test_mpy_compile.py index 954e303..e74748c 100644 --- a/cli/tests/test_mpy_compile.py +++ b/cli/tests/test_mpy_compile.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """Compile-on-upload via mpy-cross (mpftp#4). No board or real mpy-cross required.""" from __future__ import annotations diff --git a/cli/tests/test_package_search.py b/cli/tests/test_package_search.py index 21e098c..905c6aa 100644 --- a/cli/tests/test_package_search.py +++ b/cli/tests/test_package_search.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """`mpftp search`: one search across micropython-lib, the PyDevices index and the CircuitPython bundles. The index samples under fixtures/package-index are cut from the real ones diff --git a/cli/tests/test_panel.py b/cli/tests/test_panel.py index 0787a05..02d33ab 100644 --- a/cli/tests/test_panel.py +++ b/cli/tests/test_panel.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """The browser's File Transfer panel host (mpftp.panel): the port of the VS Code extension's FtpViewProvider. A fake sidecar stands in for the board; the local side is a real temporary directory. No board, browser or built UI required. diff --git a/cli/tests/test_parentwatch.py b/cli/tests/test_parentwatch.py index abbd7ef..e97c67e 100644 --- a/cli/tests/test_parentwatch.py +++ b/cli/tests/test_parentwatch.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """The desktop helpers end with the app that started them (mpftp#159).""" from __future__ import annotations diff --git a/cli/tests/test_partition_table.py b/cli/tests/test_partition_table.py index 7304e38..77f6357 100644 --- a/cli/tests/test_partition_table.py +++ b/cli/tests/test_partition_table.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """Binary partition tables: decode, diff, and find one inside a firmware image. The check these back exists because a T-Embed S3 was flashed through its ROM diff --git a/cli/tests/test_probe.py b/cli/tests/test_probe.py index 1222890..8a82f59 100644 --- a/cli/tests/test_probe.py +++ b/cli/tests/test_probe.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """probe: run -> wait -> capture in one shot (mpftp#11). Exercises cmd_probe/_wait_and_reconnect against a fake RpcClient (no board, diff --git a/cli/tests/test_put.py b/cli/tests/test_put.py index c2a5adc..0c5082a 100644 --- a/cli/tests/test_put.py +++ b/cli/tests/test_put.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """put: directories go through fs_cp, not Path.read_bytes (IsADirectoryError).""" from __future__ import annotations diff --git a/cli/tests/test_pwa.py b/cli/tests/test_pwa.py index 3eff3a0..6d7475e 100644 --- a/cli/tests/test_pwa.py +++ b/cli/tests/test_pwa.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """mpftp local PWA backend: WS codec, static path safety, sidecar relay (mpftp#11 phase 11). No board, browser, or built UI required. diff --git a/cli/tests/test_rawpaste.py b/cli/tests/test_rawpaste.py index b94208a..c11f8f8 100644 --- a/cli/tests/test_rawpaste.py +++ b/cli/tests/test_rawpaste.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """Raw-paste pacing for CircuitPython over serial (mpftp#50).""" from __future__ import annotations diff --git a/cli/tests/test_read_ahead.py b/cli/tests/test_read_ahead.py index 03bede6..2ca6239 100644 --- a/cli/tests/test_read_ahead.py +++ b/cli/tests/test_read_ahead.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """A download reads its reply in bulk, not a byte per serial call (mpftp#133).""" from __future__ import annotations diff --git a/cli/tests/test_read_file_checked.py b/cli/tests/test_read_file_checked.py index eb65494..6a98a20 100644 --- a/cli/tests/test_read_file_checked.py +++ b/cli/tests/test_read_file_checked.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """``get`` survives a board that sends more than it was asked to print. The P4 DEV-KIT, on its native USB, sometimes sends bytes after the closing diff --git a/cli/tests/test_readonly_drive.py b/cli/tests/test_readonly_drive.py index be38b92..6a3a0e4 100644 --- a/cli/tests/test_readonly_drive.py +++ b/cli/tests/test_readonly_drive.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """An upload to a CIRCUITPY drive the computer can't write (mpftp#158).""" from __future__ import annotations diff --git a/cli/tests/test_repl_connect_prompt.py b/cli/tests/test_repl_connect_prompt.py index 17aee7a..d0ec181 100644 --- a/cli/tests/test_repl_connect_prompt.py +++ b/cli/tests/test_repl_connect_prompt.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """Opening the REPL pane right after connect shows no lone ``>`` (mpftp#150). The connect handshake runs commands in raw REPL, and each one leaves the raw diff --git a/cli/tests/test_repl_quiet_transfer.py b/cli/tests/test_repl_quiet_transfer.py index 5725357..8bf3d68 100644 --- a/cli/tests/test_repl_quiet_transfer.py +++ b/cli/tests/test_repl_quiet_transfer.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """A transfer leaves the REPL pane alone (mpftp#134). Leaving raw REPL sends Ctrl-B, and the board answers with its banner and a diff --git a/cli/tests/test_reset_monitor.py b/cli/tests/test_reset_monitor.py index 5f0c371..f7b61eb 100644 --- a/cli/tests/test_reset_monitor.py +++ b/cli/tests/test_reset_monitor.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """``mpftp hard-reset --monitor SECONDS`` (mpftp#60). Reset, let main.py run, then capture the boot read-only on the same port. The diff --git a/cli/tests/test_resolve_python.py b/cli/tests/test_resolve_python.py index 2bb8c0a..52f03e1 100644 --- a/cli/tests/test_resolve_python.py +++ b/cli/tests/test_resolve_python.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """Which interpreter the sidecar runs in.""" import io diff --git a/cli/tests/test_romfs.py b/cli/tests/test_romfs.py index e08c367..4612083 100644 --- a/cli/tests/test_romfs.py +++ b/cli/tests/test_romfs.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """romfs build is host-only; mpremote still requires a State with did_action().""" from __future__ import annotations diff --git a/cli/tests/test_rpc_discovery.py b/cli/tests/test_rpc_discovery.py index bb888fb..c5b9ced 100644 --- a/cli/tests/test_rpc_discovery.py +++ b/cli/tests/test_rpc_discovery.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """CLI RPC address discovery: env override, then workspace registry, then nothing. There is deliberately no third fallback. The extension only ever listens on an diff --git a/cli/tests/test_rtc.py b/cli/tests/test_rtc.py index dc10ef5..695d0ed 100644 --- a/cli/tests/test_rtc.py +++ b/cli/tests/test_rtc.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """The board clock on connect and on ``rtc --set`` (mpftp#58). Every connect used to write the host's *local* time into the board's RTC, diff --git a/cli/tests/test_s2_rom_usb.py b/cli/tests/test_s2_rom_usb.py index 07fda6c..a67f92c 100644 --- a/cli/tests/test_s2_rom_usb.py +++ b/cli/tests/test_s2_rom_usb.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """An ESP32-S2 in ROM download mode on its own USB is detected and flashed without being stranded (mpftp#70). diff --git a/cli/tests/test_serial_recovery.py b/cli/tests/test_serial_recovery.py index fa73ba8..41dd078 100644 --- a/cli/tests/test_serial_recovery.py +++ b/cli/tests/test_serial_recovery.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """Wedged-COM-handle recovery: bounded writes + dead-transport detection. pyserial defaults to write_timeout=None (block forever). A COM handle left diff --git a/cli/tests/test_session_sidecars.py b/cli/tests/test_session_sidecars.py index f06119e..52172ba 100644 --- a/cli/tests/test_session_sidecars.py +++ b/cli/tests/test_session_sidecars.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """Per-window sidecar session pid isolation (no board required).""" from __future__ import annotations diff --git a/cli/tests/test_sidecar_job.py b/cli/tests/test_sidecar_job.py index fd82eba..2ece0d0 100644 --- a/cli/tests/test_sidecar_job.py +++ b/cli/tests/test_sidecar_job.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """The sidecar's children die with it on Windows (mpftp#146). Run from WSL, the sidecar is ended when the Linux command that started it is diff --git a/cli/tests/test_sidecar_runs_this_mpftp.py b/cli/tests/test_sidecar_runs_this_mpftp.py index 7de436a..e3636e5 100644 --- a/cli/tests/test_sidecar_runs_this_mpftp.py +++ b/cli/tests/test_sidecar_runs_this_mpftp.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """The sidecar the CLI starts runs the CLI's own mpftp (mpftp#171). On WSL the CLI starts its sidecar under Windows Python, for the COM ports. diff --git a/cli/tests/test_stray_output.py b/cli/tests/test_stray_output.py index 23d7a45..91a0d41 100644 --- a/cli/tests/test_stray_output.py +++ b/cli/tests/test_stray_output.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """A board that is busy when mpftp connects over a USB-UART bridge (mpftp#98). On a CircuitPython board whose console is a CH343 UART, every standalone diff --git a/cli/tests/test_subprocess_stdin.py b/cli/tests/test_subprocess_stdin.py index 900e9b6..e39820e 100644 --- a/cli/tests/test_subprocess_stdin.py +++ b/cli/tests/test_subprocess_stdin.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """Every child process the sidecar starts must not inherit its stdin (no board required). The sidecar reads JSON requests from stdin on a reader thread. On Windows a diff --git a/cli/tests/test_transfer_progress.py b/cli/tests/test_transfer_progress.py index 60a56a6..0d15136 100644 --- a/cli/tests/test_transfer_progress.py +++ b/cli/tests/test_transfer_progress.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """Bytes moving inside one large file count as activity (mpftp#149). A 2.8 MB download over USB serial is a single request for about twelve diff --git a/cli/tests/test_uf2.py b/cli/tests/test_uf2.py index 517a604..1c42aa4 100644 --- a/cli/tests/test_uf2.py +++ b/cli/tests/test_uf2.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """UF2 file validation, volume discovery, and the copy/verify flash path.""" from __future__ import annotations diff --git a/cli/tests/test_uf2_flash.py b/cli/tests/test_uf2_flash.py index c8d67d1..f02d442 100644 --- a/cli/tests/test_uf2_flash.py +++ b/cli/tests/test_uf2_flash.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """The flash_uf2 path in the firmware engine. These cover the failure modes that motivated the feature: a copy that reports diff --git a/cli/tests/test_vendor_pins.py b/cli/tests/test_vendor_pins.py index f0cfa25..51b7d46 100644 --- a/cli/tests/test_vendor_pins.py +++ b/cli/tests/test_vendor_pins.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """The mpremote and pyserial bundled into the VSIX sit inside pyproject's ranges. The pip package and the VS Code extension must run the same mpremote that CI diff --git a/cli/tests/test_version_flag.py b/cli/tests/test_version_flag.py index 205cd3c..ff6b709 100644 --- a/cli/tests/test_version_flag.py +++ b/cli/tests/test_version_flag.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """``mpftp --version`` prints the version and exits 0 (mpftp#52).""" from __future__ import annotations diff --git a/cli/tests/test_watch_repl.py b/cli/tests/test_watch_repl.py index c91f7f8..b0e7b37 100644 --- a/cli/tests/test_watch_repl.py +++ b/cli/tests/test_watch_repl.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """Non-interrupting live tail of the board's own stdout (mpftp#10). Both transports stream repl_data/repl_error notify events to a callback diff --git a/cli/tests/test_webflash.py b/cli/tests/test_webflash.py index 1a5b04c..b3e9c04 100644 --- a/cli/tests/test_webflash.py +++ b/cli/tests/test_webflash.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """The browser's Firmware button, server side (mpftp.webflash). The board is a mocked sidecar and esptool is tests/fixtures/fake-esptool or a diff --git a/cli/tests/test_webrepl.py b/cli/tests/test_webrepl.py index 2b1acb0..5e1330c 100644 --- a/cli/tests/test_webrepl.py +++ b/cli/tests/test_webrepl.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """WebREPL client: WebSocket framing, the upgrade, the password login. The "board" here is a thread on the far end of a socketpair that speaks the diff --git a/cli/tests/test_wifi_access.py b/cli/tests/test_wifi_access.py index 036921a..c194877 100644 --- a/cli/tests/test_wifi_access.py +++ b/cli/tests/test_wifi_access.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """Wi-Fi as a first-class connection: boot.py block, power save, busy boards, remembered boards and their passwords, mDNS. No board required.""" diff --git a/cli/tests/test_wslenv.py b/cli/tests/test_wslenv.py index 390d5bd..49601f6 100644 --- a/cli/tests/test_wslenv.py +++ b/cli/tests/test_wslenv.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """WSLENV forwarding when spawning a Windows interpreter from WSL (mpftp#12). A Windows binary spawned from WSL only receives env vars named in WSLENV diff --git a/docs/conf.py b/docs/conf.py index f2a4936..87e50e8 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """Sphinx configuration for the mpftp documentation. Everything shared by the PyDevices documentation projects (theme, top bar, diff --git a/extension/python/mpftp_launch.py b/extension/python/mpftp_launch.py index 62891f8..f4d9597 100644 --- a/extension/python/mpftp_launch.py +++ b/extension/python/mpftp_launch.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """Run an mpftp entry point from the copy vendored inside the VSIX. The extension spawns Python by absolute *script path* so that platform.ts can diff --git a/scripts/check_versions.py b/scripts/check_versions.py index 44f9959..5e44dcb 100755 --- a/scripts/check_versions.py +++ b/scripts/check_versions.py @@ -1,4 +1,8 @@ #!/usr/bin/env python3 +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """Assert every deliverable reports the version in the root VERSION file. One release version covers the Python distribution, the VS Code extension, and diff --git a/tools/ble_bench.py b/tools/ble_bench.py index 3c28a8f..0890bcd 100644 --- a/tools/ble_bench.py +++ b/tools/ble_bench.py @@ -1,4 +1,8 @@ #!/usr/bin/env python3 +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """Time file transfers to a board over BLE: file transfer against raw REPL. Opens one ``ble://`` transport (the sidecar's own code path), then times a diff --git a/tools/ble_gate.py b/tools/ble_gate.py index 93a4c89..a7ac6f6 100644 --- a/tools/ble_gate.py +++ b/tools/ble_gate.py @@ -1,4 +1,8 @@ #!/usr/bin/env python3 +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """The ble:// gate, in one sidecar session, as the VS Code extension drives it. Against a board running ``bledev.filetransfer.start()`` (or diff --git a/tools/test_cli_workflows.py b/tools/test_cli_workflows.py index f374785..b5a4343 100755 --- a/tools/test_cli_workflows.py +++ b/tools/test_cli_workflows.py @@ -1,4 +1,8 @@ #!/usr/bin/env python3 +# SPDX-FileCopyrightText: 2026 Brad Barnett +# +# SPDX-License-Identifier: MIT + """Exercise mpftp CLI workflows against attached boards. Host-only commands run once. Board commands run on each REPL port from