diff options
Diffstat (limited to 'python/qemu/qmp/__init__.py')
| -rw-r--r-- | python/qemu/qmp/__init__.py | 59 |
1 files changed, 48 insertions, 11 deletions
diff --git a/python/qemu/qmp/__init__.py b/python/qemu/qmp/__init__.py index 9606248a3d..376954cb6d 100644 --- a/python/qemu/qmp/__init__.py +++ b/python/qemu/qmp/__init__.py @@ -30,21 +30,30 @@ from typing import ( TextIO, Tuple, Type, + TypeVar, Union, cast, ) -# QMPMessage is a QMP Message of any kind. -# e.g. {'yee': 'haw'} +#: QMPMessage is an entire QMP message of any kind. +QMPMessage = Dict[str, Any] + +#: QMPReturnValue is the 'return' value of a command. +QMPReturnValue = object + +#: QMPObject is any object in a QMP message. +QMPObject = Dict[str, object] + +# QMPMessage can be outgoing commands or incoming events/returns. +# QMPReturnValue is usually a dict/json object, but due to QAPI's +# 'returns-whitelist', it can actually be anything. # -# QMPReturnValue is the inner value of return values only. -# {'return': {}} is the QMPMessage, +# {'return': {}} is a QMPMessage, # {} is the QMPReturnValue. -QMPMessage = Dict[str, Any] -QMPReturnValue = Dict[str, Any] -InternetAddrT = Tuple[str, str] + +InternetAddrT = Tuple[str, int] UnixAddrT = str SocketAddrT = Union[InternetAddrT, UnixAddrT] @@ -92,6 +101,12 @@ class QMPResponseError(QMPError): self.reply = reply +class QMPBadPortError(QMPError): + """ + Unable to parse socket address: Port was non-numerical. + """ + + class QEMUMonitorProtocol: """ Provide an API to connect to QEMU via QEMU Monitor Protocol (QMP) and then @@ -206,7 +221,9 @@ class QEMUMonitorProtocol: if ret is None: raise QMPConnectError("Error while reading from socket") - def __enter__(self) -> 'QEMUMonitorProtocol': + T = TypeVar('T') + + def __enter__(self: T) -> T: # Implement context manager enter function. return self @@ -219,6 +236,26 @@ class QEMUMonitorProtocol: # Implement context manager exit function. self.close() + @classmethod + def parse_address(cls, address: str) -> SocketAddrT: + """ + Parse a string into a QMP address. + + Figure out if the argument is in the port:host form. + If it's not, it's probably a file path. + """ + components = address.split(':') + if len(components) == 2: + try: + port = int(components[1]) + except ValueError: + msg = f"Bad port: '{components[1]}' in '{address}'." + raise QMPBadPortError(msg) from None + return (components[0], port) + + # Treat as filepath. + return address + def connect(self, negotiate: bool = True) -> Optional[QMPMessage]: """ Connect to the QMP Monitor and perform capabilities negotiation. @@ -271,8 +308,8 @@ class QEMUMonitorProtocol: return resp def cmd(self, name: str, - args: Optional[Dict[str, Any]] = None, - cmd_id: Optional[Any] = None) -> QMPMessage: + args: Optional[Dict[str, object]] = None, + cmd_id: Optional[object] = None) -> QMPMessage: """ Build a QMP command and send it to the QMP Monitor. @@ -287,7 +324,7 @@ class QEMUMonitorProtocol: qmp_cmd['id'] = cmd_id return self.cmd_obj(qmp_cmd) - def command(self, cmd: str, **kwds: Any) -> QMPReturnValue: + def command(self, cmd: str, **kwds: object) -> QMPReturnValue: """ Build and send a QMP command to the monitor, report errors if any """ |