From d1c1309106897c899dd011ae1a1f00a0b6ec39fa Mon Sep 17 00:00:00 2001 From: shaggy Date: Fri, 31 Oct 2025 16:16:16 -0500 Subject: [PATCH 1/4] cli/__init__.py: catch a syntax error when re-compiling the target file --- pybricksdev/cli/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pybricksdev/cli/__init__.py b/pybricksdev/cli/__init__.py index 8f4a1e4..bc0c734 100644 --- a/pybricksdev/cli/__init__.py +++ b/pybricksdev/cli/__init__.py @@ -359,6 +359,10 @@ async def reconnect_hub(): case _: return + except SyntaxError as e: + print("\nA syntax error occurred when parsing your program:") + print(e, "\n") + except HubPowerButtonPressedError: # This means the user pressed the button on the hub to re-start the # current program, so the menu was canceled and we are now printing From 8b5eb9c183be1bc2be703bb8bcc8f77bdf552cb7 Mon Sep 17 00:00:00 2001 From: shaggy Date: Fri, 31 Oct 2025 16:25:18 -0500 Subject: [PATCH 2/4] cli/__init__.py: slightly modify the error message warning --- pybricksdev/cli/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pybricksdev/cli/__init__.py b/pybricksdev/cli/__init__.py index bc0c734..6beedf8 100644 --- a/pybricksdev/cli/__init__.py +++ b/pybricksdev/cli/__init__.py @@ -360,7 +360,7 @@ async def reconnect_hub(): return except SyntaxError as e: - print("\nA syntax error occurred when parsing your program:") + print("\nA syntax error occurred while parsing your program:") print(e, "\n") except HubPowerButtonPressedError: From e95fc0e313ca4b8002a5ab861287e606503d495a Mon Sep 17 00:00:00 2001 From: shaggy Date: Sat, 1 Nov 2025 10:47:12 -0500 Subject: [PATCH 3/4] cli/__init__.py: refactor to allow the catching of syntax errors on the first download to the hub --- pybricksdev/cli/__init__.py | 139 +++++++++++++++++++----------------- 1 file changed, 75 insertions(+), 64 deletions(-) diff --git a/pybricksdev/cli/__init__.py b/pybricksdev/cli/__init__.py index 6beedf8..42c2ae6 100644 --- a/pybricksdev/cli/__init__.py +++ b/pybricksdev/cli/__init__.py @@ -25,6 +25,7 @@ from pybricksdev.connections.pybricks import ( HubDisconnectError, HubPowerButtonPressedError, + PybricksHub, ) PROG_NAME = ( @@ -184,70 +185,7 @@ def add_parser(self, subparsers: argparse._SubParsersAction): async def run(self, args: argparse.Namespace): - # Pick the right connection - if args.conntype == "ble": - from pybricksdev.ble import find_device as find_ble - from pybricksdev.connections.pybricks import PybricksHubBLE - - # It is a Pybricks Hub with BLE. Device name or address is given. - print(f"Searching for {args.name or 'any hub with Pybricks service'}...") - device_or_address = await find_ble(args.name) - hub = PybricksHubBLE(device_or_address) - elif args.conntype == "usb": - from usb.core import find as find_usb - - from pybricksdev.connections.pybricks import PybricksHubUSB - from pybricksdev.usb import ( - EV3_USB_PID, - LEGO_USB_VID, - MINDSTORMS_INVENTOR_USB_PID, - NXT_USB_PID, - SPIKE_ESSENTIAL_USB_PID, - SPIKE_PRIME_USB_PID, - ) - - def is_pybricks_usb(dev): - return ( - (dev.idVendor == LEGO_USB_VID) - and ( - dev.idProduct - in [ - NXT_USB_PID, - EV3_USB_PID, - SPIKE_PRIME_USB_PID, - SPIKE_ESSENTIAL_USB_PID, - MINDSTORMS_INVENTOR_USB_PID, - ] - ) - and dev.product.endswith("Pybricks") - ) - - device_or_address = find_usb(custom_match=is_pybricks_usb) - - if device_or_address is None: - print("Pybricks Hub not found.", file=sys.stderr) - exit(1) - - hub = PybricksHubUSB(device_or_address) - else: - raise ValueError(f"Unknown connection type: {args.conntype}") - - # Connect to the address and run the script - await hub.connect() - try: - with _get_script_path(args.file) as script_path: - if args.start: - await hub.run(script_path, args.wait or args.stay_connected) - else: - if args.stay_connected: - # if the user later starts the program by pressing the button on the hub, - # we still want the hub stdout to print to Python's stdout - hub.print_output = True - hub._enable_line_handler = True - await hub.download(script_path) - - if not args.stay_connected: - return + async def stay_connected_menu(hub: PybricksHub): class ResponseOptions(IntEnum): RECOMPILE_RUN = 0 @@ -379,6 +317,79 @@ async def reconnect_hub(): await asyncio.sleep(0.3) hub = await reconnect_hub() + # Pick the right connection + if args.conntype == "ble": + from pybricksdev.ble import find_device as find_ble + from pybricksdev.connections.pybricks import PybricksHubBLE + + # It is a Pybricks Hub with BLE. Device name or address is given. + print(f"Searching for {args.name or 'any hub with Pybricks service'}...") + device_or_address = await find_ble(args.name) + hub = PybricksHubBLE(device_or_address) + elif args.conntype == "usb": + from usb.core import find as find_usb + + from pybricksdev.connections.pybricks import PybricksHubUSB + from pybricksdev.usb import ( + EV3_USB_PID, + LEGO_USB_VID, + MINDSTORMS_INVENTOR_USB_PID, + NXT_USB_PID, + SPIKE_ESSENTIAL_USB_PID, + SPIKE_PRIME_USB_PID, + ) + + def is_pybricks_usb(dev): + return ( + (dev.idVendor == LEGO_USB_VID) + and ( + dev.idProduct + in [ + NXT_USB_PID, + EV3_USB_PID, + SPIKE_PRIME_USB_PID, + SPIKE_ESSENTIAL_USB_PID, + MINDSTORMS_INVENTOR_USB_PID, + ] + ) + and dev.product.endswith("Pybricks") + ) + + device_or_address = find_usb(custom_match=is_pybricks_usb) + + if device_or_address is None: + print("Pybricks Hub not found.", file=sys.stderr) + exit(1) + + hub = PybricksHubUSB(device_or_address) + else: + raise ValueError(f"Unknown connection type: {args.conntype}") + + # Connect to the address and run the script + await hub.connect() + try: + with _get_script_path(args.file) as script_path: + if args.start: + await hub.run(script_path, args.wait or args.stay_connected) + else: + if args.stay_connected: + # if the user later starts the program by pressing the button on the hub, + # we still want the hub stdout to print to Python's stdout + hub.print_output = True + hub._enable_line_handler = True + await hub.download(script_path) + + if not args.stay_connected: + return + + await stay_connected_menu(hub) + + except SyntaxError as e: + print("\nA syntax error occurred while parsing your program:") + print(e, "\n") + if args.stay_connected: + await stay_connected_menu(hub) + finally: await hub.disconnect() From c3f3c2016d68d57bc4b9f5968dd2050096faf293 Mon Sep 17 00:00:00 2001 From: shaggy Date: Sat, 1 Nov 2025 10:53:30 -0500 Subject: [PATCH 4/4] cli/__init__.py: clean up an if statement --- pybricksdev/cli/__init__.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pybricksdev/cli/__init__.py b/pybricksdev/cli/__init__.py index 42c2ae6..7730ce0 100644 --- a/pybricksdev/cli/__init__.py +++ b/pybricksdev/cli/__init__.py @@ -379,10 +379,8 @@ def is_pybricks_usb(dev): hub._enable_line_handler = True await hub.download(script_path) - if not args.stay_connected: - return - - await stay_connected_menu(hub) + if args.stay_connected: + await stay_connected_menu(hub) except SyntaxError as e: print("\nA syntax error occurred while parsing your program:")