From 63e77f0ce4a11b0e3f4ce8476a74cc6f4b76d52b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bojan=20Poto=C4=8Dnik?= Date: Thu, 22 Apr 2021 13:53:39 +0200 Subject: [PATCH] Add error description to BleakDBusError in addition to error name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Converting BleakDBusError to string now adds detailed description of the error, which can be very useful for debugging, as more than 12 different errors are reported under org.bluez.Error.Failed error name. Instead of bleak.exc.BleakDBusError: org.bluez.Error.Failed one now gets bleak.exc.BleakDBusError: org.bluez.Error.Failed (Operation failed with ATT error: 0x0e = Connection Rejected Due To Security Reasons) Some details are less useful, as example bleak.exc.BleakDBusError: org.bluez.Error.AuthenticationFailed becomes bleak.exc.BleakDBusError: org.bluez.Error.AuthenticationFailed (Authentication Failed) But looking at more possible error codes and their details (majority from BlueZ sources gdbus/object.c and src/gatt-client.c), it becomes clear that additional description of error can be very useful: org.freedesktop.DBus.Error.InvalidArgs org.freedesktop.DBus.Error.UnknownProperty No such interface '%s' No such property '%s' Invalid signature for '%s' Invalid argument type: '%c' Property '%s' is not readable Property '%s' is not writable No arguments given org.bluez.Error.Failed `strerror(-err)` Connect failed Not connected Invalid UUID Operation failed with ATT error: 0x%02x Failed to initiate write ... and many more Signed-off-by: Bojan Potočnik --- CHANGELOG.rst | 1 + bleak/backends/bluezdbus/utils.py | 2 +- bleak/exc.py | 25 +++++++++++++++++++++++-- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d5ea4138..50d8fc9e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -23,6 +23,7 @@ Changed * Added ``Programming Language :: Python :: 3.9`` classifier in ``setup.py`` * Deprecated ``BleakScanner.get_discovered_devices()`` async method. * Added capability to handle async functions as detection callbacks in ``BleakScanner``. +* Added error description in addition to error name when ``BleakDBusError`` is converted to string Fixed ~~~~~ diff --git a/bleak/backends/bluezdbus/utils.py b/bleak/backends/bluezdbus/utils.py index 537ef172..a4db0126 100644 --- a/bleak/backends/bluezdbus/utils.py +++ b/bleak/backends/bluezdbus/utils.py @@ -20,7 +20,7 @@ def assert_reply(reply: Message): AssentationError: if the message type is not ``MessageType.METHOD_RETURN`` """ if reply.message_type == MessageType.ERROR: - raise BleakDBusError(reply.error_name) + raise BleakDBusError(reply.error_name, reply.body) assert reply.message_type == MessageType.METHOD_RETURN diff --git a/bleak/exc.py b/bleak/exc.py index 1388d639..42feb02d 100644 --- a/bleak/exc.py +++ b/bleak/exc.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +from typing import Optional class BleakError(Exception): @@ -16,18 +17,38 @@ class BleakDotNetTaskError(BleakError): class BleakDBusError(BleakError): """Specialized exception type for D-Bus errors.""" - def __init__(self, dbus_error: str): + def __init__(self, dbus_error: str, error_body: list): """ Args: dbus_error (str): The D-Bus error, e.g. ``org.freedesktop.DBus.Error.UnknownObject``. + error_body (list): Body of the D-Bus error, sometimes containing error description or details. """ - super().__init__(dbus_error) + super().__init__(dbus_error, *error_body) @property def dbus_error(self) -> str: """Gets the D-Bus error name, e.g. ``org.freedesktop.DBus.Error.UnknownObject``.""" return self.args[0] + @property + def dbus_error_details(self) -> Optional[str]: + """Gets the optional D-Bus error details, e.g. 'Invalid UUID'.""" + if len(self.args) > 1: + details = self.args[1] + # Some error descriptions can be further parsed to be even more helpful + if "ATT error: 0x" in details: + more_detail = CONTROLLER_ERROR_CODES.get( + int(details.rsplit("x")[1], 16), "Unknown code" + ) + details += f" ({more_detail})" + return details + return None + + def __str__(self) -> str: + name = f"[{self.dbus_error}]" + details = self.dbus_error_details + return (name + " " + details) if details else name + CONTROLLER_ERROR_CODES = { 0x00: "Success",