From 93e9987efa16f5df83b0ae948d724d6ae1c3cfd2 Mon Sep 17 00:00:00 2001 From: Nicolas Schodet Date: Sat, 16 Mar 2024 11:56:34 +0100 Subject: [PATCH] Add specific errors subclasses for message_read When reading a message queue, it is useful to make the distinction between several possible errors. Add DirectProtocolError exception subclasses: NoActiveProgramError and EmptyMailboxError. Also update stop_program and get_current_program_name documentation to reflect the change. This is backward compatible as they are subclasses of the original error exceptions. --- docs/migration.rst | 2 ++ nxt/brick.py | 7 ++++--- nxt/error.py | 12 ++++++++++++ nxt/telegram.py | 4 ++-- tests/test_brick.py | 10 ++++++++++ 5 files changed, 30 insertions(+), 5 deletions(-) diff --git a/docs/migration.rst b/docs/migration.rst index ce7df59..b5cbb0d 100644 --- a/docs/migration.rst +++ b/docs/migration.rst @@ -181,6 +181,8 @@ From :mod:`nxt.error`: :exc:`DirectProtocolError` and :exc:`SystemProtocolError`. - :exc:`!FileNotFound` has been renamed to :exc:`FileNotFoundError`. - :exc:`!ModuleNotFound` has been renamed to :exc:`ModuleNotFoundError`. +- New :exc:`EmptyMailboxError` and :exc:`NoActiveProgramError` have been added + as subclasses of :exc:`DirectProtocolError`. Sensors: diff --git a/nxt/brick.py b/nxt/brick.py index f365238..034d93a 100644 --- a/nxt/brick.py +++ b/nxt/brick.py @@ -342,7 +342,7 @@ def start_program(self, name): def stop_program(self): """Stop the running program on the brick. - :raises nxt.error.DirectProtocolError: When no program is running. + :raises nxt.error.NoActiveProgramError: When no program is running. """ tgram = Telegram(Opcode.DIRECT_STOP_PROGRAM) self._cmd(tgram) @@ -655,7 +655,7 @@ def get_current_program_name(self): :return: Program file name :rtype: str - :raises nxt.error.DirectProtocolError: When no program is running. + :raises nxt.error.NoActiveProgramError: When no program is running. """ tgram = Telegram(Opcode.DIRECT_GET_CURR_PROGRAM) tgram = self._cmd(tgram) @@ -670,7 +670,8 @@ def message_read(self, remote_inbox, local_inbox, remove): :param bool remove: Whether to remove the message from the mailbox. :return: The read message. :rtype: bytes - :raises nxt.error.DirectProtocolError: When mailbox is empty. + :raises nxt.error.EmptyMailboxError: When mailbox is empty. + :raises nxt.error.NoActiveProgramError: When no program is running. """ tgram = Telegram(Opcode.DIRECT_MESSAGE_READ) tgram.add_u8(remote_inbox) diff --git a/nxt/error.py b/nxt/error.py index 41a89c5..77f3c62 100644 --- a/nxt/error.py +++ b/nxt/error.py @@ -50,12 +50,24 @@ class DirectProtocolError(ProtocolError): pass +class EmptyMailboxError(DirectProtocolError): + """Raised when trying to read from empty mailbox.""" + + pass + + class I2CError(DirectProtocolError): """Raised on I2C error on a sensor port.""" pass +class NoActiveProgramError(DirectProtocolError): + """Raised when no program is running.""" + + pass + + class I2CPendingError(I2CError): """Raised when an I2C transaction on a sensor port is still in progress.""" diff --git a/nxt/telegram.py b/nxt/telegram.py index 6acd5e2..1b20b40 100644 --- a/nxt/telegram.py +++ b/nxt/telegram.py @@ -88,7 +88,7 @@ def is_system(self): CODES = { 0x00: None, 0x20: nxt.error.I2CPendingError("pending communication transaction in progress"), - 0x40: nxt.error.DirectProtocolError("specified mailbox queue is empty"), + 0x40: nxt.error.EmptyMailboxError("specified mailbox queue is empty"), 0x81: nxt.error.SystemProtocolError("no more handles"), 0x82: nxt.error.SystemProtocolError("no space"), 0x83: nxt.error.SystemProtocolError("no more files"), @@ -118,7 +118,7 @@ def is_system(self): 0xDE: nxt.error.DirectProtocolError("no free memory in communication buffer"), 0xDF: nxt.error.DirectProtocolError("specified channel/connection is not valid"), 0xE0: nxt.error.I2CError("specified channel/connection not configured or busy"), - 0xEC: nxt.error.DirectProtocolError("no active program"), + 0xEC: nxt.error.NoActiveProgramError("no active program"), 0xED: nxt.error.DirectProtocolError("illegal size specified"), 0xEE: nxt.error.DirectProtocolError("illegal mailbox queue ID specified"), 0xEF: nxt.error.DirectProtocolError( diff --git a/tests/test_brick.py b/tests/test_brick.py index db40440..7567b50 100644 --- a/tests/test_brick.py +++ b/tests/test_brick.py @@ -303,6 +303,11 @@ def test_stop_program(self, sock, brick): brick.stop_program() assert sock.mock_calls == sent_recved(bytes.fromhex("0001")) + def test_stop_program_fail(self, sock, brick): + sock.recv.return_value = bytes.fromhex("0201ec") + with pytest.raises(nxt.error.NoActiveProgramError): + brick.stop_program() + def test_play_sound_file(self, sock, brick): brick.play_sound_file(True, "test.rso") assert sock.mock_calls == sent(bytes.fromhex("8002 01") + test_rso_bin) @@ -463,6 +468,11 @@ def test_message_read(self, sock, brick): assert local_inbox == 0 assert message == bytes.fromhex("21222324252627") + def test_message_read_fail(self, sock, brick): + sock.recv.return_value = bytes.fromhex("021340 00 00") + bytes(59) + with pytest.raises(nxt.error.EmptyMailboxError): + local_inbox, message = brick.message_read(10, 0, True) + class TestFilesModules: """Test nxt.brick files & modules access."""