From be68a79c523e7ff360a4f9914b41956b5f430d93 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 20 May 2024 11:37:31 -1000 Subject: [PATCH] fix: clear exception flag on disconnect future if its also sent to handlers (#281) --- src/dbus_fast/aio/message_bus.py | 11 +++++++++++ tests/test_aio_low_level.py | 19 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/dbus_fast/aio/message_bus.py b/src/dbus_fast/aio/message_bus.py index 8b7bc28..10081d2 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 @@ class MessageBus(BaseMessageBus): 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 @@ class MessageBus(BaseMessageBus): 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) diff --git a/tests/test_aio_low_level.py b/tests/test_aio_low_level.py index 587618d..3335202 100644 --- a/tests/test_aio_low_level.py +++ b/tests/test_aio_low_level.py @@ -44,6 +44,25 @@ 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 == "s" + + bus.disconnect() + + @pytest.mark.asyncio async def test_sending_messages_between_buses(): bus1 = await MessageBus().connect()