All of lore.kernel.org
 help / color / mirror / Atom feed
From: John Snow <jsnow@redhat.com>
To: qemu-devel@nongnu.org
Cc: "Kevin Wolf" <kwolf@redhat.com>,
	"Michael Roth" <michael.roth@amd.com>,
	"John Snow" <jsnow@redhat.com>, "Hanna Reitz" <hreitz@redhat.com>,
	"Peter Maydell" <peter.maydell@linaro.org>,
	"Cleber Rosa" <crosa@redhat.com>,
	qemu-block@nongnu.org, "Markus Armbruster" <armbru@redhat.com>,
	"Daniel P. Berrangé" <berrange@redhat.com>
Subject: [PULL 01/19] python: backport 'Change error classes to have better repr methods'
Date: Tue, 16 Sep 2025 12:23:46 -0400	[thread overview]
Message-ID: <20250916162404.9195-2-jsnow@redhat.com> (raw)
In-Reply-To: <20250916162404.9195-1-jsnow@redhat.com>

By passing all of the arguments to the base class and overriding the
__str__ method when we want a different "human readable" message that
isn't just printing the list of arguments, we can ensure that all custom
error classes have a reasonable __repr__ implementation.

In the case of ExecuteError, the pseudo-field that isn't actually
correlated to an input argument can be re-imagined as a read-only
property; this forces consistency in the class and makes the repr output
more obviously correct.

Signed-off-by: John Snow <jsnow@redhat.com>
cherry picked from commit python-qemu-qmp@afdb7893f3b34212da4259b7202973f9a8cb85b3
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
---
 python/qemu/qmp/error.py      |  7 +++++--
 python/qemu/qmp/message.py    | 12 ++++++------
 python/qemu/qmp/protocol.py   |  7 +++++--
 python/qemu/qmp/qmp_client.py | 20 +++++++++++++-------
 4 files changed, 29 insertions(+), 17 deletions(-)

diff --git a/python/qemu/qmp/error.py b/python/qemu/qmp/error.py
index 24ba4d50541..c87b078f620 100644
--- a/python/qemu/qmp/error.py
+++ b/python/qemu/qmp/error.py
@@ -44,7 +44,10 @@ class ProtocolError(QMPError):
 
     :param error_message: Human-readable string describing the error.
     """
-    def __init__(self, error_message: str):
-        super().__init__(error_message)
+    def __init__(self, error_message: str, *args: object):
+        super().__init__(error_message, *args)
         #: Human-readable error message, without any prefix.
         self.error_message: str = error_message
+
+    def __str__(self) -> str:
+        return self.error_message
diff --git a/python/qemu/qmp/message.py b/python/qemu/qmp/message.py
index f76ccc90746..c2e9dd0dd54 100644
--- a/python/qemu/qmp/message.py
+++ b/python/qemu/qmp/message.py
@@ -178,15 +178,15 @@ class DeserializationError(ProtocolError):
     :param raw: The raw `bytes` that prompted the failure.
     """
     def __init__(self, error_message: str, raw: bytes):
-        super().__init__(error_message)
+        super().__init__(error_message, raw)
         #: The raw `bytes` that were not understood as JSON.
         self.raw: bytes = raw
 
     def __str__(self) -> str:
-        return "\n".join([
+        return "\n".join((
             super().__str__(),
             f"  raw bytes were: {str(self.raw)}",
-        ])
+        ))
 
 
 class UnexpectedTypeError(ProtocolError):
@@ -197,13 +197,13 @@ class UnexpectedTypeError(ProtocolError):
     :param value: The deserialized JSON value that wasn't an object.
     """
     def __init__(self, error_message: str, value: object):
-        super().__init__(error_message)
+        super().__init__(error_message, value)
         #: The JSON value that was expected to be an object.
         self.value: object = value
 
     def __str__(self) -> str:
         strval = json.dumps(self.value, indent=2)
-        return "\n".join([
+        return "\n".join((
             super().__str__(),
             f"  json value was: {strval}",
-        ])
+        ))
diff --git a/python/qemu/qmp/protocol.py b/python/qemu/qmp/protocol.py
index a4ffdfad51b..86e588881b7 100644
--- a/python/qemu/qmp/protocol.py
+++ b/python/qemu/qmp/protocol.py
@@ -80,7 +80,7 @@ class ConnectError(QMPError):
     :param exc: The root-cause exception.
     """
     def __init__(self, error_message: str, exc: Exception):
-        super().__init__(error_message)
+        super().__init__(error_message, exc)
         #: Human-readable error string
         self.error_message: str = error_message
         #: Wrapped root cause exception
@@ -108,11 +108,14 @@ class StateError(QMPError):
     """
     def __init__(self, error_message: str,
                  state: Runstate, required: Runstate):
-        super().__init__(error_message)
+        super().__init__(error_message, state, required)
         self.error_message = error_message
         self.state = state
         self.required = required
 
+    def __str__(self) -> str:
+        return self.error_message
+
 
 F = TypeVar('F', bound=Callable[..., Any])  # pylint: disable=invalid-name
 
diff --git a/python/qemu/qmp/qmp_client.py b/python/qemu/qmp/qmp_client.py
index 2a817f9db33..a87fb565ab5 100644
--- a/python/qemu/qmp/qmp_client.py
+++ b/python/qemu/qmp/qmp_client.py
@@ -41,7 +41,7 @@ class _WrappedProtocolError(ProtocolError):
     :param exc: The root-cause exception.
     """
     def __init__(self, error_message: str, exc: Exception):
-        super().__init__(error_message)
+        super().__init__(error_message, exc)
         self.exc = exc
 
     def __str__(self) -> str:
@@ -76,15 +76,21 @@ class ExecuteError(QMPError):
     """
     def __init__(self, error_response: ErrorResponse,
                  sent: Message, received: Message):
-        super().__init__(error_response.error.desc)
+        super().__init__(error_response, sent, received)
         #: The sent `Message` that caused the failure
         self.sent: Message = sent
         #: The received `Message` that indicated failure
         self.received: Message = received
         #: The parsed error response
         self.error: ErrorResponse = error_response
-        #: The QMP error class
-        self.error_class: str = error_response.error.class_
+
+    @property
+    def error_class(self) -> str:
+        """The QMP error class"""
+        return self.error.error.class_
+
+    def __str__(self) -> str:
+        return self.error.error.desc
 
 
 class ExecInterruptedError(QMPError):
@@ -110,8 +116,8 @@ class _MsgProtocolError(ProtocolError):
     :param error_message: Human-readable string describing the error.
     :param msg: The QMP `Message` that caused the error.
     """
-    def __init__(self, error_message: str, msg: Message):
-        super().__init__(error_message)
+    def __init__(self, error_message: str, msg: Message, *args: object):
+        super().__init__(error_message, msg, *args)
         #: The received `Message` that caused the error.
         self.msg: Message = msg
 
@@ -150,7 +156,7 @@ class BadReplyError(_MsgProtocolError):
     :param sent: The message that was sent that prompted the error.
     """
     def __init__(self, error_message: str, msg: Message, sent: Message):
-        super().__init__(error_message, msg)
+        super().__init__(error_message, msg, sent)
         #: The sent `Message` that caused the failure
         self.sent = sent
 
-- 
2.51.0



  reply	other threads:[~2025-09-16 16:33 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-09-16 16:23 [PULL 00/19] Python patches John Snow
2025-09-16 16:23 ` John Snow [this message]
2025-09-16 16:23 ` [PULL 02/19] python: backport 'EventListener: add __repr__ method' John Snow
2025-09-16 16:23 ` [PULL 03/19] python: backport 'kick event queue on legacy event_pull()' John Snow
2025-09-16 16:23 ` [PULL 04/19] python: backport 'protocol: adjust logging name when changing client name' John Snow
2025-10-15  7:11   ` Thomas Huth
2025-10-22  0:37     ` John Snow
2025-09-16 16:23 ` [PULL 05/19] python: backport 'drop Python3.6 workarounds' John Snow
2025-09-16 16:23 ` [PULL 06/19] python: backport 'Use @asynciocontextmanager' John Snow
2025-09-16 16:23 ` [PULL 07/19] python: backport 'qmp-shell: add common_parser()' John Snow
2025-09-16 16:23 ` [PULL 08/19] python: backport 'feat: allow setting read buffer limit' John Snow
2025-09-16 16:23 ` [PULL 09/19] python: backport 'make require() preserve async-ness' John Snow
2025-09-16 16:23 ` [PULL 10/19] python: backport 'qmp-shell-wrap: handle missing binary gracefully' John Snow
2025-09-16 16:23 ` [PULL 11/19] python: backport 'qmp-tui: Do not crash if optional dependencies are not met' John Snow
2025-09-16 16:23 ` [PULL 12/19] python: backport 'Remove deprecated get_event_loop calls' John Snow
2025-09-16 16:23 ` [PULL 13/19] python: backport 'avoid creating additional event loops per thread' John Snow
2025-09-16 16:23 ` [PULL 14/19] python: synchronize qemu.qmp documentation John Snow
2025-09-16 16:24 ` [PULL 15/19] iotests: drop compat for old version context manager John Snow
2025-09-16 16:24 ` [PULL 16/19] python: ensure QEMUQtestProtocol closes its socket John Snow
2025-09-16 16:24 ` [PULL 17/19] iotests/147: ensure temporary sockets are closed before exiting John Snow
2025-09-16 16:24 ` [PULL 18/19] iotests/151: ensure subprocesses are cleaned up John Snow
2025-09-16 16:24 ` [PULL 19/19] iotests/check: always enable all python warnings John Snow
2025-09-16 18:20 ` [PULL 00/19] Python patches John Snow
2025-09-16 19:22 ` Richard Henderson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250916162404.9195-2-jsnow@redhat.com \
    --to=jsnow@redhat.com \
    --cc=armbru@redhat.com \
    --cc=berrange@redhat.com \
    --cc=crosa@redhat.com \
    --cc=hreitz@redhat.com \
    --cc=kwolf@redhat.com \
    --cc=michael.roth@amd.com \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-block@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.