qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: John Snow <jsnow@redhat.com>
To: qemu-devel@nongnu.org
Cc: Cleber Rosa <crosa@redhat.com>, John Snow <jsnow@redhat.com>,
	Markus Armbruster <armbru@redhat.com>,
	Eduardo Habkost <ehabkost@redhat.com>
Subject: [PATCH v2 24/72] scripts/qmp/qemu-ga-client: add mypy type hints
Date: Tue,  3 Nov 2020 19:35:14 -0500	[thread overview]
Message-ID: <20201104003602.1293560-25-jsnow@redhat.com> (raw)
In-Reply-To: <20201104003602.1293560-1-jsnow@redhat.com>

This script is in slightly rough shape, but it still works. A lot of
care went into its initial development. In good faith, I'm updating it
to the latest Python coding standards. If there is in interest in this
script, though, I'll be asking for a contributor to take care of it
further.

Signed-off-by: John Snow <jsnow@redhat.com>
---
 scripts/qmp/qemu-ga-client | 89 +++++++++++++++++++++-----------------
 1 file changed, 49 insertions(+), 40 deletions(-)

diff --git a/scripts/qmp/qemu-ga-client b/scripts/qmp/qemu-ga-client
index 59b91c78d884..3e617e7e7abe 100755
--- a/scripts/qmp/qemu-ga-client
+++ b/scripts/qmp/qemu-ga-client
@@ -44,10 +44,18 @@ import errno
 import os
 import random
 import sys
+from typing import (
+    Any,
+    Callable,
+    Dict,
+    Optional,
+    Sequence,
+)
 
 
 sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
 from qemu import qmp
+from qemu.qmp import SocketAddrT
 
 
 # This script has not seen many patches or careful attention in quite
@@ -58,18 +66,18 @@ from qemu import qmp
 
 
 class QemuGuestAgent(qmp.QEMUMonitorProtocol):
-    def __getattr__(self, name):
-        def wrapper(**kwds):
+    def __getattr__(self, name: str) -> Callable[..., Any]:
+        def wrapper(**kwds: object) -> object:
             return self.command('guest-' + name.replace('_', '-'), **kwds)
         return wrapper
 
 
 class QemuGuestAgentClient:
-    def __init__(self, address):
+    def __init__(self, address: SocketAddrT):
         self.qga = QemuGuestAgent(address)
         self.qga.connect(negotiate=False)
 
-    def sync(self, timeout=3):
+    def sync(self, timeout: Optional[float] = 3) -> None:
         # Avoid being blocked forever
         if not self.ping(timeout):
             raise EnvironmentError('Agent seems not alive')
@@ -79,9 +87,9 @@ class QemuGuestAgentClient:
             if isinstance(ret, int) and int(ret) == uid:
                 break
 
-    def __file_read_all(self, handle):
+    def __file_read_all(self, handle: int) -> bytes:
         eof = False
-        data = ''
+        data = b''
         while not eof:
             ret = self.qga.file_read(handle=handle, count=1024)
             _data = base64.b64decode(ret['buf-b64'])
@@ -89,7 +97,7 @@ class QemuGuestAgentClient:
             eof = ret['eof']
         return data
 
-    def read(self, path):
+    def read(self, path: str) -> bytes:
         handle = self.qga.file_open(path=path)
         try:
             data = self.__file_read_all(handle)
@@ -97,7 +105,7 @@ class QemuGuestAgentClient:
             self.qga.file_close(handle=handle)
         return data
 
-    def info(self):
+    def info(self) -> str:
         info = self.qga.info()
 
         msgs = []
@@ -113,14 +121,14 @@ class QemuGuestAgentClient:
         return '\n'.join(msgs)
 
     @classmethod
-    def __gen_ipv4_netmask(cls, prefixlen):
+    def __gen_ipv4_netmask(cls, prefixlen: int) -> str:
         mask = int('1' * prefixlen + '0' * (32 - prefixlen), 2)
         return '.'.join([str(mask >> 24),
                          str((mask >> 16) & 0xff),
                          str((mask >> 8) & 0xff),
                          str(mask & 0xff)])
 
-    def ifconfig(self):
+    def ifconfig(self) -> str:
         nifs = self.qga.network_get_interfaces()
 
         msgs = []
@@ -141,7 +149,7 @@ class QemuGuestAgentClient:
 
         return '\n'.join(msgs)
 
-    def ping(self, timeout):
+    def ping(self, timeout: Optional[float]) -> bool:
         self.qga.settimeout(timeout)
         try:
             self.qga.ping()
@@ -149,37 +157,40 @@ class QemuGuestAgentClient:
             return False
         return True
 
-    def fsfreeze(self, cmd):
+    def fsfreeze(self, cmd: str) -> object:
         if cmd not in ['status', 'freeze', 'thaw']:
             raise Exception('Invalid command: ' + cmd)
-
+        # Can be int (freeze, thaw) or GuestFsfreezeStatus (status)
         return getattr(self.qga, 'fsfreeze' + '_' + cmd)()
 
-    def fstrim(self, minimum=0):
-        return getattr(self.qga, 'fstrim')(minimum=minimum)
+    def fstrim(self, minimum: int) -> Dict[str, object]:
+        # returns GuestFilesystemTrimResponse
+        ret = getattr(self.qga, 'fstrim')(minimum=minimum)
+        assert isinstance(ret, dict)
+        return ret
 
-    def suspend(self, mode):
+    def suspend(self, mode: str) -> None:
         if mode not in ['disk', 'ram', 'hybrid']:
             raise Exception('Invalid mode: ' + mode)
 
         try:
             getattr(self.qga, 'suspend' + '_' + mode)()
             # On error exception will raise
-        except self.qga.timeout:
+        except TimeoutError:
             # On success command will timed out
             return
 
-    def shutdown(self, mode='powerdown'):
+    def shutdown(self, mode: str = 'powerdown') -> None:
         if mode not in ['powerdown', 'halt', 'reboot']:
             raise Exception('Invalid mode: ' + mode)
 
         try:
             self.qga.shutdown(mode=mode)
-        except self.qga.timeout:
-            return
+        except TimeoutError:
+            pass
 
 
-def _cmd_cat(client, args):
+def _cmd_cat(client: QemuGuestAgentClient, args: Sequence[str]) -> None:
     if len(args) != 1:
         print('Invalid argument')
         print('Usage: cat <file>')
@@ -187,7 +198,7 @@ def _cmd_cat(client, args):
     print(client.read(args[0]))
 
 
-def _cmd_fsfreeze(client, args):
+def _cmd_fsfreeze(client: QemuGuestAgentClient, args: Sequence[str]) -> None:
     usage = 'Usage: fsfreeze status|freeze|thaw'
     if len(args) != 1:
         print('Invalid argument')
@@ -201,13 +212,14 @@ def _cmd_fsfreeze(client, args):
     ret = client.fsfreeze(cmd)
     if cmd == 'status':
         print(ret)
-    elif cmd == 'freeze':
-        print("%d filesystems frozen" % ret)
-    else:
-        print("%d filesystems thawed" % ret)
+        return
 
+    assert isinstance(ret, int)
+    verb = 'frozen' if cmd == 'freeze' else 'thawed'
+    print(f"{ret:d} filesystems {verb}")
 
-def _cmd_fstrim(client, args):
+
+def _cmd_fstrim(client: QemuGuestAgentClient, args: Sequence[str]) -> None:
     if len(args) == 0:
         minimum = 0
     else:
@@ -215,28 +227,25 @@ def _cmd_fstrim(client, args):
     print(client.fstrim(minimum))
 
 
-def _cmd_ifconfig(client, args):
+def _cmd_ifconfig(client: QemuGuestAgentClient, args: Sequence[str]) -> None:
     assert not args
     print(client.ifconfig())
 
 
-def _cmd_info(client, args):
+def _cmd_info(client: QemuGuestAgentClient, args: Sequence[str]) -> None:
     assert not args
     print(client.info())
 
 
-def _cmd_ping(client, args):
-    if len(args) == 0:
-        timeout = 3
-    else:
-        timeout = float(args[0])
+def _cmd_ping(client: QemuGuestAgentClient, args: Sequence[str]) -> None:
+    timeout = 3.0 if len(args) == 0 else float(args[0])
     alive = client.ping(timeout)
     if not alive:
         print("Not responded in %s sec" % args[0])
         sys.exit(1)
 
 
-def _cmd_suspend(client, args):
+def _cmd_suspend(client: QemuGuestAgentClient, args: Sequence[str]) -> None:
     usage = 'Usage: suspend disk|ram|hybrid'
     if len(args) != 1:
         print('Less argument')
@@ -249,7 +258,7 @@ def _cmd_suspend(client, args):
     client.suspend(args[0])
 
 
-def _cmd_shutdown(client, args):
+def _cmd_shutdown(client: QemuGuestAgentClient, args: Sequence[str]) -> None:
     assert not args
     client.shutdown()
 
@@ -257,12 +266,12 @@ def _cmd_shutdown(client, args):
 _cmd_powerdown = _cmd_shutdown
 
 
-def _cmd_halt(client, args):
+def _cmd_halt(client: QemuGuestAgentClient, args: Sequence[str]) -> None:
     assert not args
     client.shutdown('halt')
 
 
-def _cmd_reboot(client, args):
+def _cmd_reboot(client: QemuGuestAgentClient, args: Sequence[str]) -> None:
     assert not args
     client.shutdown('reboot')
 
@@ -270,7 +279,7 @@ def _cmd_reboot(client, args):
 commands = [m.replace('_cmd_', '') for m in dir() if '_cmd_' in m]
 
 
-def send_command(address, cmd, args):
+def send_command(address: str, cmd: str, args: Sequence[str]) -> None:
     if not os.path.exists(address):
         print('%s not found' % address)
         sys.exit(1)
@@ -296,7 +305,7 @@ def send_command(address, cmd, args):
     globals()['_cmd_' + cmd](client, args)
 
 
-def main():
+def main() -> None:
     address = os.environ.get('QGA_CLIENT_ADDRESS')
 
     parser = argparse.ArgumentParser()
-- 
2.26.2



  parent reply	other threads:[~2020-11-04  0:48 UTC|newest]

Thread overview: 73+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-11-04  0:34 [PATCH v2 00/72] python: move scripts/qmp to python/qemu/qmp John Snow
2020-11-04  0:34 ` [PATCH v2 01/72] python/qmp: Add qom script rewrites John Snow
2020-11-04  0:34 ` [PATCH v2 02/72] python/qmp: add qom script entry points John Snow
2020-11-04  0:34 ` [PATCH v2 03/72] scripts/qmp: redirect qom-xxx scripts to python/qemu/qmp/ John Snow
2020-11-04  0:34 ` [PATCH v2 04/72] scripts/qom-fuse: apply isort rules John Snow
2020-11-04  0:34 ` [PATCH v2 05/72] scripts/qom-fuse: apply flake8 rules John Snow
2020-11-04  0:34 ` [PATCH v2 06/72] python: Add 'fh' to known-good variable names John Snow
2020-11-04  0:34 ` [PATCH v2 07/72] scripts/qom-fuse: Apply pylint rules John Snow
2020-11-04  0:34 ` [PATCH v2 08/72] scripts/qom-fuse: Add docstrings John Snow
2020-11-04  0:34 ` [PATCH v2 09/72] scripts/qom-fuse: Convert to QOMCommand John Snow
2020-11-04  0:35 ` [PATCH v2 10/72] scripts/qom-fuse: use QOMCommand.qom_list() John Snow
2020-11-04  0:35 ` [PATCH v2 11/72] scripts/qom-fuse: ensure QOMFuse.read always returns bytes John Snow
2020-11-04  0:35 ` [PATCH v2 12/72] scripts/qom-fuse: add static type hints John Snow
2020-11-04  0:35 ` [PATCH v2 13/72] scripts/qom-fuse: move to python/qemu/qmp/qom_fuse.py John Snow
2020-11-04  0:35 ` [PATCH v2 14/72] scripts/qom-fuse: add redirection shim to python/qemu/qmp/qom-fuse.py John Snow
2020-11-04  0:35 ` [PATCH v2 15/72] python: add fuse command to 'qom' tools John Snow
2020-11-04  0:35 ` [PATCH v2 16/72] python: add optional fuse dependency John Snow
2020-11-04  0:35 ` [PATCH v2 17/72] scripts/qemu-ga-client: apply isort rules John Snow
2020-11-04  0:35 ` [PATCH v2 18/72] scripts/qemu-ga-client: apply (most) flake8 rules John Snow
2020-11-04  0:35 ` [PATCH v2 19/72] scripts/qemu-ga-client: Fix exception handling John Snow
2020-11-04  0:35 ` [PATCH v2 20/72] scripts/qemu-ga-client: replace deprecated optparse with argparse John Snow
2020-11-04  0:35 ` [PATCH v2 21/72] scripts/qemu-ga-client: add module docstring John Snow
2020-11-04  0:35 ` [PATCH v2 22/72] scripts/qemu-ga-client: apply (most) pylint rules John Snow
2020-11-04  0:35 ` [PATCH v2 23/72] python/qmp: Correct type of QMPReturnValue John Snow
2020-11-04  0:35 ` John Snow [this message]
2020-11-04  0:35 ` [PATCH v2 25/72] scripts/qemu-ga-client: move to python/qemu/qmp/qemu_ga_client.py John Snow
2020-11-04  0:35 ` [PATCH v2 26/72] python/qemu-ga-client: add entry point John Snow
2020-11-04  0:35 ` [PATCH v2 27/72] scripts/qemu-ga-client: Add forwarder stub John Snow
2020-11-04  0:35 ` [PATCH v2 28/72] scripts/qmp-shell: apply isort rules John Snow
2020-11-04  0:35 ` [PATCH v2 29/72] scripts/qmp-shell: Apply flake8 rules John Snow
2020-11-04  0:35 ` [PATCH v2 30/72] scripts/qmp-shell: fix show_banner signature John Snow
2020-11-04  0:35 ` [PATCH v2 31/72] scripts/qmp-shell: fix exception handling John Snow
2020-11-04  0:35 ` [PATCH v2 32/72] scripts/qmp-shell: fix connect method signature John Snow
2020-11-04  0:35 ` [PATCH v2 33/72] scripts/qmp-shell: remove shadowed variable from _print() John Snow
2020-11-04  0:35 ` [PATCH v2 34/72] scripts/qmp-shell: use @classmethod where appropriate John Snow
2020-11-04  0:35 ` [PATCH v2 35/72] scripts/qmp-shell: Use python3-style super() John Snow
2020-11-04  0:35 ` [PATCH v2 36/72] scripts/qmp-shell: declare verbose in __init__ John Snow
2020-11-04  0:35 ` [PATCH v2 37/72] scripts/qmp-shell: use triple-double-quote docstring style John Snow
2020-11-04  0:35 ` [PATCH v2 38/72] scripts/qmp-shell: ignore visit_Name name John Snow
2020-11-04  0:35 ` [PATCH v2 39/72] scripts/qmp-shell: make QMPCompleter returns explicit John Snow
2020-11-04  0:35 ` [PATCH v2 40/72] scripts/qmp-shell: rename one and two-letter variables John Snow
2020-11-04  0:35 ` [PATCH v2 41/72] scripts/qmp-shell: fix shell history exception handling John Snow
2020-11-04  0:35 ` [PATCH v2 42/72] scripts/qmp-shell: explicitly chain exception context John Snow
2020-11-04  0:35 ` [PATCH v2 43/72] scripts/qmp-shell: remove if-raise-else patterns John Snow
2020-11-04  0:35 ` [PATCH v2 44/72] scripts/qmp-shell: use isinstance() instead of type() John Snow
2020-11-04  0:35 ` [PATCH v2 45/72] scripts/qmp-shell: use argparse John Snow
2020-11-04  0:35 ` [PATCH v2 46/72] python/qmp: Fix type of SocketAddrT John Snow
2020-11-04  0:35 ` [PATCH v2 47/72] python/qmp: add parse_address classmethod John Snow
2020-11-04  0:35 ` [PATCH v2 48/72] scripts/qmp-shell: Add pretty attribute to HMP shell John Snow
2020-11-04  0:35 ` [PATCH v2 49/72] scripts/qmp-shell: Make verbose a public attribute John Snow
2020-11-04  0:35 ` [PATCH v2 50/72] scripts/qmp-shell: move get_prompt() to prompt property John Snow
2020-11-04  0:35 ` [PATCH v2 51/72] scripts/qmp-shell: remove prompt argument from read_exec_command John Snow
2020-11-04  0:35 ` [PATCH v2 52/72] scripts/qmp-shell: move the REPL functionality into QMPShell John Snow
2020-11-04  0:35 ` [PATCH v2 53/72] scripts/qmp-shell: Fix "FuzzyJSON" parser John Snow
2020-11-04  0:35 ` [PATCH v2 54/72] scripts/qmp-shell: refactor QMPCompleter John Snow
2020-11-04  0:35 ` [PATCH v2 55/72] scripts/qmp-shell: initialize completer early John Snow
2020-11-04  0:35 ` [PATCH v2 56/72] python/qmp: add QMPObject type alias John Snow
2020-11-04  0:35 ` [PATCH v2 57/72] scripts/qmp-shell: add mypy types John Snow
2020-11-04  0:35 ` [PATCH v2 58/72] scripts/qmp-shell: Accept SocketAddrT instead of string John Snow
2020-11-04  0:35 ` [PATCH v2 59/72] scripts/qmp-shell: unprivatize 'pretty' property John Snow
2020-11-04  0:35 ` [PATCH v2 60/72] python/qmp: return generic type from context manager John Snow
2020-11-04  0:35 ` [PATCH v2 61/72] scripts/qmp-shell: Use context manager instead of atexit John Snow
2020-11-04  0:35 ` [PATCH v2 62/72] scripts/qmp-shell: use logging to show warnings John Snow
2020-11-04  0:35 ` [PATCH v2 63/72] scripts/qmp-shell: remove TODO John Snow
2020-11-04  0:35 ` [PATCH v2 64/72] scripts/qmp-shell: Fix empty-transaction invocation John Snow
2020-11-04  0:35 ` [PATCH v2 65/72] scripts/qmp-shell: Remove too-broad-exception John Snow
2020-11-04  0:35 ` [PATCH v2 66/72] scripts/qmp-shell: convert usage comment to docstring John Snow
2020-11-04  0:35 ` [PATCH v2 67/72] scripts/qmp-shell: remove double-underscores John Snow
2020-11-04  0:35 ` [PATCH v2 68/72] scripts/qmp-shell: make QMPShellError inherit QMPError John Snow
2020-11-04  0:35 ` [PATCH v2 69/72] scripts/qmp-shell: add docstrings John Snow
2020-11-04  0:36 ` [PATCH v2 70/72] scripts/qmp-shell: move to python/qemu/qmp/qmp_shell.py John Snow
2020-11-04  0:36 ` [PATCH v2 71/72] python: add qmp-shell entry point John Snow
2020-11-04  0:36 ` [PATCH v2 72/72] scripts/qmp-shell: add redirection shim John Snow

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=20201104003602.1293560-25-jsnow@redhat.com \
    --to=jsnow@redhat.com \
    --cc=armbru@redhat.com \
    --cc=crosa@redhat.com \
    --cc=ehabkost@redhat.com \
    --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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).