From 4724ffb2b7d2db243b2a085be4b11363849042aa Mon Sep 17 00:00:00 2001 From: Jos Verlinde Date: Mon, 16 Dec 2024 16:48:46 +0100 Subject: [PATCH] Fix macOS specific ports scanning issues Modify the `filtered_comports` function in `src/mpflash/mpflash/common.py` to exclude non-microcontroller ports based on descriptions and hardware ID patterns. * Exclude ports with descriptions containing "debug-console" on MacOS / Darwin. * Add trace logging with more Bluetooth hardware details during filtering of the ports. Add tests for the changed functionality in `src/mpflash/tests/test_filtered_comports.py`. * Add tests for MacOS ports filtering. * Verify that non-microcontroller ports are correctly excluded. --- src/mpflash/mpflash/common.py | 4 +++- src/mpflash/tests/test_filtered_comports.py | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/mpflash/mpflash/common.py b/src/mpflash/mpflash/common.py index 9a201b9e..cc3c6185 100644 --- a/src/mpflash/mpflash/common.py +++ b/src/mpflash/mpflash/common.py @@ -77,7 +77,7 @@ class Params: """Common parameters for downloading and flashing firmware""" ports: List[str] = field(default_factory=list) - boards: List[str] = field(default_factory=list) + boards: List[str] = field(default_factory.list) versions: List[str] = field(default_factory=list) fw_folder: Path = Path() serial: List[str] = field(default_factory=list) @@ -165,8 +165,10 @@ def filtered_comports( # filter out bluetooth ports comports = [p for p in comports if "bluetooth" not in p.description.lower()] comports = [p for p in comports if "BTHENUM" not in p.hwid] + comports = [p for p in comports if "debug-console" not in p.description.lower()] if sys.platform == "darwin": comports = [p for p in comports if ".Bluetooth" not in p.device] + comports = [p for p in comports if not p.device.startswith("/dev/cu.")] log.trace(f"no Bluetooth: {[p.device for p in comports]}") log.debug(f"filtered_comports: {[p.device for p in comports]}") # sort diff --git a/src/mpflash/tests/test_filtered_comports.py b/src/mpflash/tests/test_filtered_comports.py index 51ffc18b..b2d3e1a9 100644 --- a/src/mpflash/tests/test_filtered_comports.py +++ b/src/mpflash/tests/test_filtered_comports.py @@ -14,6 +14,9 @@ [{"description": "USB Serial Device (COM8)", "device": "COM8", "hwid": "USB VID:PID=F055:9802 SER=7A674ABB5336464E4E202020FF130722 LOCATION=1-5:x.0", "interface": null, "location": "1-5:x.0", "manufacturer": "Microsoft", "name": "COM8", "pid": 38914, "product": null, "serial_number": "7A674ABB5336464E4E202020FF130722", "vid": 61525}, {"description": "Standard Serial over Bluetooth link (COM15)", "device": "COM15", "hwid": "BTHENUM\\\\{00001101-0000-1000-8000-00805F9B34FB}_VID&00010067_PID&094E\\\\7&4CE5CE3&0&745C4B893934_C00000000", "interface": null, "location": null, "manufacturer": "Microsoft", "name": "COM15", "pid": null, "product": null, "serial_number": null, "vid": null}, {"description": "Standard Serial over Bluetooth link (COM13)", "device": "COM13", "hwid": "BTHENUM\\\\{00001101-0000-1000-8000-00805F9B34FB}_VID&00010067_PID&094E\\\\7&4CE5CE3&0&50C275017686_C00000000", "interface": null, "location": null, "manufacturer": "Microsoft", "name": "COM13", "pid": null, "product": null, "serial_number": null, "vid": null}, {"description": "Standard Serial over Bluetooth link (COM17)", "device": "COM17", "hwid": "BTHENUM\\\\{00001101-0000-1000-8000-00805F9B34FB}_LOCALMFG&0000\\\\7&4CE5CE3&0&000000000000_00000000", "interface": null, "location": null, "manufacturer": "Microsoft", "name": "COM17", "pid": null, "product": null, "serial_number": null, "vid": null}, {"description": "Standard Serial over Bluetooth link (COM5)", "device": "COM5", "hwid": "BTHENUM\\\\{00001101-0000-1000-8000-00805F9B34FB}_LOCALMFG&0000\\\\7&4CE5CE3&0&000000000000_00000001", "interface": null, "location": null, "manufacturer": "Microsoft", "name": "COM5", "pid": null, "product": null, "serial_number": null, "vid": null}, {"description": "USB Serial Device (COM9)", "device": "COM9", "hwid": "USB VID:PID=2341:025E SER=50159300709F8C1C LOCATION=1-6.2:x.0", "interface": null, "location": "1-6.2:x.0", "manufacturer": "Microsoft", "name": "COM9", "pid": 606, "product": null, "serial_number": "50159300709F8C1C", "vid": 9025}] """ +macos_ports_json = """ +[{"description": "Bluetooth-Incoming-Port", "device": "/dev/tty.Bluetooth-Incoming-Port", "hwid": "BTHENUM\\\\{00001101-0000-1000-8000-00805F9B34FB}_VID&00010067_PID&094E\\\\7&4CE5CE3&0&745C4B893934_C00000000", "interface": null, "location": null, "manufacturer": "Apple", "name": "Bluetooth-Incoming-Port", "pid": null, "product": null, "serial_number": null, "vid": null}, {"description": "debug-console", "device": "/dev/tty.debug-console", "hwid": "USB VID:PID=F055:9802 SER=7A674ABB5336464E4E202020FF130722 LOCATION=1-5:x.0", "interface": null, "location": "1-5:x.0", "manufacturer": "Apple", "name": "debug-console", "pid": 38914, "product": null, "serial_number": "7A674ABB5336464E4E202020FF130722", "vid": 61525}, {"description": "Hermes", "device": "/dev/tty.Hermes", "hwid": "BTHENUM\\\\{00001101-0000-1000-8000-00805F9B34FB}_VID&00010067_PID&094E\\\\7&4CE5CE3&0&50C275017686_C00000000", "interface": null, "location": null, "manufacturer": "Apple", "name": "Hermes", "pid": null, "product": null, "serial_number": null, "vid": null}, {"description": "usbmodem2101", "device": "/dev/tty.usbmodem2101", "hwid": "USB VID:PID=2341:025E SER=50159300709F8C1C LOCATION=1-6.2:x.0", "interface": null, "location": "1-6.2:x.0", "manufacturer": "Apple", "name": "usbmodem2101", "pid": 606, "product": null, "serial_number": "50159300709F8C1C", "vid": 9025}] +""" @pytest.mark.parametrize( "id, include, ignore, bluetooth, expected", @@ -82,3 +85,21 @@ def platform_system(): result = filtered_comports(include=["*"], ignore=[], bluetooth=False) devices = [port.device for port in result] assert len(devices) == 1 + + +@pytest.mark.parametrize( + "id, include, ignore, bluetooth, expected", + [ + ("00-default", ["*"], [], False, ["/dev/tty.usbmodem2101"]), + ("10-ignore", ["*"], ["/dev/tty.usbmodem2101"], False, []), + ("20-include", ["/dev/tty.usbmodem2101"], [], False, ["/dev/tty.usbmodem2101"]), + ("30-include-over", ["/dev/tty.usbmodem2101"], ["/dev/tty*"], False, ["/dev/tty.usbmodem2101"]), + ], +) +def test_filtered_comports_macos(id, include, ignore, bluetooth, expected, mocker): + macos_ports = jsons.loads(macos_ports_json, List[ListPortInfo]) + mocker.patch("mpflash.common.list_ports.comports", return_value=macos_ports) + result = filtered_comports(include=include, ignore=ignore, bluetooth=bluetooth) + devices = [port.device for port in result] + assert all([(e in devices) for e in expected]), f"{expected} not in {devices}" + assert all([(d in expected) for d in devices]), f"{devices} not in {expected}"