From e493903ce73a4766fbc64c042a394b97c1fcad43 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 19 May 2024 21:23:18 -1000 Subject: [PATCH 1/4] fix: clear exception flag on disconnect future if its also sent to handlers If we do not clear the exception retrieved flag on the disconnect future it will likely never be retrieved since wait_for_disconnect will never be called when the reply handler raises. --- src/dbus_fast/aio/message_bus.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/dbus_fast/aio/message_bus.py b/src/dbus_fast/aio/message_bus.py index 8b7bc288..d8e45836 100644 --- a/src/dbus_fast/aio/message_bus.py +++ b/src/dbus_fast/aio/message_bus.py @@ -1,5 +1,6 @@ import array import asyncio +import contextlib import logging import socket from collections import deque @@ -522,6 +523,8 @@ def _finalize(self, err: Optional[Exception] = None) -> None: except Exception: logging.warning("could not remove message writer", exc_info=True) + had_handlers = bool(self._method_return_handlers or self._user_message_handlers) + super()._finalize(err) if self._disconnect_future.done(): @@ -529,6 +532,14 @@ def _finalize(self, err: Optional[Exception] = None) -> None: if err and not self._user_disconnect: _future_set_exception(self._disconnect_future, err) + # If this happens during a reply the message handlers + # will have the exception set and wait_for_disconnect will + # never be called so we need to manually set the exception + # as retrieved to avoid asyncio warnings when the future + # is garbage collected. + if had_handlers: + with contextlib.suppress(Exception): + self._disconnect_future.exception() else: _future_set_result(self._disconnect_future, None) From 251d7ddeb29c38f205596f4527670f0b5f95d12b Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 19 May 2024 21:35:31 -1000 Subject: [PATCH 2/4] Update src/dbus_fast/aio/message_bus.py --- src/dbus_fast/aio/message_bus.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dbus_fast/aio/message_bus.py b/src/dbus_fast/aio/message_bus.py index d8e45836..10081d2d 100644 --- a/src/dbus_fast/aio/message_bus.py +++ b/src/dbus_fast/aio/message_bus.py @@ -532,7 +532,7 @@ def _finalize(self, err: Optional[Exception] = None) -> None: if err and not self._user_disconnect: _future_set_exception(self._disconnect_future, err) - # If this happens during a reply the message handlers + # If this happens during a reply, the message handlers # will have the exception set and wait_for_disconnect will # never be called so we need to manually set the exception # as retrieved to avoid asyncio warnings when the future From e359a6781818604ee82971ff1d99d6a981deb1ea Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 20 May 2024 10:41:06 -1000 Subject: [PATCH 3/4] fix: add test --- tests/test_aio_low_level.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/test_aio_low_level.py b/tests/test_aio_low_level.py index 587618dd..3ca981ae 100644 --- a/tests/test_aio_low_level.py +++ b/tests/test_aio_low_level.py @@ -44,6 +44,26 @@ async def test_standard_interfaces(): bus.disconnect() +@pytest.mark.asyncio +async def test_error_handling(): + bus = await MessageBus().connect() + msg = Message( + destination="org.freedesktop.DBus", + path="/org/freedesktop/DBus", + interface="org.freedesktop.DBus", + member="InvalidMember", + serial=bus.next_serial(), + ) + reply = await bus.call(msg) + + assert reply.message_type == MessageType.ERROR + assert reply.reply_serial == msg.serial + assert reply.signature == "as" + assert bus.unique_name in reply.body[0] + + bus.disconnect() + + @pytest.mark.asyncio async def test_sending_messages_between_buses(): bus1 = await MessageBus().connect() From 2b625b05fe33f585079345da15f9eb4ac1123857 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 20 May 2024 11:28:56 -1000 Subject: [PATCH 4/4] fix: test --- tests/test_aio_low_level.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/test_aio_low_level.py b/tests/test_aio_low_level.py index 3ca981ae..33352026 100644 --- a/tests/test_aio_low_level.py +++ b/tests/test_aio_low_level.py @@ -58,8 +58,7 @@ async def test_error_handling(): assert reply.message_type == MessageType.ERROR assert reply.reply_serial == msg.serial - assert reply.signature == "as" - assert bus.unique_name in reply.body[0] + assert reply.signature == "s" bus.disconnect()