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 afdb7893f3b34212da4259b7202973f9a8cb85b3
---
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.50.1