On 5/14/20 7:53 AM, John Snow wrote:
> mypy and python type hints are not powerful enough to properly describe
> JSON messages in Python 3.6. The best we can do, generally, is describe
> them as Dict[str, Any].
>
> Add casts to coerce this type for static analysis; but do NOT enforce
> this type at runtime in any way.
>
> Note: Python 3.8 adds a TypedDict construct which allows for the
> description of more arbitrary Dictionary shapes. There is a third-party
> module, "Pydantic", which is compatible with 3.6 that can be used
> instead of the JSON library that parses JSON messages to fully-typed
> Python objects, and may be preferable in some cases.
>
> (That is well beyond the scope of this commit or series.)
>
> Signed-off-by: John Snow <jsnow@redhat.com>
> ---
> python/qemu/lib/qmp.py | 8 ++++++--
> 1 file changed, 6 insertions(+), 2 deletions(-)
>
> diff --git a/python/qemu/lib/qmp.py b/python/qemu/lib/qmp.py
> index 0036204218..e460234f2e 100644
> --- a/python/qemu/lib/qmp.py
> +++ b/python/qemu/lib/qmp.py
> @@ -13,6 +13,7 @@
> import logging
> from typing import (
> Any,
> + cast,
> Dict,
> Optional,
> TextIO,
> @@ -129,7 +130,10 @@ def __json_read(self, only_event=False):
> data = self.__sockfile.readline()
> if not data:
> return None
> - resp = json.loads(data)
> + # By definition, any JSON received from QMP is a QMPMessage,
> + # and we are asserting only at static analysis time that it
> + # has a particular shape.
> + resp = cast(QMPMessage, json.loads(data))
> if 'event' in resp:
> self.logger.debug("<<< %s", resp)
> self.__events.append(resp)
> @@ -261,7 +265,7 @@ def command(self, cmd, **kwds):
> ret = self.cmd(cmd, kwds)
> if 'error' in ret:
> raise QMPResponseError(ret)
> - return ret['return']
> + return cast(QMPReturnValue, ret['return'])
>
> def pull_event(self, wait=False):
> """
>
Acked-by: Philippe Mathieu-Daudé <philmd@redhat.com>