[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH v2] Python3 Support for qmp.py
From: |
Daniel P. Berrange |
Subject: |
Re: [Qemu-devel] [PATCH v2] Python3 Support for qmp.py |
Date: |
Fri, 7 Jul 2017 12:01:24 +0100 |
User-agent: |
Mutt/1.8.0 (2017-02-23) |
On Fri, Jul 07, 2017 at 12:38:47AM +0530, Ishani Chugh wrote:
> This patch intends to make qmp.py compatible with both python2 and python3.
>
> * Python 3 does not have dict.has_key(key), use key in dict instead
> * Avoid line-based I/O since Python 2/3 have different character
> encoding behavior. Explicitly encode/decode JSON UTF-8.
> * Replace print by print function.
If you're going todo this, then you need to actually import the python3
compatible print function - not just call the python2 print statement
with brackets, as the semantics are different:
$ python2
>>> print("foo", "bar")
('foo', 'bar')
>>> from __future__ import print_function
>>> print("foo", "bar")
foo bar
Only the latter matches python3 semantics
>
> Signed-off-by: Ishani Chugh <address@hidden>
> ---
> scripts/qmp/qmp.py | 58
> ++++++++++++++++++++++++++++++++++--------------------
> 1 file changed, 37 insertions(+), 21 deletions(-)
>
> diff --git a/scripts/qmp/qmp.py b/scripts/qmp/qmp.py
> index 62d3651..58fb7d1 100644
> --- a/scripts/qmp/qmp.py
> +++ b/scripts/qmp/qmp.py
> @@ -42,6 +42,7 @@ class QEMUMonitorProtocol:
> self.__address = address
> self._debug = debug
> self.__sock = self.__get_sock()
> + self.__data = b""
> if server:
> self.__sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
> self.__sock.bind(self.__address)
> @@ -56,7 +57,7 @@ class QEMUMonitorProtocol:
>
> def __negotiate_capabilities(self):
> greeting = self.__json_read()
> - if greeting is None or not greeting.has_key('QMP'):
> + if greeting is None or 'QMP' not in greeting:
> raise QMPConnectError
> # Greeting seems ok, negotiate capabilities
> resp = self.cmd('qmp_capabilities')
> @@ -64,15 +65,28 @@ class QEMUMonitorProtocol:
> return greeting
> raise QMPCapabilitiesError
>
> + def __sock_readline(self):
> + while True:
> + ch = self.__sock.recv(1)
> + if ch is None:
> + if self.__data:
> + raise ValueError('socket closed mid-line')
> + return None
> + self.__data += ch
> + if ch == b'\n':
> + line = self.__data.decode('utf-8')
> + self.__data = b""
> + return line
> +
> def __json_read(self, only_event=False):
> while True:
> - data = self.__sockfile.readline()
> + data = self.__sock_readline()
So originally we could get back a "str" on python2, but now
we get a "str" (which is unicode) on python2, but "unicode"
on python2.
> if not data:
> return
> resp = json.loads(data)
This means the 'resp' now contains "unicode" data too on
python2 instead of 'str'.
This hopefully isn't a problem, but we certainly need to
make sure the iotests still pass on py2, as it could well
have a ripple effect in this respect. Have you run the
iotests with this change applied ?
> if 'event' in resp:
> if self._debug:
> - print >>sys.stderr, "QMP:<<< %s" % resp
> + print("QMP:<<< %s" % resp)
This is changing from printing to stderr, to printing to stdout
which is not desirable. Likewise all the similar changes below.
> self.__events.append(resp)
> if not only_event:
> continue
> @@ -87,10 +101,10 @@ class QEMUMonitorProtocol:
> @param wait (bool): block until an event is available.
> @param wait (float): If wait is a float, treat it as a timeout value.
>
> - @raise QMPTimeoutError: If a timeout float is provided and the
> timeout
> - period elapses.
> - @raise QMPConnectError: If wait is True but no events could be
> retrieved
> - or if some other error occurred.
> + @raise QMPTimeoutError: If a timeout float is provided and the
> + timeout period elapses.
> + @raise QMPConnectError: If wait is True but no events could be
> + retrieved or if some other error occurred.
> """
Don't mix whitespace changes in with other functional changes.
>
> # Check for new events regardless and pull them into the cache:
> @@ -98,9 +112,11 @@ class QEMUMonitorProtocol:
> try:
> self.__json_read()
> except socket.error as err:
> - if err[0] == errno.EAGAIN:
> + if err.errno == errno.EAGAIN:
> # No data available
> pass
> + else:
> + raise
> self.__sock.setblocking(1)
>
> # Wait for new events, if needed.
> @@ -128,7 +144,6 @@ class QEMUMonitorProtocol:
> @raise QMPCapabilitiesError if fails to negotiate capabilities
> """
> self.__sock.connect(self.__address)
> - self.__sockfile = self.__sock.makefile()
> if negotiate:
> return self.__negotiate_capabilities()
>
> @@ -143,7 +158,6 @@ class QEMUMonitorProtocol:
> """
> self.__sock.settimeout(15)
> self.__sock, _ = self.__sock.accept()
> - self.__sockfile = self.__sock.makefile()
> return self.__negotiate_capabilities()
>
> def cmd_obj(self, qmp_cmd):
> @@ -155,16 +169,17 @@ class QEMUMonitorProtocol:
> been closed
> """
> if self._debug:
> - print >>sys.stderr, "QMP:>>> %s" % qmp_cmd
> + print("QMP:>>> %s" % qmp_cmd)
> try:
> - self.__sock.sendall(json.dumps(qmp_cmd))
> + command = json.dumps(qmp_cmd)
> + self.__sock.sendall(command.encode('UTF-8'))
> except socket.error as err:
> - if err[0] == errno.EPIPE:
> + if err.errno == errno.EPIPE:
> return
> - raise socket.error(err)
> + raise
> resp = self.__json_read()
> if self._debug:
> - print >>sys.stderr, "QMP:<<< %s" % resp
> + print("QMP:<<< %s" % resp)
> return resp
>
> def cmd(self, name, args=None, id=None):
> @@ -175,7 +190,7 @@ class QEMUMonitorProtocol:
> @param args: command arguments (dict)
> @param id: command id (dict, list, string or int)
> """
> - qmp_cmd = { 'execute': name }
> + qmp_cmd = {'execute': name}
Again bogus whitespace changes
> if args:
> qmp_cmd['arguments'] = args
> if id:
> @@ -184,7 +199,7 @@ class QEMUMonitorProtocol:
>
> def command(self, cmd, **kwds):
> ret = self.cmd(cmd, kwds)
> - if ret.has_key('error'):
> + if 'error' in ret:
> raise Exception(ret['error']['desc'])
> return ret['return']
>
> @@ -197,8 +212,8 @@ class QEMUMonitorProtocol:
>
> @raise QMPTimeoutError: If a timeout float is provided and the
> timeout
> period elapses.
> - @raise QMPConnectError: If wait is True but no events could be
> retrieved
> - or if some other error occurred.
> + @raise QMPConnectError: If wait is True but no events could be
> + retrieved or if some other error occurred.
And again
>
> @return The first available QMP event, or None.
> """
> @@ -217,8 +232,8 @@ class QEMUMonitorProtocol:
>
> @raise QMPTimeoutError: If a timeout float is provided and the
> timeout
> period elapses.
> - @raise QMPConnectError: If wait is True but no events could be
> retrieved
> - or if some other error occurred.
> + @raise QMPConnectError: If wait is True but no events could be
> + retrieved or if some other error occurred.
Same
>
> @return The list of available QMP events.
> """
> @@ -245,3 +260,4 @@ class QEMUMonitorProtocol:
>
> def is_scm_available(self):
> return self.__sock.family == socket.AF_UNIX
> +
Adding trailing blank line to the file is bad.
Regards,
Daniel
--
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o- https://fstop138.berrange.com :|
|: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|