Skip to content

Commit 745a588

Browse files
committed
minor fixes and cleanup
1 parent 52f055f commit 745a588

File tree

2 files changed

+74
-71
lines changed

2 files changed

+74
-71
lines changed

pybricksdev/cli/__init__.py

Lines changed: 63 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -230,75 +230,77 @@ def is_pybricks_usb(dev):
230230
await hub.run(script_path, args.wait or args.stay_connected)
231231
else:
232232
if args.stay_connected:
233+
# if the user later starts the program by pressing the button on the hub,
234+
# we still want the hub stdout to print to Python's stdout
233235
hub.print_output = True
234236
hub._enable_line_handler = True
235237
await hub.download(script_path)
236238

237-
if args.stay_connected:
238-
239-
async def reconnect_hub():
240-
if not await questionary.confirm(
241-
"\nThe hub has been disconnected. Would you like to re-connect?"
242-
).ask_async():
243-
exit()
244-
245-
if args.conntype == "ble":
246-
print(
247-
f"Searching for {args.name or 'any hub with Pybricks service'}..."
248-
)
249-
device_or_address = await find_ble(args.name)
250-
hub = PybricksHubBLE(device_or_address)
251-
elif args.conntype == "usb":
252-
device_or_address = find_usb(custom_match=is_pybricks_usb)
253-
hub = PybricksHubUSB(device_or_address)
254-
255-
await hub.connect()
256-
# re-enable echoing of the hub's stdout
257-
hub.log_file = None
258-
hub.output = []
259-
hub._stdout_buf.clear()
260-
hub._stdout_line_queue = asyncio.Queue()
261-
hub.print_output = True
262-
hub._enable_line_handler = True
263-
return hub
264-
265-
response_options = [
266-
"Recompile and Run",
267-
"Recompile and Download",
268-
"Exit",
269-
]
270-
while True:
271-
try:
272-
response = await hub.race_power_button_press(
273-
questionary.select(
274-
"Would you like to re-compile your code?",
275-
response_options,
276-
default=(
277-
response_options[0]
278-
if args.start
279-
else response_options[1]
280-
),
281-
).ask_async()
282-
)
283-
with _get_script_path(args.file) as script_path:
284-
if response == response_options[0]:
285-
await hub.run(script_path, True)
286-
elif response == response_options[1]:
287-
await hub.download(script_path)
288-
else:
289-
exit()
290-
291-
except HubPowerButtonPressedError:
292-
try:
293-
await hub._wait_for_user_program_stop(5)
294-
except HubDisconnectError:
295-
hub = await reconnect_hub()
239+
if not args.stay_connected:
240+
exit()
241+
242+
async def reconnect_hub():
243+
if not await questionary.confirm(
244+
"\nThe hub has been disconnected. Would you like to re-connect?"
245+
).ask_async():
246+
exit()
296247

248+
if args.conntype == "ble":
249+
print(
250+
f"Searching for {args.name or 'any hub with Pybricks service'}..."
251+
)
252+
device_or_address = await find_ble(args.name)
253+
hub = PybricksHubBLE(device_or_address)
254+
elif args.conntype == "usb":
255+
device_or_address = find_usb(custom_match=is_pybricks_usb)
256+
hub = PybricksHubUSB(device_or_address)
257+
258+
await hub.connect()
259+
# re-enable echoing of the hub's stdout
260+
hub._enable_line_handler = True
261+
hub.print_output = True
262+
return hub
263+
264+
response_options = [
265+
"Recompile and Run",
266+
"Recompile and Download",
267+
"Exit",
268+
]
269+
while True:
270+
try:
271+
response = await hub.race_power_button_press(
272+
questionary.select(
273+
"Would you like to re-compile your code?",
274+
response_options,
275+
default=(
276+
response_options[0]
277+
if args.start
278+
else response_options[1]
279+
),
280+
).ask_async()
281+
)
282+
with _get_script_path(args.file) as script_path:
283+
if response == response_options[0]:
284+
await hub.run(script_path, wait=True)
285+
elif response == response_options[1]:
286+
await hub.download(script_path)
287+
else:
288+
exit()
289+
290+
except HubPowerButtonPressedError:
291+
# This means the user pressed the button on the hub to re-start the
292+
# current program, so the menu was canceled and we are now printing
293+
# the hub stdout until the user program ends on the hub.
294+
try:
295+
await hub._wait_for_user_program_stop(5)
297296
except HubDisconnectError:
298-
# let terminal cool off before making a new prompt
299-
await asyncio.sleep(0.3)
300297
hub = await reconnect_hub()
301298

299+
except HubDisconnectError:
300+
# let terminal cool off before making a new prompt
301+
await asyncio.sleep(0.3)
302+
hub = await reconnect_hub()
303+
302304
finally:
303305
await hub.disconnect()
304306

pybricksdev/connections/pybricks.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,12 @@
6565
T = TypeVar("T")
6666

6767

68-
class HubDisconnectError(Exception):
68+
class HubDisconnectError(RuntimeError):
6969
"""Raise when a hub disconnect occurs."""
7070

7171

72-
class HubPowerButtonPressedError(Exception):
73-
"""Raise when the hub's power button is pressed."""
72+
class HubPowerButtonPressedError(RuntimeError):
73+
"""Raise when a task was canceled because the hub's power button was pressed."""
7474

7575

7676
class PybricksHub:
@@ -689,12 +689,13 @@ async def send_block(data: bytes) -> None:
689689
async def race_power_button_press(self, awaitable: Awaitable[T]) -> T:
690690
"""
691691
Races an awaitable against the user pressing the power button of the hub.
692-
693692
If the power button is pressed or the hub becomes disconnected before the awaitable is complete, a
694-
``RuntimeError`` is raised and the awaitable is canceled.
695-
693+
:class:`HubPowerButtonPressedError` or :class:`HubDisconnectError` is raised and the awaitable is canceled.
696694
Otherwise, the result of the awaitable is returned. If the awaitable
697695
raises an exception, that exception will be raised.
696+
The intended purpose of this function is to detect when
697+
the user manually starts a program on the hub. It is used instead of the program running flag
698+
because the hub can send info through stdout before we can detect a change in the program running flag.
698699
699700
Args:
700701
awaitable: Any awaitable such as a coroutine.
@@ -703,8 +704,8 @@ async def race_power_button_press(self, awaitable: Awaitable[T]) -> T:
703704
The result of the awaitable.
704705
705706
Raises:
706-
RuntimeError:
707-
Thrown if the hub's power button is pressed or the hub is disconnected.
707+
HubPowerButtonPressedError
708+
HubDisconnectError
708709
"""
709710
awaitable_task = asyncio.ensure_future(awaitable)
710711

@@ -724,7 +725,7 @@ def handle_power_button_press(status: StatusFlag):
724725

725726
with self.status_observable.subscribe(
726727
handle_power_button_press
727-
) and self.connection_state_observable.subscribe(handle_disconnect):
728+
), self.connection_state_observable.subscribe(handle_disconnect):
728729
done, pending = await asyncio.wait(
729730
{awaitable_task, power_button_press_task, disconnect_task},
730731
return_when=asyncio.FIRST_COMPLETED,
@@ -737,7 +738,7 @@ def handle_power_button_press(status: StatusFlag):
737738
raise HubPowerButtonPressedError(
738739
"the hub's power button was pressed during operation"
739740
)
740-
elif disconnect_task in done:
741+
if disconnect_task in done:
741742
raise HubDisconnectError("the hub was disconnected during operation")
742743
return awaitable_task.result()
743744

0 commit comments

Comments
 (0)