All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/10] Python: Remove synchronous QMP library
@ 2022-03-21 21:08 John Snow
  2022-03-21 21:08 ` [PATCH 01/10] python/aqmp: add explicit GPLv2 license to legacy.py John Snow
                   ` (9 more replies)
  0 siblings, 10 replies; 25+ messages in thread
From: John Snow @ 2022-03-21 21:08 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Vladimir Sementsov-Ogievskiy, Beraldo Leal,
	qemu-block, Markus Armbruster, Hanna Reitz, Cleber Rosa,
	John Snow

Based-On: <20220321203315.909411-1-jsnow@redhat.com>
GitLab: https://gitlab.com/jsnow/qemu/-/tree/python-qmp-legacy-switch-pt1c
CI: https://gitlab.com/jsnow/qemu/-/pipelines/497561638

This series finalizes swapping out the old QMP library for the new
one. It's been through about two release cycles now, it's time.

John Snow (10):
  python/aqmp: add explicit GPLv2 license to legacy.py
  python/aqmp: relicense as GPLv2+
  python: temporarily silence pylint duplicate-code warnings
  python/aqmp: take QMPBadPortError and parse_address from qemu.qmp
  python/aqmp: fully separate from qmp.QEMUMonitorProtocol
  python/aqmp: copy qmp docstrings to qemu.aqmp.legacy
  python: remove the old QMP package
  python: re-enable pylint duplicate-code warnings
  python: rename qemu.aqmp to qemu.qmp
  python: rename 'aqmp-tui' to 'qmp-tui'

 python/README.rst                             |   2 +-
 python/qemu/qmp/README.rst                    |   9 -
 python/qemu/aqmp/__init__.py                  |  59 ---
 python/qemu/aqmp/legacy.py                    | 177 -------
 python/qemu/aqmp/py.typed                     |   0
 python/qemu/machine/machine.py                |   4 +-
 python/qemu/machine/qtest.py                  |   2 +-
 python/qemu/qmp/__init__.py                   | 445 ++----------------
 python/qemu/{aqmp => qmp}/error.py            |   0
 python/qemu/{aqmp => qmp}/events.py           |   2 +-
 python/qemu/qmp/legacy.py                     | 321 +++++++++++++
 python/qemu/{aqmp => qmp}/message.py          |   0
 python/qemu/{aqmp => qmp}/models.py           |   0
 python/qemu/{aqmp => qmp}/protocol.py         |   4 +-
 python/qemu/{aqmp => qmp}/qmp_client.py       |  16 +-
 python/qemu/{aqmp => qmp}/qmp_shell.py        |   4 +-
 .../qemu/{aqmp/aqmp_tui.py => qmp/qmp_tui.py} |  15 +-
 python/qemu/{aqmp => qmp}/util.py             |   0
 python/qemu/utils/qemu_ga_client.py           |   4 +-
 python/qemu/utils/qom.py                      |   2 +-
 python/qemu/utils/qom_common.py               |   4 +-
 python/qemu/utils/qom_fuse.py                 |   2 +-
 python/setup.cfg                              |  11 +-
 python/tests/protocol.py                      |  14 +-
 scripts/cpu-x86-uarch-abi.py                  |   2 +-
 scripts/device-crash-test                     |   4 +-
 scripts/qmp/qmp-shell                         |   2 +-
 scripts/qmp/qmp-shell-wrap                    |   2 +-
 scripts/render_block_graph.py                 |   4 +-
 scripts/simplebench/bench_block_job.py        |   2 +-
 tests/qemu-iotests/iotests.py                 |   2 +-
 tests/qemu-iotests/tests/mirror-top-perms     |   2 +-
 32 files changed, 414 insertions(+), 703 deletions(-)
 delete mode 100644 python/qemu/qmp/README.rst
 delete mode 100644 python/qemu/aqmp/__init__.py
 delete mode 100644 python/qemu/aqmp/legacy.py
 delete mode 100644 python/qemu/aqmp/py.typed
 rename python/qemu/{aqmp => qmp}/error.py (100%)
 rename python/qemu/{aqmp => qmp}/events.py (99%)
 create mode 100644 python/qemu/qmp/legacy.py
 rename python/qemu/{aqmp => qmp}/message.py (100%)
 rename python/qemu/{aqmp => qmp}/models.py (100%)
 rename python/qemu/{aqmp => qmp}/protocol.py (99%)
 rename python/qemu/{aqmp => qmp}/qmp_client.py (97%)
 rename python/qemu/{aqmp => qmp}/qmp_shell.py (99%)
 rename python/qemu/{aqmp/aqmp_tui.py => qmp/qmp_tui.py} (98%)
 rename python/qemu/{aqmp => qmp}/util.py (100%)

-- 
2.34.1




^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 01/10] python/aqmp: add explicit GPLv2 license to legacy.py
  2022-03-21 21:08 [PATCH 00/10] Python: Remove synchronous QMP library John Snow
@ 2022-03-21 21:08 ` John Snow
  2022-03-23 21:47   ` John Snow
  2022-03-21 21:08 ` [PATCH 02/10] python/aqmp: relicense as GPLv2+ John Snow
                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 25+ messages in thread
From: John Snow @ 2022-03-21 21:08 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Vladimir Sementsov-Ogievskiy, Beraldo Leal,
	qemu-block, Markus Armbruster, Hanna Reitz, Cleber Rosa,
	John Snow

The legacy.py module is heavily based on the QMP module by Luiz
Capitulino (et al) which is licensed as explicit GPLv2-only. The async
QMP package is currently licensed similarly, but I intend to relicense
the async package to the more flexible GPLv2+.

In preparation for that change, make the license on legacy.py explicit.

Signed-off-by: John Snow <jsnow@redhat.com>
---
 python/qemu/aqmp/legacy.py | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/python/qemu/aqmp/legacy.py b/python/qemu/aqmp/legacy.py
index 46026e9fdc..f86cb29804 100644
--- a/python/qemu/aqmp/legacy.py
+++ b/python/qemu/aqmp/legacy.py
@@ -4,6 +4,17 @@
 This class pretends to be qemu.qmp.QEMUMonitorProtocol.
 """
 
+#
+# Copyright (C) 2009-2022 Red Hat Inc.
+#
+# Authors:
+#  Luiz Capitulino <lcapitulino@redhat.com>
+#  John Snow <jsnow@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2.  See
+# the COPYING file in the top-level directory.
+#
+
 import asyncio
 from typing import (
     Any,
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 02/10] python/aqmp: relicense as GPLv2+
  2022-03-21 21:08 [PATCH 00/10] Python: Remove synchronous QMP library John Snow
  2022-03-21 21:08 ` [PATCH 01/10] python/aqmp: add explicit GPLv2 license to legacy.py John Snow
@ 2022-03-21 21:08 ` John Snow
  2022-03-21 21:08 ` [PATCH 03/10] python: temporarily silence pylint duplicate-code warnings John Snow
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 25+ messages in thread
From: John Snow @ 2022-03-21 21:08 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Vladimir Sementsov-Ogievskiy, Beraldo Leal,
	qemu-block, Markus Armbruster, Hanna Reitz, Cleber Rosa,
	John Snow

I am the sole author of all of the async QMP code (python/qemu/aqmp)
with the following exceptions:

python/qemu/aqmp/qmp_shell.py and python/qemu/aqmp/legacy.py were
written by Luiz Capitulino (et al) and are already licensed separately
as GPLv2 (only).

aqmp_tui.py was written by Niteesh Babu G S and is already licensed as GPLv2+.

I wish to relicense as GPLv2+ in order to provide as much flexibility as
I reasonably can, while retaining a strong copyleft license. It is my
belief that GPLv2+ is a suitable license for the Python ecosystem that
aligns with the goals and philosophy of the QEMU project.

Signed-off-by: John Snow <jsnow@redhat.com>
---
 python/qemu/aqmp/__init__.py | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/python/qemu/aqmp/__init__.py b/python/qemu/aqmp/__init__.py
index 4c22c38079..2e4478ac05 100644
--- a/python/qemu/aqmp/__init__.py
+++ b/python/qemu/aqmp/__init__.py
@@ -11,15 +11,15 @@
 managing QMP events.
 """
 
-# Copyright (C) 2020, 2021 John Snow for Red Hat, Inc.
+# Copyright (C) 2020-2022 John Snow for Red Hat, Inc.
 #
 # Authors:
 #  John Snow <jsnow@redhat.com>
 #
 # Based on earlier work by Luiz Capitulino <lcapitulino@redhat.com>.
 #
-# This work is licensed under the terms of the GNU GPL, version 2.  See
-# the COPYING file in the top-level directory.
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
 
 import logging
 
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 03/10] python: temporarily silence pylint duplicate-code warnings
  2022-03-21 21:08 [PATCH 00/10] Python: Remove synchronous QMP library John Snow
  2022-03-21 21:08 ` [PATCH 01/10] python/aqmp: add explicit GPLv2 license to legacy.py John Snow
  2022-03-21 21:08 ` [PATCH 02/10] python/aqmp: relicense as GPLv2+ John Snow
@ 2022-03-21 21:08 ` John Snow
  2022-03-21 21:08 ` [PATCH 04/10] python/aqmp: take QMPBadPortError and parse_address from qemu.qmp John Snow
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 25+ messages in thread
From: John Snow @ 2022-03-21 21:08 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Vladimir Sementsov-Ogievskiy, Beraldo Leal,
	qemu-block, Markus Armbruster, Hanna Reitz, Cleber Rosa,
	John Snow

The next several commits copy some code from qemu.qmp to qemu.aqmp, then
delete qemu.qmp. In the interim, to prevent test failures, the duplicate
code detection needs to be silenced to prevent bisect problems with CI
testing.

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
---
 python/setup.cfg | 1 +
 1 file changed, 1 insertion(+)

diff --git a/python/setup.cfg b/python/setup.cfg
index 241f243e8b..cdeced44d2 100644
--- a/python/setup.cfg
+++ b/python/setup.cfg
@@ -119,6 +119,7 @@ disable=consider-using-f-string,
         too-many-function-args,  # mypy handles this with less false positives.
         too-many-instance-attributes,
         no-member,  # mypy also handles this better.
+        duplicate-code,  # To be removed by the end of this patch series.
 
 [pylint.basic]
 # Good variable names which should always be accepted, separated by a comma.
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 04/10] python/aqmp: take QMPBadPortError and parse_address from qemu.qmp
  2022-03-21 21:08 [PATCH 00/10] Python: Remove synchronous QMP library John Snow
                   ` (2 preceding siblings ...)
  2022-03-21 21:08 ` [PATCH 03/10] python: temporarily silence pylint duplicate-code warnings John Snow
@ 2022-03-21 21:08 ` John Snow
  2022-03-21 21:08 ` [PATCH 05/10] python/aqmp: fully separate from qmp.QEMUMonitorProtocol John Snow
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 25+ messages in thread
From: John Snow @ 2022-03-21 21:08 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Vladimir Sementsov-Ogievskiy, Beraldo Leal,
	qemu-block, Markus Armbruster, Hanna Reitz, Cleber Rosa,
	John Snow

Shift these definitions over from the qmp package to the async qmp
package.

(Licensing: this is a lateral move, from GPLv2 (only) to GPLv2 (only))

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Beraldo Leal <bleal@redhat.com>
---
 python/qemu/aqmp/aqmp_tui.py |  3 +--
 python/qemu/aqmp/legacy.py   | 30 ++++++++++++++++++++++++++----
 python/qemu/qmp/__init__.py  | 26 --------------------------
 3 files changed, 27 insertions(+), 32 deletions(-)

diff --git a/python/qemu/aqmp/aqmp_tui.py b/python/qemu/aqmp/aqmp_tui.py
index f1e926dd75..184a3e4690 100644
--- a/python/qemu/aqmp/aqmp_tui.py
+++ b/python/qemu/aqmp/aqmp_tui.py
@@ -35,9 +35,8 @@
 import urwid
 import urwid_readline
 
-from qemu.qmp import QEMUMonitorProtocol, QMPBadPortError
-
 from .error import ProtocolError
+from .legacy import QEMUMonitorProtocol, QMPBadPortError
 from .message import DeserializationError, Message, UnexpectedTypeError
 from .protocol import ConnectError, Runstate
 from .qmp_client import ExecInterruptedError, QMPClient
diff --git a/python/qemu/aqmp/legacy.py b/python/qemu/aqmp/legacy.py
index f86cb29804..f026274949 100644
--- a/python/qemu/aqmp/legacy.py
+++ b/python/qemu/aqmp/legacy.py
@@ -33,9 +33,6 @@
 from .qmp_client import QMPClient
 
 
-# (Temporarily) Re-export QMPBadPortError
-QMPBadPortError = qemu.qmp.QMPBadPortError
-
 #: QMPMessage is an entire QMP message of any kind.
 QMPMessage = Dict[str, Any]
 
@@ -56,6 +53,12 @@
 # pylint: disable=missing-docstring
 
 
+class QMPBadPortError(QMPError):
+    """
+    Unable to parse socket address: Port was non-numerical.
+    """
+
+
 class QEMUMonitorProtocol(qemu.qmp.QEMUMonitorProtocol):
     def __init__(self, address: SocketAddrT,
                  server: bool = False,
@@ -86,7 +89,26 @@ def _get_greeting(self) -> Optional[QMPMessage]:
         return None
 
     # __enter__ and __exit__ need no changes
-    # parse_address needs no changes
+
+    @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]:
         self._aqmp.await_greeting = negotiate
diff --git a/python/qemu/qmp/__init__.py b/python/qemu/qmp/__init__.py
index 358c0971d0..4e08641154 100644
--- a/python/qemu/qmp/__init__.py
+++ b/python/qemu/qmp/__init__.py
@@ -102,12 +102,6 @@ def __init__(self, reply: QMPMessage):
         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
@@ -237,26 +231,6 @@ def __exit__(self,
         # 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.
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 05/10] python/aqmp: fully separate from qmp.QEMUMonitorProtocol
  2022-03-21 21:08 [PATCH 00/10] Python: Remove synchronous QMP library John Snow
                   ` (3 preceding siblings ...)
  2022-03-21 21:08 ` [PATCH 04/10] python/aqmp: take QMPBadPortError and parse_address from qemu.qmp John Snow
@ 2022-03-21 21:08 ` John Snow
  2022-03-21 21:08 ` [PATCH 06/10] python/aqmp: copy qmp docstrings to qemu.aqmp.legacy John Snow
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 25+ messages in thread
From: John Snow @ 2022-03-21 21:08 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Vladimir Sementsov-Ogievskiy, Beraldo Leal,
	qemu-block, Markus Armbruster, Hanna Reitz, Cleber Rosa,
	John Snow

After this patch, qemu.aqmp.legacy.QEMUMonitorProtocol no longer
inherits from qemu.qmp.QEMUMonitorProtocol. To do this, several
inherited methods need to be explicitly re-defined.

(Licensing: This is copying and modifying GPLv2-only code into a
GPLv2-only file.)

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Beraldo Leal <bleal@redhat.com>
---
 python/qemu/aqmp/legacy.py | 37 +++++++++++++++++++++++++++++++------
 1 file changed, 31 insertions(+), 6 deletions(-)

diff --git a/python/qemu/aqmp/legacy.py b/python/qemu/aqmp/legacy.py
index f026274949..10c7c99c4f 100644
--- a/python/qemu/aqmp/legacy.py
+++ b/python/qemu/aqmp/legacy.py
@@ -16,18 +16,18 @@
 #
 
 import asyncio
+from types import TracebackType
 from typing import (
     Any,
     Awaitable,
     Dict,
     List,
     Optional,
+    Type,
     TypeVar,
     Union,
 )
 
-import qemu.qmp
-
 from .error import QMPError
 from .protocol import Runstate, SocketAddrT
 from .qmp_client import QMPClient
@@ -59,12 +59,11 @@ class QMPBadPortError(QMPError):
     """
 
 
-class QEMUMonitorProtocol(qemu.qmp.QEMUMonitorProtocol):
+class QEMUMonitorProtocol:
     def __init__(self, address: SocketAddrT,
                  server: bool = False,
                  nickname: Optional[str] = None):
 
-        # pylint: disable=super-init-not-called
         self._aqmp = QMPClient(nickname)
         self._aloop = asyncio.get_event_loop()
         self._address = address
@@ -88,7 +87,18 @@ def _get_greeting(self) -> Optional[QMPMessage]:
             return self._aqmp.greeting._asdict()
         return None
 
-    # __enter__ and __exit__ need no changes
+    def __enter__(self: _T) -> _T:
+        # Implement context manager enter function.
+        return self
+
+    def __exit__(self,
+                 # pylint: disable=duplicate-code
+                 # see https://github.com/PyCQA/pylint/issues/3619
+                 exc_type: Optional[Type[BaseException]],
+                 exc_val: Optional[BaseException],
+                 exc_tb: Optional[TracebackType]) -> None:
+        # Implement context manager exit function.
+        self.close()
 
     @classmethod
     def parse_address(cls, address: str) -> SocketAddrT:
@@ -142,7 +152,22 @@ def cmd_obj(self, qmp_cmd: QMPMessage) -> QMPMessage:
             )
         )
 
-    # Default impl of cmd() delegates to cmd_obj
+    def cmd(self, name: str,
+            args: Optional[Dict[str, object]] = None,
+            cmd_id: Optional[object] = None) -> QMPMessage:
+        """
+        Build a QMP command and send it to the QMP Monitor.
+
+        @param name: command name (string)
+        @param args: command arguments (dict)
+        @param cmd_id: command id (dict, list, string or int)
+        """
+        qmp_cmd: QMPMessage = {'execute': name}
+        if args:
+            qmp_cmd['arguments'] = args
+        if cmd_id:
+            qmp_cmd['id'] = cmd_id
+        return self.cmd_obj(qmp_cmd)
 
     def command(self, cmd: str, **kwds: object) -> QMPReturnValue:
         return self._sync(
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 06/10] python/aqmp: copy qmp docstrings to qemu.aqmp.legacy
  2022-03-21 21:08 [PATCH 00/10] Python: Remove synchronous QMP library John Snow
                   ` (4 preceding siblings ...)
  2022-03-21 21:08 ` [PATCH 05/10] python/aqmp: fully separate from qmp.QEMUMonitorProtocol John Snow
@ 2022-03-21 21:08 ` John Snow
  2022-03-23 18:24   ` Hanna Reitz
  2022-03-21 21:08 ` [PATCH 07/10] python: remove the old QMP package John Snow
                   ` (3 subsequent siblings)
  9 siblings, 1 reply; 25+ messages in thread
From: John Snow @ 2022-03-21 21:08 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Vladimir Sementsov-Ogievskiy, Beraldo Leal,
	qemu-block, Markus Armbruster, Hanna Reitz, Cleber Rosa,
	John Snow

Copy the docstrings out of qemu.qmp, adjusting them as necessary to
more accurately reflect the current state of this class.

(Licensing: This is copying and modifying GPLv2-only licensed docstrings
into a GPLv2-only file.)

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Beraldo Leal <bleal@redhat.com>
---
 python/qemu/aqmp/legacy.py | 102 ++++++++++++++++++++++++++++++++++---
 1 file changed, 94 insertions(+), 8 deletions(-)

diff --git a/python/qemu/aqmp/legacy.py b/python/qemu/aqmp/legacy.py
index 10c7c99c4f..20ffdd8956 100644
--- a/python/qemu/aqmp/legacy.py
+++ b/python/qemu/aqmp/legacy.py
@@ -1,7 +1,13 @@
 """
-Sync QMP Wrapper
+(Legacy) Sync QMP Wrapper
 
-This class pretends to be qemu.qmp.QEMUMonitorProtocol.
+This module provides the `QEMUMonitorProtocol` class, which is a
+synchronous wrapper around `QMPClient`.
+
+Its design closely resembles that of the original QEMUMonitorProtocol
+class, originally written by Luiz Capitulino. It is provided here for
+compatibility with scripts inside the QEMU source tree that expect the
+old interface.
 """
 
 #
@@ -50,9 +56,6 @@
 # {} is the QMPReturnValue.
 
 
-# pylint: disable=missing-docstring
-
-
 class QMPBadPortError(QMPError):
     """
     Unable to parse socket address: Port was non-numerical.
@@ -60,6 +63,21 @@ class QMPBadPortError(QMPError):
 
 
 class QEMUMonitorProtocol:
+    """
+    Provide an API to connect to QEMU via QEMU Monitor Protocol (QMP)
+    and then allow to handle commands and events.
+
+    :param address:  QEMU address, can be either a unix socket path (string)
+                     or a tuple in the form ( address, port ) for a TCP
+                     connection
+    :param server:   Deprecated, ignored. (See 'accept')
+    :param nickname: Optional nickname used for logging.
+
+    ..note::
+        No connection is established during `__init__`, this is done by
+        the `connect()` or `accept()` methods.
+    """
+
     def __init__(self, address: SocketAddrT,
                  server: bool = False,
                  nickname: Optional[str] = None):
@@ -121,6 +139,12 @@ def parse_address(cls, address: str) -> SocketAddrT:
         return address
 
     def connect(self, negotiate: bool = True) -> Optional[QMPMessage]:
+        """
+        Connect to the QMP Monitor and perform capabilities negotiation.
+
+        :return: QMP greeting dict, or None if negotiate is false
+        :raise ConnectError: on connection errors
+        """
         self._aqmp.await_greeting = negotiate
         self._aqmp.negotiate = negotiate
 
@@ -130,6 +154,16 @@ def connect(self, negotiate: bool = True) -> Optional[QMPMessage]:
         return self._get_greeting()
 
     def accept(self, timeout: Optional[float] = 15.0) -> QMPMessage:
+        """
+        Await connection from QMP Monitor and perform capabilities negotiation.
+
+        :param timeout:
+            timeout in seconds (nonnegative float number, or None).
+            If None, there is no timeout, and this may block forever.
+
+        :return: QMP greeting dict
+        :raise ConnectError: on connection errors
+        """
         self._aqmp.await_greeting = True
         self._aqmp.negotiate = True
 
@@ -140,6 +174,12 @@ def accept(self, timeout: Optional[float] = 15.0) -> QMPMessage:
         return ret
 
     def cmd_obj(self, qmp_cmd: QMPMessage) -> QMPMessage:
+        """
+        Send a QMP command to the QMP Monitor.
+
+        :param qmp_cmd: QMP command to be sent as a Python dict
+        :return: QMP response as a Python dict
+        """
         return dict(
             self._sync(
                 # pylint: disable=protected-access
@@ -158,9 +198,9 @@ def cmd(self, name: str,
         """
         Build a QMP command and send it to the QMP Monitor.
 
-        @param name: command name (string)
-        @param args: command arguments (dict)
-        @param cmd_id: command id (dict, list, string or int)
+        :param name: command name (string)
+        :param args: command arguments (dict)
+        :param cmd_id: command id (dict, list, string or int)
         """
         qmp_cmd: QMPMessage = {'execute': name}
         if args:
@@ -170,6 +210,9 @@ def cmd(self, name: str,
         return self.cmd_obj(qmp_cmd)
 
     def command(self, cmd: str, **kwds: object) -> QMPReturnValue:
+        """
+        Build and send a QMP command to the monitor, report errors if any
+        """
         return self._sync(
             self._aqmp.execute(cmd, kwds),
             self._timeout
@@ -177,6 +220,19 @@ def command(self, cmd: str, **kwds: object) -> QMPReturnValue:
 
     def pull_event(self,
                    wait: Union[bool, float] = False) -> Optional[QMPMessage]:
+        """
+        Pulls a single event.
+
+        :param wait:
+            If False or 0, do not wait. Return None if no events ready.
+            If True, wait forever until the next event.
+            Otherwise, wait for the specified number of seconds.
+
+        :raise asyncio.TimeoutError:
+            When a timeout is requested and the timeout period elapses.
+
+        :return: The first available QMP event, or None.
+        """
         if not wait:
             # wait is False/0: "do not wait, do not except."
             if self._aqmp.events.empty():
@@ -197,6 +253,20 @@ def pull_event(self,
         )
 
     def get_events(self, wait: Union[bool, float] = False) -> List[QMPMessage]:
+        """
+        Get a list of QMP events and clear all pending events.
+
+        :param wait:
+            If False or 0, do not wait. Return None if no events ready.
+            If True, wait until we have at least one event.
+            Otherwise, wait for up to the specified number of seconds for at
+            least one event.
+
+        :raise asyncio.TimeoutError:
+            When a timeout is requested and the timeout period elapses.
+
+        :return: A list of QMP events.
+        """
         events = [dict(x) for x in self._aqmp.events.clear()]
         if events:
             return events
@@ -205,17 +275,33 @@ def get_events(self, wait: Union[bool, float] = False) -> List[QMPMessage]:
         return [event] if event is not None else []
 
     def clear_events(self) -> None:
+        """Clear current list of pending events."""
         self._aqmp.events.clear()
 
     def close(self) -> None:
+        """Close the connection."""
         self._sync(
             self._aqmp.disconnect()
         )
 
     def settimeout(self, timeout: Optional[float]) -> None:
+        """
+        Set the timeout for QMP RPC execution.
+
+        This timeout affects the `cmd`, `cmd_obj`, and `command` methods.
+        The `accept`, `pull_event` and `get_event` methods have their
+        own configurable timeouts.
+
+        :param timeout:
+            timeout in seconds, or None.
+            None will wait indefinitely.
+        """
         self._timeout = timeout
 
     def send_fd_scm(self, fd: int) -> None:
+        """
+        Send a file descriptor to the remote via SCM_RIGHTS.
+        """
         self._aqmp.send_fd_scm(fd)
 
     def __del__(self) -> None:
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 07/10] python: remove the old QMP package
  2022-03-21 21:08 [PATCH 00/10] Python: Remove synchronous QMP library John Snow
                   ` (5 preceding siblings ...)
  2022-03-21 21:08 ` [PATCH 06/10] python/aqmp: copy qmp docstrings to qemu.aqmp.legacy John Snow
@ 2022-03-21 21:08 ` John Snow
  2022-03-21 21:08 ` [PATCH 08/10] python: re-enable pylint duplicate-code warnings John Snow
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 25+ messages in thread
From: John Snow @ 2022-03-21 21:08 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Vladimir Sementsov-Ogievskiy, Beraldo Leal,
	qemu-block, Markus Armbruster, Hanna Reitz, Cleber Rosa,
	John Snow

Thank you for your service!

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Beraldo Leal <bleal@redhat.com>
---
 python/PACKAGE.rst          |   4 +-
 python/README.rst           |   2 +-
 python/qemu/qmp/README.rst  |   9 -
 python/qemu/qmp/__init__.py | 396 ------------------------------------
 python/qemu/qmp/py.typed    |   0
 python/setup.cfg            |   3 +-
 6 files changed, 4 insertions(+), 410 deletions(-)
 delete mode 100644 python/qemu/qmp/README.rst
 delete mode 100644 python/qemu/qmp/__init__.py
 delete mode 100644 python/qemu/qmp/py.typed

diff --git a/python/PACKAGE.rst b/python/PACKAGE.rst
index b0b86cc4c3..ddfa9ba3f5 100644
--- a/python/PACKAGE.rst
+++ b/python/PACKAGE.rst
@@ -8,11 +8,11 @@ to change at any time.
 Usage
 -----
 
-The ``qemu.qmp`` subpackage provides a library for communicating with
+The ``qemu.aqmp`` subpackage provides a library for communicating with
 QMP servers. The ``qemu.machine`` subpackage offers rudimentary
 facilities for launching and managing QEMU processes. Refer to each
 package's documentation
-(``>>> help(qemu.qmp)``, ``>>> help(qemu.machine)``)
+(``>>> help(qemu.aqmp)``, ``>>> help(qemu.machine)``)
 for more information.
 
 Contributing
diff --git a/python/README.rst b/python/README.rst
index fcf74f69ea..eb5213337d 100644
--- a/python/README.rst
+++ b/python/README.rst
@@ -3,7 +3,7 @@ QEMU Python Tooling
 
 This directory houses Python tooling used by the QEMU project to build,
 configure, and test QEMU. It is organized by namespace (``qemu``), and
-then by package (e.g. ``qemu/machine``, ``qemu/qmp``, etc).
+then by package (e.g. ``qemu/machine``, ``qemu/aqmp``, etc).
 
 ``setup.py`` is used by ``pip`` to install this tooling to the current
 environment. ``setup.cfg`` provides the packaging configuration used by
diff --git a/python/qemu/qmp/README.rst b/python/qemu/qmp/README.rst
deleted file mode 100644
index 5bfb82535f..0000000000
--- a/python/qemu/qmp/README.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-qemu.qmp package
-================
-
-This package provides a library used for connecting to and communicating
-with QMP servers. It is used extensively by iotests, vm tests,
-avocado tests, and other utilities in the ./scripts directory. It is
-not a fully-fledged SDK and is subject to change at any time.
-
-See the documentation in ``__init__.py`` for more information.
diff --git a/python/qemu/qmp/__init__.py b/python/qemu/qmp/__init__.py
deleted file mode 100644
index 4e08641154..0000000000
--- a/python/qemu/qmp/__init__.py
+++ /dev/null
@@ -1,396 +0,0 @@
-"""
-QEMU Monitor Protocol (QMP) development library & tooling.
-
-This package provides a fairly low-level class for communicating to QMP
-protocol servers, as implemented by QEMU, the QEMU Guest Agent, and the
-QEMU Storage Daemon. This library is not intended for production use.
-
-`QEMUMonitorProtocol` is the primary class of interest, and all errors
-raised derive from `QMPError`.
-"""
-
-# Copyright (C) 2009, 2010 Red Hat Inc.
-#
-# Authors:
-#  Luiz Capitulino <lcapitulino@redhat.com>
-#
-# This work is licensed under the terms of the GNU GPL, version 2.  See
-# the COPYING file in the top-level directory.
-
-import errno
-import json
-import logging
-import socket
-import struct
-from types import TracebackType
-from typing import (
-    Any,
-    Dict,
-    List,
-    Optional,
-    TextIO,
-    Tuple,
-    Type,
-    TypeVar,
-    Union,
-    cast,
-)
-
-
-#: 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.
-#
-# {'return': {}} is a QMPMessage,
-# {} is the QMPReturnValue.
-
-
-InternetAddrT = Tuple[str, int]
-UnixAddrT = str
-SocketAddrT = Union[InternetAddrT, UnixAddrT]
-
-
-class QMPError(Exception):
-    """
-    QMP base exception
-    """
-
-
-class QMPConnectError(QMPError):
-    """
-    QMP connection exception
-    """
-
-
-class QMPCapabilitiesError(QMPError):
-    """
-    QMP negotiate capabilities exception
-    """
-
-
-class QMPTimeoutError(QMPError):
-    """
-    QMP timeout exception
-    """
-
-
-class QMPProtocolError(QMPError):
-    """
-    QMP protocol error; unexpected response
-    """
-
-
-class QMPResponseError(QMPError):
-    """
-    Represents erroneous QMP monitor reply
-    """
-    def __init__(self, reply: QMPMessage):
-        try:
-            desc = reply['error']['desc']
-        except KeyError:
-            desc = reply
-        super().__init__(desc)
-        self.reply = reply
-
-
-class QEMUMonitorProtocol:
-    """
-    Provide an API to connect to QEMU via QEMU Monitor Protocol (QMP) and then
-    allow to handle commands and events.
-    """
-
-    #: Logger object for debugging messages
-    logger = logging.getLogger('QMP')
-
-    def __init__(self, address: SocketAddrT,
-                 server: bool = False,
-                 nickname: Optional[str] = None):
-        """
-        Create a QEMUMonitorProtocol class.
-
-        @param address: QEMU address, can be either a unix socket path (string)
-                        or a tuple in the form ( address, port ) for a TCP
-                        connection
-        @param server: server mode listens on the socket (bool)
-        @raise OSError on socket connection errors
-        @note No connection is established, this is done by the connect() or
-              accept() methods
-        """
-        self.__events: List[QMPMessage] = []
-        self.__address = address
-        self.__sock = self.__get_sock()
-        self.__sockfile: Optional[TextIO] = None
-        self._nickname = nickname
-        if self._nickname:
-            self.logger = logging.getLogger('QMP').getChild(self._nickname)
-        if server:
-            self.__sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
-            self.__sock.bind(self.__address)
-            self.__sock.listen(1)
-
-    def __get_sock(self) -> socket.socket:
-        if isinstance(self.__address, tuple):
-            family = socket.AF_INET
-        else:
-            family = socket.AF_UNIX
-        return socket.socket(family, socket.SOCK_STREAM)
-
-    def __negotiate_capabilities(self) -> QMPMessage:
-        greeting = self.__json_read()
-        if greeting is None or "QMP" not in greeting:
-            raise QMPConnectError
-        # Greeting seems ok, negotiate capabilities
-        resp = self.cmd('qmp_capabilities')
-        if resp and "return" in resp:
-            return greeting
-        raise QMPCapabilitiesError
-
-    def __json_read(self, only_event: bool = False) -> Optional[QMPMessage]:
-        assert self.__sockfile is not None
-        while True:
-            data = self.__sockfile.readline()
-            if not data:
-                return None
-            # 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: QMPMessage = json.loads(data)
-            if 'event' in resp:
-                self.logger.debug("<<< %s", resp)
-                self.__events.append(resp)
-                if not only_event:
-                    continue
-            return resp
-
-    def __get_events(self, wait: Union[bool, float] = False) -> None:
-        """
-        Check for new events in the stream and cache them in __events.
-
-        @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.
-        """
-
-        # Current timeout and blocking status
-        current_timeout = self.__sock.gettimeout()
-
-        # Check for new events regardless and pull them into the cache:
-        self.__sock.settimeout(0)  # i.e. setblocking(False)
-        try:
-            self.__json_read()
-        except OSError as err:
-            # EAGAIN: No data available; not critical
-            if err.errno != errno.EAGAIN:
-                raise
-        finally:
-            self.__sock.settimeout(current_timeout)
-
-        # Wait for new events, if needed.
-        # if wait is 0.0, this means "no wait" and is also implicitly false.
-        if not self.__events and wait:
-            if isinstance(wait, float):
-                self.__sock.settimeout(wait)
-            try:
-                ret = self.__json_read(only_event=True)
-            except socket.timeout as err:
-                raise QMPTimeoutError("Timeout waiting for event") from err
-            except Exception as err:
-                msg = "Error while reading from socket"
-                raise QMPConnectError(msg) from err
-            finally:
-                self.__sock.settimeout(current_timeout)
-
-            if ret is None:
-                raise QMPConnectError("Error while reading from socket")
-
-    T = TypeVar('T')
-
-    def __enter__(self: T) -> T:
-        # Implement context manager enter function.
-        return self
-
-    def __exit__(self,
-                 # pylint: disable=duplicate-code
-                 # see https://github.com/PyCQA/pylint/issues/3619
-                 exc_type: Optional[Type[BaseException]],
-                 exc_val: Optional[BaseException],
-                 exc_tb: Optional[TracebackType]) -> None:
-        # Implement context manager exit function.
-        self.close()
-
-    def connect(self, negotiate: bool = True) -> Optional[QMPMessage]:
-        """
-        Connect to the QMP Monitor and perform capabilities negotiation.
-
-        @return QMP greeting dict, or None if negotiate is false
-        @raise OSError on socket connection errors
-        @raise QMPConnectError if the greeting is not received
-        @raise QMPCapabilitiesError if fails to negotiate capabilities
-        """
-        self.__sock.connect(self.__address)
-        self.__sockfile = self.__sock.makefile(mode='r')
-        if negotiate:
-            return self.__negotiate_capabilities()
-        return None
-
-    def accept(self, timeout: Optional[float] = 15.0) -> QMPMessage:
-        """
-        Await connection from QMP Monitor and perform capabilities negotiation.
-
-        @param timeout: timeout in seconds (nonnegative float number, or
-                        None). The value passed will set the behavior of the
-                        underneath QMP socket as described in [1].
-                        Default value is set to 15.0.
-
-        @return QMP greeting dict
-        @raise OSError on socket connection errors
-        @raise QMPConnectError if the greeting is not received
-        @raise QMPCapabilitiesError if fails to negotiate capabilities
-
-        [1]
-        https://docs.python.org/3/library/socket.html#socket.socket.settimeout
-        """
-        self.__sock.settimeout(timeout)
-        self.__sock, _ = self.__sock.accept()
-        self.__sockfile = self.__sock.makefile(mode='r')
-        return self.__negotiate_capabilities()
-
-    def cmd_obj(self, qmp_cmd: QMPMessage) -> QMPMessage:
-        """
-        Send a QMP command to the QMP Monitor.
-
-        @param qmp_cmd: QMP command to be sent as a Python dict
-        @return QMP response as a Python dict
-        """
-        self.logger.debug(">>> %s", qmp_cmd)
-        self.__sock.sendall(json.dumps(qmp_cmd).encode('utf-8'))
-        resp = self.__json_read()
-        if resp is None:
-            raise QMPConnectError("Unexpected empty reply from server")
-        self.logger.debug("<<< %s", resp)
-        return resp
-
-    def cmd(self, name: str,
-            args: Optional[Dict[str, object]] = None,
-            cmd_id: Optional[object] = None) -> QMPMessage:
-        """
-        Build a QMP command and send it to the QMP Monitor.
-
-        @param name: command name (string)
-        @param args: command arguments (dict)
-        @param cmd_id: command id (dict, list, string or int)
-        """
-        qmp_cmd: QMPMessage = {'execute': name}
-        if args:
-            qmp_cmd['arguments'] = args
-        if cmd_id:
-            qmp_cmd['id'] = cmd_id
-        return self.cmd_obj(qmp_cmd)
-
-    def command(self, cmd: str, **kwds: object) -> QMPReturnValue:
-        """
-        Build and send a QMP command to the monitor, report errors if any
-        """
-        ret = self.cmd(cmd, kwds)
-        if 'error' in ret:
-            raise QMPResponseError(ret)
-        if 'return' not in ret:
-            raise QMPProtocolError(
-                "'return' key not found in QMP response '{}'".format(str(ret))
-            )
-        return cast(QMPReturnValue, ret['return'])
-
-    def pull_event(self,
-                   wait: Union[bool, float] = False) -> Optional[QMPMessage]:
-        """
-        Pulls a single event.
-
-        @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.
-
-        @return The first available QMP event, or None.
-        """
-        self.__get_events(wait)
-
-        if self.__events:
-            return self.__events.pop(0)
-        return None
-
-    def get_events(self, wait: bool = False) -> List[QMPMessage]:
-        """
-        Get a list of available QMP events and clear all pending events.
-
-        @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.
-
-        @return The list of available QMP events.
-        """
-        self.__get_events(wait)
-        events = self.__events
-        self.__events = []
-        return events
-
-    def clear_events(self) -> None:
-        """
-        Clear current list of pending events.
-        """
-        self.__events = []
-
-    def close(self) -> None:
-        """
-        Close the socket and socket file.
-        """
-        if self.__sock:
-            self.__sock.close()
-        if self.__sockfile:
-            self.__sockfile.close()
-
-    def settimeout(self, timeout: Optional[float]) -> None:
-        """
-        Set the socket timeout.
-
-        @param timeout (float): timeout in seconds (non-zero), or None.
-        @note This is a wrap around socket.settimeout
-
-        @raise ValueError: if timeout was set to 0.
-        """
-        if timeout == 0:
-            msg = "timeout cannot be 0; this engages non-blocking mode."
-            msg += " Use 'None' instead to disable timeouts."
-            raise ValueError(msg)
-        self.__sock.settimeout(timeout)
-
-    def send_fd_scm(self, fd: int) -> None:
-        """
-        Send a file descriptor to the remote via SCM_RIGHTS.
-        """
-        if self.__sock.family != socket.AF_UNIX:
-            raise RuntimeError("Can't use SCM_RIGHTS on non-AF_UNIX socket.")
-
-        self.__sock.sendmsg(
-            [b' '],
-            [(socket.SOL_SOCKET, socket.SCM_RIGHTS, struct.pack('@i', fd))]
-        )
diff --git a/python/qemu/qmp/py.typed b/python/qemu/qmp/py.typed
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/python/setup.cfg b/python/setup.cfg
index cdeced44d2..4340c29a24 100644
--- a/python/setup.cfg
+++ b/python/setup.cfg
@@ -24,10 +24,9 @@ classifiers =
 [options]
 python_requires = >= 3.6
 packages =
-    qemu.qmp
+    qemu.aqmp
     qemu.machine
     qemu.utils
-    qemu.aqmp
 
 [options.package_data]
 * = py.typed
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 08/10] python: re-enable pylint duplicate-code warnings
  2022-03-21 21:08 [PATCH 00/10] Python: Remove synchronous QMP library John Snow
                   ` (6 preceding siblings ...)
  2022-03-21 21:08 ` [PATCH 07/10] python: remove the old QMP package John Snow
@ 2022-03-21 21:08 ` John Snow
  2022-03-21 21:08 ` [PATCH 09/10] python: rename qemu.aqmp to qemu.qmp John Snow
  2022-03-21 21:08 ` [PATCH 10/10] python: rename 'aqmp-tui' to 'qmp-tui' John Snow
  9 siblings, 0 replies; 25+ messages in thread
From: John Snow @ 2022-03-21 21:08 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Vladimir Sementsov-Ogievskiy, Beraldo Leal,
	qemu-block, Markus Armbruster, Hanna Reitz, Cleber Rosa,
	John Snow

With the old library gone, there's nothing duplicated in the tree, so
the warning suppression can be removed.

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Beraldo Leal <bleal@redhat.com>
---
 python/setup.cfg | 1 -
 1 file changed, 1 deletion(-)

diff --git a/python/setup.cfg b/python/setup.cfg
index 4340c29a24..49e3c285f1 100644
--- a/python/setup.cfg
+++ b/python/setup.cfg
@@ -118,7 +118,6 @@ disable=consider-using-f-string,
         too-many-function-args,  # mypy handles this with less false positives.
         too-many-instance-attributes,
         no-member,  # mypy also handles this better.
-        duplicate-code,  # To be removed by the end of this patch series.
 
 [pylint.basic]
 # Good variable names which should always be accepted, separated by a comma.
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 09/10] python: rename qemu.aqmp to qemu.qmp
  2022-03-21 21:08 [PATCH 00/10] Python: Remove synchronous QMP library John Snow
                   ` (7 preceding siblings ...)
  2022-03-21 21:08 ` [PATCH 08/10] python: re-enable pylint duplicate-code warnings John Snow
@ 2022-03-21 21:08 ` John Snow
  2022-03-23 18:19   ` Hanna Reitz
  2022-03-21 21:08 ` [PATCH 10/10] python: rename 'aqmp-tui' to 'qmp-tui' John Snow
  9 siblings, 1 reply; 25+ messages in thread
From: John Snow @ 2022-03-21 21:08 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Vladimir Sementsov-Ogievskiy, Beraldo Leal,
	qemu-block, Markus Armbruster, Hanna Reitz, Cleber Rosa,
	John Snow

Now that we are fully switched over to the new QMP library, move it back
over the old namespace. This is being done primarily so that we may
upload this package simply as "qemu.qmp" without introducing confusion
over whether or not "aqmp" is a new protocol or not.

The trade-off is increased confusion inside the QEMU developer
tree. Sorry!

Note: the 'private' member "_aqmp" in legacy.py also changes to "_qmp";
not out of necessity, but just to remove any traces of the "aqmp"
name.

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Beraldo Leal <bleal@redhat.com>
---
 python/PACKAGE.rst                        |  4 +--
 python/README.rst                         |  4 +--
 python/qemu/machine/machine.py            |  4 +--
 python/qemu/machine/qtest.py              |  2 +-
 python/qemu/{aqmp => qmp}/__init__.py     |  6 ++--
 python/qemu/{aqmp => qmp}/aqmp_tui.py     |  0
 python/qemu/{aqmp => qmp}/error.py        |  0
 python/qemu/{aqmp => qmp}/events.py       |  2 +-
 python/qemu/{aqmp => qmp}/legacy.py       | 38 +++++++++++------------
 python/qemu/{aqmp => qmp}/message.py      |  0
 python/qemu/{aqmp => qmp}/models.py       |  0
 python/qemu/{aqmp => qmp}/protocol.py     |  4 +--
 python/qemu/{aqmp => qmp}/py.typed        |  0
 python/qemu/{aqmp => qmp}/qmp_client.py   | 16 +++++-----
 python/qemu/{aqmp => qmp}/qmp_shell.py    |  4 +--
 python/qemu/{aqmp => qmp}/util.py         |  0
 python/qemu/utils/qemu_ga_client.py       |  4 +--
 python/qemu/utils/qom.py                  |  2 +-
 python/qemu/utils/qom_common.py           |  4 +--
 python/qemu/utils/qom_fuse.py             |  2 +-
 python/setup.cfg                          | 10 +++---
 python/tests/protocol.py                  | 14 ++++-----
 scripts/cpu-x86-uarch-abi.py              |  2 +-
 scripts/device-crash-test                 |  4 +--
 scripts/qmp/qmp-shell                     |  2 +-
 scripts/qmp/qmp-shell-wrap                |  2 +-
 scripts/render_block_graph.py             |  4 +--
 scripts/simplebench/bench_block_job.py    |  2 +-
 tests/qemu-iotests/iotests.py             |  2 +-
 tests/qemu-iotests/tests/mirror-top-perms |  2 +-
 30 files changed, 70 insertions(+), 70 deletions(-)
 rename python/qemu/{aqmp => qmp}/__init__.py (87%)
 rename python/qemu/{aqmp => qmp}/aqmp_tui.py (100%)
 rename python/qemu/{aqmp => qmp}/error.py (100%)
 rename python/qemu/{aqmp => qmp}/events.py (99%)
 rename python/qemu/{aqmp => qmp}/legacy.py (91%)
 rename python/qemu/{aqmp => qmp}/message.py (100%)
 rename python/qemu/{aqmp => qmp}/models.py (100%)
 rename python/qemu/{aqmp => qmp}/protocol.py (99%)
 rename python/qemu/{aqmp => qmp}/py.typed (100%)
 rename python/qemu/{aqmp => qmp}/qmp_client.py (97%)
 rename python/qemu/{aqmp => qmp}/qmp_shell.py (99%)
 rename python/qemu/{aqmp => qmp}/util.py (100%)

diff --git a/python/PACKAGE.rst b/python/PACKAGE.rst
index ddfa9ba3f5..b0b86cc4c3 100644
--- a/python/PACKAGE.rst
+++ b/python/PACKAGE.rst
@@ -8,11 +8,11 @@ to change at any time.
 Usage
 -----
 
-The ``qemu.aqmp`` subpackage provides a library for communicating with
+The ``qemu.qmp`` subpackage provides a library for communicating with
 QMP servers. The ``qemu.machine`` subpackage offers rudimentary
 facilities for launching and managing QEMU processes. Refer to each
 package's documentation
-(``>>> help(qemu.aqmp)``, ``>>> help(qemu.machine)``)
+(``>>> help(qemu.qmp)``, ``>>> help(qemu.machine)``)
 for more information.
 
 Contributing
diff --git a/python/README.rst b/python/README.rst
index eb5213337d..9c1fceaee7 100644
--- a/python/README.rst
+++ b/python/README.rst
@@ -3,7 +3,7 @@ QEMU Python Tooling
 
 This directory houses Python tooling used by the QEMU project to build,
 configure, and test QEMU. It is organized by namespace (``qemu``), and
-then by package (e.g. ``qemu/machine``, ``qemu/aqmp``, etc).
+then by package (e.g. ``qemu/machine``, ``qemu/qmp``, etc).
 
 ``setup.py`` is used by ``pip`` to install this tooling to the current
 environment. ``setup.cfg`` provides the packaging configuration used by
@@ -59,7 +59,7 @@ Package installation also normally provides executable console scripts,
 so that tools like ``qmp-shell`` are always available via $PATH. To
 invoke them without installation, you can invoke e.g.:
 
-``> PYTHONPATH=~/src/qemu/python python3 -m qemu.aqmp.qmp_shell``
+``> PYTHONPATH=~/src/qemu/python python3 -m qemu.qmp.qmp_shell``
 
 The mappings between console script name and python module path can be
 found in ``setup.cfg``.
diff --git a/python/qemu/machine/machine.py b/python/qemu/machine/machine.py
index 41be025ac7..07ac5a710b 100644
--- a/python/qemu/machine/machine.py
+++ b/python/qemu/machine/machine.py
@@ -40,8 +40,8 @@
     TypeVar,
 )
 
-from qemu.aqmp import SocketAddrT
-from qemu.aqmp.legacy import (
+from qemu.qmp import SocketAddrT
+from qemu.qmp.legacy import (
     QEMUMonitorProtocol,
     QMPMessage,
     QMPReturnValue,
diff --git a/python/qemu/machine/qtest.py b/python/qemu/machine/qtest.py
index 13e0aaff84..1a1fc6c9b0 100644
--- a/python/qemu/machine/qtest.py
+++ b/python/qemu/machine/qtest.py
@@ -26,7 +26,7 @@
     TextIO,
 )
 
-from qemu.aqmp import SocketAddrT
+from qemu.qmp import SocketAddrT
 
 from .machine import QEMUMachine
 
diff --git a/python/qemu/aqmp/__init__.py b/python/qemu/qmp/__init__.py
similarity index 87%
rename from python/qemu/aqmp/__init__.py
rename to python/qemu/qmp/__init__.py
index 2e4478ac05..3e13f23ed7 100644
--- a/python/qemu/aqmp/__init__.py
+++ b/python/qemu/qmp/__init__.py
@@ -6,8 +6,8 @@
 QEMU Guest Agent, and the QEMU Storage Daemon.
 
 `QMPClient` provides the main functionality of this package. All errors
-raised by this library derive from `QMPError`, see `aqmp.error` for
-additional detail. See `aqmp.events` for an in-depth tutorial on
+raised by this library derive from `QMPError`, see `qmp.error` for
+additional detail. See `qmp.events` for an in-depth tutorial on
 managing QMP events.
 """
 
@@ -36,7 +36,7 @@
 
 
 # Suppress logging unless an application engages it.
-logging.getLogger('qemu.aqmp').addHandler(logging.NullHandler())
+logging.getLogger('qemu.qmp').addHandler(logging.NullHandler())
 
 
 # The order of these fields impact the Sphinx documentation order.
diff --git a/python/qemu/aqmp/aqmp_tui.py b/python/qemu/qmp/aqmp_tui.py
similarity index 100%
rename from python/qemu/aqmp/aqmp_tui.py
rename to python/qemu/qmp/aqmp_tui.py
diff --git a/python/qemu/aqmp/error.py b/python/qemu/qmp/error.py
similarity index 100%
rename from python/qemu/aqmp/error.py
rename to python/qemu/qmp/error.py
diff --git a/python/qemu/aqmp/events.py b/python/qemu/qmp/events.py
similarity index 99%
rename from python/qemu/aqmp/events.py
rename to python/qemu/qmp/events.py
index f3d4e2b5e8..6199776cc6 100644
--- a/python/qemu/aqmp/events.py
+++ b/python/qemu/qmp/events.py
@@ -1,5 +1,5 @@
 """
-AQMP Events and EventListeners
+QMP Events and EventListeners
 
 Asynchronous QMP uses `EventListener` objects to listen for events. An
 `EventListener` is a FIFO event queue that can be pre-filtered to listen
diff --git a/python/qemu/aqmp/legacy.py b/python/qemu/qmp/legacy.py
similarity index 91%
rename from python/qemu/aqmp/legacy.py
rename to python/qemu/qmp/legacy.py
index 20ffdd8956..0815b03dd2 100644
--- a/python/qemu/aqmp/legacy.py
+++ b/python/qemu/qmp/legacy.py
@@ -82,13 +82,13 @@ def __init__(self, address: SocketAddrT,
                  server: bool = False,
                  nickname: Optional[str] = None):
 
-        self._aqmp = QMPClient(nickname)
+        self._qmp = QMPClient(nickname)
         self._aloop = asyncio.get_event_loop()
         self._address = address
         self._timeout: Optional[float] = None
 
         if server:
-            self._sync(self._aqmp.start_server(self._address))
+            self._sync(self._qmp.start_server(self._address))
 
     _T = TypeVar('_T')
 
@@ -100,9 +100,9 @@ def _sync(
         )
 
     def _get_greeting(self) -> Optional[QMPMessage]:
-        if self._aqmp.greeting is not None:
+        if self._qmp.greeting is not None:
             # pylint: disable=protected-access
-            return self._aqmp.greeting._asdict()
+            return self._qmp.greeting._asdict()
         return None
 
     def __enter__(self: _T) -> _T:
@@ -145,11 +145,11 @@ def connect(self, negotiate: bool = True) -> Optional[QMPMessage]:
         :return: QMP greeting dict, or None if negotiate is false
         :raise ConnectError: on connection errors
         """
-        self._aqmp.await_greeting = negotiate
-        self._aqmp.negotiate = negotiate
+        self._qmp.await_greeting = negotiate
+        self._qmp.negotiate = negotiate
 
         self._sync(
-            self._aqmp.connect(self._address)
+            self._qmp.connect(self._address)
         )
         return self._get_greeting()
 
@@ -164,10 +164,10 @@ def accept(self, timeout: Optional[float] = 15.0) -> QMPMessage:
         :return: QMP greeting dict
         :raise ConnectError: on connection errors
         """
-        self._aqmp.await_greeting = True
-        self._aqmp.negotiate = True
+        self._qmp.await_greeting = True
+        self._qmp.negotiate = True
 
-        self._sync(self._aqmp.accept(), timeout)
+        self._sync(self._qmp.accept(), timeout)
 
         ret = self._get_greeting()
         assert ret is not None
@@ -187,7 +187,7 @@ def cmd_obj(self, qmp_cmd: QMPMessage) -> QMPMessage:
                 # _raw() isn't a public API, because turning off
                 # automatic ID assignment is discouraged. For
                 # compatibility with iotests *only*, do it anyway.
-                self._aqmp._raw(qmp_cmd, assign_id=False),
+                self._qmp._raw(qmp_cmd, assign_id=False),
                 self._timeout
             )
         )
@@ -214,7 +214,7 @@ def command(self, cmd: str, **kwds: object) -> QMPReturnValue:
         Build and send a QMP command to the monitor, report errors if any
         """
         return self._sync(
-            self._aqmp.execute(cmd, kwds),
+            self._qmp.execute(cmd, kwds),
             self._timeout
         )
 
@@ -235,7 +235,7 @@ def pull_event(self,
         """
         if not wait:
             # wait is False/0: "do not wait, do not except."
-            if self._aqmp.events.empty():
+            if self._qmp.events.empty():
                 return None
 
         # If wait is 'True', wait forever. If wait is False/0, the events
@@ -247,7 +247,7 @@ def pull_event(self,
 
         return dict(
             self._sync(
-                self._aqmp.events.get(),
+                self._qmp.events.get(),
                 timeout
             )
         )
@@ -267,7 +267,7 @@ def get_events(self, wait: Union[bool, float] = False) -> List[QMPMessage]:
 
         :return: A list of QMP events.
         """
-        events = [dict(x) for x in self._aqmp.events.clear()]
+        events = [dict(x) for x in self._qmp.events.clear()]
         if events:
             return events
 
@@ -276,12 +276,12 @@ def get_events(self, wait: Union[bool, float] = False) -> List[QMPMessage]:
 
     def clear_events(self) -> None:
         """Clear current list of pending events."""
-        self._aqmp.events.clear()
+        self._qmp.events.clear()
 
     def close(self) -> None:
         """Close the connection."""
         self._sync(
-            self._aqmp.disconnect()
+            self._qmp.disconnect()
         )
 
     def settimeout(self, timeout: Optional[float]) -> None:
@@ -302,10 +302,10 @@ def send_fd_scm(self, fd: int) -> None:
         """
         Send a file descriptor to the remote via SCM_RIGHTS.
         """
-        self._aqmp.send_fd_scm(fd)
+        self._qmp.send_fd_scm(fd)
 
     def __del__(self) -> None:
-        if self._aqmp.runstate == Runstate.IDLE:
+        if self._qmp.runstate == Runstate.IDLE:
             return
 
         if not self._aloop.is_running():
diff --git a/python/qemu/aqmp/message.py b/python/qemu/qmp/message.py
similarity index 100%
rename from python/qemu/aqmp/message.py
rename to python/qemu/qmp/message.py
diff --git a/python/qemu/aqmp/models.py b/python/qemu/qmp/models.py
similarity index 100%
rename from python/qemu/aqmp/models.py
rename to python/qemu/qmp/models.py
diff --git a/python/qemu/aqmp/protocol.py b/python/qemu/qmp/protocol.py
similarity index 99%
rename from python/qemu/aqmp/protocol.py
rename to python/qemu/qmp/protocol.py
index 36fae57f27..6ea86650ad 100644
--- a/python/qemu/aqmp/protocol.py
+++ b/python/qemu/qmp/protocol.py
@@ -196,9 +196,9 @@ class AsyncProtocol(Generic[T]):
 
     :param name:
         Name used for logging messages, if any. By default, messages
-        will log to 'qemu.aqmp.protocol', but each individual connection
+        will log to 'qemu.qmp.protocol', but each individual connection
         can be given its own logger by giving it a name; messages will
-        then log to 'qemu.aqmp.protocol.${name}'.
+        then log to 'qemu.qmp.protocol.${name}'.
     """
     # pylint: disable=too-many-instance-attributes
 
diff --git a/python/qemu/aqmp/py.typed b/python/qemu/qmp/py.typed
similarity index 100%
rename from python/qemu/aqmp/py.typed
rename to python/qemu/qmp/py.typed
diff --git a/python/qemu/aqmp/qmp_client.py b/python/qemu/qmp/qmp_client.py
similarity index 97%
rename from python/qemu/aqmp/qmp_client.py
rename to python/qemu/qmp/qmp_client.py
index 90a8737f03..5dcda04a75 100644
--- a/python/qemu/aqmp/qmp_client.py
+++ b/python/qemu/qmp/qmp_client.py
@@ -192,7 +192,7 @@ async def run(self, address='/tmp/qemu.socket'):
               await self.qmp.runstate_changed.wait()
               await self.disconnect()
 
-    See `aqmp.events` for more detail on event handling patterns.
+    See `qmp.events` for more detail on event handling patterns.
     """
     #: Logger object used for debugging messages.
     logger = logging.getLogger(__name__)
@@ -416,7 +416,7 @@ def _do_send(self, msg: Message) -> None:
 
     @upper_half
     def _get_exec_id(self) -> str:
-        exec_id = f"__aqmp#{self._execute_id:05d}"
+        exec_id = f"__qmp#{self._execute_id:05d}"
         self._execute_id += 1
         return exec_id
 
@@ -476,7 +476,7 @@ async def _execute(self, msg: Message, assign_id: bool = True) -> Message:
         An execution ID will be assigned if assign_id is `True`. It can be
         disabled, but this requires that an ID is manually assigned
         instead. For manually assigned IDs, you must not use the string
-        '__aqmp#' anywhere in the ID.
+        '__qmp#' anywhere in the ID.
 
         :param msg: The QMP `Message` to execute.
         :param assign_id: If True, assign a new execution ID.
@@ -490,7 +490,7 @@ async def _execute(self, msg: Message, assign_id: bool = True) -> Message:
             msg['id'] = self._get_exec_id()
         elif 'id' in msg:
             assert isinstance(msg['id'], str)
-            assert '__aqmp#' not in msg['id']
+            assert '__qmp#' not in msg['id']
 
         exec_id = await self._issue(msg)
         return await self._reply(exec_id)
@@ -512,7 +512,7 @@ async def _raw(
             Assign an arbitrary execution ID to this message. If
             `False`, the existing id must either be absent (and no other
             such pending execution may omit an ID) or a string. If it is
-            a string, it must not start with '__aqmp#' and no other such
+            a string, it must not start with '__qmp#' and no other such
             pending execution may currently be using that ID.
 
         :return: Execution reply from the server.
@@ -524,7 +524,7 @@ async def _raw(
             When assign_id is `False`, an ID is given, and it is not a string.
         :raise ValueError:
             When assign_id is `False`, but the ID is not usable;
-            Either because it starts with '__aqmp#' or it is already in-use.
+            Either because it starts with '__qmp#' or it is already in-use.
         """
         # 1. convert generic Mapping or bytes to a QMP Message
         # 2. copy Message objects so that we assign an ID only to the copy.
@@ -534,9 +534,9 @@ async def _raw(
         if not assign_id and 'id' in msg:
             if not isinstance(exec_id, str):
                 raise TypeError(f"ID ('{exec_id}') must be a string.")
-            if exec_id.startswith('__aqmp#'):
+            if exec_id.startswith('__qmp#'):
                 raise ValueError(
-                    f"ID ('{exec_id}') must not start with '__aqmp#'."
+                    f"ID ('{exec_id}') must not start with '__qmp#'."
                 )
 
         if not assign_id and exec_id in self._pending:
diff --git a/python/qemu/aqmp/qmp_shell.py b/python/qemu/qmp/qmp_shell.py
similarity index 99%
rename from python/qemu/aqmp/qmp_shell.py
rename to python/qemu/qmp/qmp_shell.py
index 35691494d0..8b09bc38a2 100644
--- a/python/qemu/aqmp/qmp_shell.py
+++ b/python/qemu/qmp/qmp_shell.py
@@ -97,8 +97,8 @@
     Sequence,
 )
 
-from qemu.aqmp import ConnectError, QMPError, SocketAddrT
-from qemu.aqmp.legacy import (
+from qemu.qmp import ConnectError, QMPError, SocketAddrT
+from qemu.qmp.legacy import (
     QEMUMonitorProtocol,
     QMPBadPortError,
     QMPMessage,
diff --git a/python/qemu/aqmp/util.py b/python/qemu/qmp/util.py
similarity index 100%
rename from python/qemu/aqmp/util.py
rename to python/qemu/qmp/util.py
diff --git a/python/qemu/utils/qemu_ga_client.py b/python/qemu/utils/qemu_ga_client.py
index 15ed430c61..8c38a7ac9c 100644
--- a/python/qemu/utils/qemu_ga_client.py
+++ b/python/qemu/utils/qemu_ga_client.py
@@ -50,8 +50,8 @@
     Sequence,
 )
 
-from qemu.aqmp import ConnectError, SocketAddrT
-from qemu.aqmp.legacy import QEMUMonitorProtocol
+from qemu.qmp import ConnectError, SocketAddrT
+from qemu.qmp.legacy import QEMUMonitorProtocol
 
 
 # This script has not seen many patches or careful attention in quite
diff --git a/python/qemu/utils/qom.py b/python/qemu/utils/qom.py
index bb5d1a78f5..bcf192f477 100644
--- a/python/qemu/utils/qom.py
+++ b/python/qemu/utils/qom.py
@@ -32,7 +32,7 @@
 
 import argparse
 
-from qemu.aqmp import ExecuteError
+from qemu.qmp import ExecuteError
 
 from .qom_common import QOMCommand
 
diff --git a/python/qemu/utils/qom_common.py b/python/qemu/utils/qom_common.py
index e034a6f247..80da1b2304 100644
--- a/python/qemu/utils/qom_common.py
+++ b/python/qemu/utils/qom_common.py
@@ -27,8 +27,8 @@
     TypeVar,
 )
 
-from qemu.aqmp import QMPError
-from qemu.aqmp.legacy import QEMUMonitorProtocol
+from qemu.qmp import QMPError
+from qemu.qmp.legacy import QEMUMonitorProtocol
 
 
 class ObjectPropertyInfo:
diff --git a/python/qemu/utils/qom_fuse.py b/python/qemu/utils/qom_fuse.py
index 653a76b93b..8dcd59fcde 100644
--- a/python/qemu/utils/qom_fuse.py
+++ b/python/qemu/utils/qom_fuse.py
@@ -48,7 +48,7 @@
 import fuse
 from fuse import FUSE, FuseOSError, Operations
 
-from qemu.aqmp import ExecuteError
+from qemu.qmp import ExecuteError
 
 from .qom_common import QOMCommand
 
diff --git a/python/setup.cfg b/python/setup.cfg
index 49e3c285f1..773e51b34e 100644
--- a/python/setup.cfg
+++ b/python/setup.cfg
@@ -24,7 +24,7 @@ classifiers =
 [options]
 python_requires = >= 3.6
 packages =
-    qemu.aqmp
+    qemu.qmp
     qemu.machine
     qemu.utils
 
@@ -66,9 +66,9 @@ console_scripts =
     qom-tree = qemu.utils.qom:QOMTree.entry_point
     qom-fuse = qemu.utils.qom_fuse:QOMFuse.entry_point [fuse]
     qemu-ga-client = qemu.utils.qemu_ga_client:main
-    qmp-shell = qemu.aqmp.qmp_shell:main
-    qmp-shell-wrap = qemu.aqmp.qmp_shell:main_wrap
-    aqmp-tui = qemu.aqmp.aqmp_tui:main [tui]
+    qmp-shell = qemu.qmp.qmp_shell:main
+    qmp-shell-wrap = qemu.qmp.qmp_shell:main_wrap
+    aqmp-tui = qemu.qmp.aqmp_tui:main [tui]
 
 [flake8]
 extend-ignore = E722  # Prefer pylint's bare-except checks to flake8's
@@ -84,7 +84,7 @@ namespace_packages = True
 # fusepy has no type stubs:
 allow_subclassing_any = True
 
-[mypy-qemu.aqmp.aqmp_tui]
+[mypy-qemu.qmp.aqmp_tui]
 # urwid and urwid_readline have no type stubs:
 allow_subclassing_any = True
 
diff --git a/python/tests/protocol.py b/python/tests/protocol.py
index d6849ad306..56c4d441f9 100644
--- a/python/tests/protocol.py
+++ b/python/tests/protocol.py
@@ -6,9 +6,9 @@
 
 import avocado
 
-from qemu.aqmp import ConnectError, Runstate
-from qemu.aqmp.protocol import AsyncProtocol, StateError
-from qemu.aqmp.util import asyncio_run, create_task
+from qemu.qmp import ConnectError, Runstate
+from qemu.qmp.protocol import AsyncProtocol, StateError
+from qemu.qmp.util import asyncio_run, create_task
 
 
 class NullProtocol(AsyncProtocol[None]):
@@ -183,7 +183,7 @@ def testDefaultName(self):
     def testLogger(self):
         self.assertEqual(
             self.proto.logger.name,
-            'qemu.aqmp.protocol'
+            'qemu.qmp.protocol'
         )
 
     def testName(self):
@@ -196,7 +196,7 @@ def testName(self):
 
         self.assertEqual(
             self.proto.logger.name,
-            'qemu.aqmp.protocol.Steve'
+            'qemu.qmp.protocol.Steve'
         )
 
         self.assertEqual(
@@ -431,7 +431,7 @@ async def _bad_connection(self, family: str):
             await self.proto.start_server_and_accept('/dev/null')
 
     async def _hanging_connection(self):
-        with TemporaryDirectory(suffix='.aqmp') as tmpdir:
+        with TemporaryDirectory(suffix='.qmp') as tmpdir:
             sock = os.path.join(tmpdir, type(self.proto).__name__ + ".sock")
             await self.proto.start_server_and_accept(sock)
 
@@ -587,7 +587,7 @@ async def _asyncTearDown(self):
 
     @TestBase.async_test
     async def testSmoke(self):
-        with TemporaryDirectory(suffix='.aqmp') as tmpdir:
+        with TemporaryDirectory(suffix='.qmp') as tmpdir:
             sock = os.path.join(tmpdir, type(self.proto).__name__ + ".sock")
             server_task = create_task(self.server.start_server_and_accept(sock))
 
diff --git a/scripts/cpu-x86-uarch-abi.py b/scripts/cpu-x86-uarch-abi.py
index c262d2f027..82ff07582f 100644
--- a/scripts/cpu-x86-uarch-abi.py
+++ b/scripts/cpu-x86-uarch-abi.py
@@ -6,7 +6,7 @@
 # compatibility levels for each CPU model.
 #
 
-from qemu.aqmp.legacy import QEMUMonitorProtocol
+from qemu.qmp.legacy import QEMUMonitorProtocol
 import sys
 
 if len(sys.argv) != 2:
diff --git a/scripts/device-crash-test b/scripts/device-crash-test
index 7fbd99158b..4bfc68c008 100755
--- a/scripts/device-crash-test
+++ b/scripts/device-crash-test
@@ -36,7 +36,7 @@ from itertools import chain
 
 sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'python'))
 from qemu.machine import QEMUMachine
-from qemu.aqmp import ConnectError
+from qemu.qmp import ConnectError
 
 logger = logging.getLogger('device-crash-test')
 dbg = logger.debug
@@ -517,7 +517,7 @@ def main():
         # Async QMP, when in use, is chatty about connection failures.
         # This script knowingly generates a ton of connection errors.
         # Silence this logger.
-        logging.getLogger('qemu.aqmp.qmp_client').setLevel(logging.CRITICAL)
+        logging.getLogger('qemu.qmp.qmp_client').setLevel(logging.CRITICAL)
 
     fatal_failures = []
     wl_stats = {}
diff --git a/scripts/qmp/qmp-shell b/scripts/qmp/qmp-shell
index 31b19d73e2..4a20f97db7 100755
--- a/scripts/qmp/qmp-shell
+++ b/scripts/qmp/qmp-shell
@@ -4,7 +4,7 @@ import os
 import sys
 
 sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
-from qemu.aqmp import qmp_shell
+from qemu.qmp import qmp_shell
 
 
 if __name__ == '__main__':
diff --git a/scripts/qmp/qmp-shell-wrap b/scripts/qmp/qmp-shell-wrap
index 66846e36d1..9e94da114f 100755
--- a/scripts/qmp/qmp-shell-wrap
+++ b/scripts/qmp/qmp-shell-wrap
@@ -4,7 +4,7 @@ import os
 import sys
 
 sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
-from qemu.aqmp import qmp_shell
+from qemu.qmp import qmp_shell
 
 
 if __name__ == '__main__':
diff --git a/scripts/render_block_graph.py b/scripts/render_block_graph.py
index b33fb70d5e..8f731a5cfe 100755
--- a/scripts/render_block_graph.py
+++ b/scripts/render_block_graph.py
@@ -25,8 +25,8 @@
 from graphviz import Digraph
 
 sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'python'))
-from qemu.aqmp import QMPError
-from qemu.aqmp.legacy import QEMUMonitorProtocol
+from qemu.qmp import QMPError
+from qemu.qmp.legacy import QEMUMonitorProtocol
 
 
 def perm(arr):
diff --git a/scripts/simplebench/bench_block_job.py b/scripts/simplebench/bench_block_job.py
index af9d1646a4..56191db44b 100755
--- a/scripts/simplebench/bench_block_job.py
+++ b/scripts/simplebench/bench_block_job.py
@@ -27,7 +27,7 @@
 
 sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
 from qemu.machine import QEMUMachine
-from qemu.aqmp import ConnectError
+from qemu.qmp import ConnectError
 
 
 def bench_block_job(cmd, cmd_args, qemu_args):
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index 8760e2c310..9563749709 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -38,7 +38,7 @@
 from contextlib import contextmanager
 
 from qemu.machine import qtest
-from qemu.aqmp.legacy import QMPMessage, QEMUMonitorProtocol
+from qemu.qmp.legacy import QMPMessage, QEMUMonitorProtocol
 
 # Use this logger for logging messages directly from the iotests module
 logger = logging.getLogger('qemu.iotests')
diff --git a/tests/qemu-iotests/tests/mirror-top-perms b/tests/qemu-iotests/tests/mirror-top-perms
index 223f3c1620..d538579961 100755
--- a/tests/qemu-iotests/tests/mirror-top-perms
+++ b/tests/qemu-iotests/tests/mirror-top-perms
@@ -99,7 +99,7 @@ class TestMirrorTopPerms(iotests.QMPTestCase):
         self.vm_b.add_device('virtio-blk,drive=drive0,share-rw=on')
         try:
             # Silence AQMP logging errors temporarily.
-            with change_log_level('qemu.aqmp'):
+            with change_log_level('qemu.qmp'):
                 self.vm_b.launch()
                 print('ERROR: VM B launched successfully, '
                       'this should not have happened')
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 10/10] python: rename 'aqmp-tui' to 'qmp-tui'
  2022-03-21 21:08 [PATCH 00/10] Python: Remove synchronous QMP library John Snow
                   ` (8 preceding siblings ...)
  2022-03-21 21:08 ` [PATCH 09/10] python: rename qemu.aqmp to qemu.qmp John Snow
@ 2022-03-21 21:08 ` John Snow
  9 siblings, 0 replies; 25+ messages in thread
From: John Snow @ 2022-03-21 21:08 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Vladimir Sementsov-Ogievskiy, Beraldo Leal,
	qemu-block, Markus Armbruster, Hanna Reitz, Cleber Rosa,
	John Snow

This is the last vestige of the "aqmp" moniker surviving in the tree; remove it.

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Beraldo Leal <bleal@redhat.com>
---
 python/qemu/qmp/{aqmp_tui.py => qmp_tui.py} | 12 ++++++------
 python/setup.cfg                            |  6 +++---
 2 files changed, 9 insertions(+), 9 deletions(-)
 rename python/qemu/qmp/{aqmp_tui.py => qmp_tui.py} (98%)

diff --git a/python/qemu/qmp/aqmp_tui.py b/python/qemu/qmp/qmp_tui.py
similarity index 98%
rename from python/qemu/qmp/aqmp_tui.py
rename to python/qemu/qmp/qmp_tui.py
index 184a3e4690..17dc94e7c3 100644
--- a/python/qemu/qmp/aqmp_tui.py
+++ b/python/qemu/qmp/qmp_tui.py
@@ -6,13 +6,13 @@
 # This work is licensed under the terms of the GNU GPL, version 2 or
 # later.  See the COPYING file in the top-level directory.
 """
-AQMP TUI
+QMP TUI
 
-AQMP TUI is an asynchronous interface built on top the of the AQMP library.
+QMP TUI is an asynchronous interface built on top the of the QMP library.
 It is the successor of QMP-shell and is bought-in as a replacement for it.
 
-Example Usage: aqmp-tui <SOCKET | TCP IP:PORT>
-Full Usage: aqmp-tui --help
+Example Usage: qmp-tui <SOCKET | TCP IP:PORT>
+Full Usage: qmp-tui --help
 """
 
 import argparse
@@ -129,7 +129,7 @@ def has_handler_type(logger: logging.Logger,
 
 class App(QMPClient):
     """
-    Implements the AQMP TUI.
+    Implements the QMP TUI.
 
     Initializes the widgets and starts the urwid event loop.
 
@@ -612,7 +612,7 @@ def main() -> None:
     Driver of the whole script, parses arguments, initialize the TUI and
     the logger.
     """
-    parser = argparse.ArgumentParser(description='AQMP TUI')
+    parser = argparse.ArgumentParser(description='QMP TUI')
     parser.add_argument('qmp_server', help='Address of the QMP server. '
                         'Format <UNIX socket path | TCP addr:port>')
     parser.add_argument('--num-retries', type=int, default=10,
diff --git a/python/setup.cfg b/python/setup.cfg
index 773e51b34e..e877ea5647 100644
--- a/python/setup.cfg
+++ b/python/setup.cfg
@@ -51,7 +51,7 @@ devel =
 fuse =
     fusepy >= 2.0.4
 
-# AQMP TUI dependencies
+# QMP TUI dependencies
 tui =
     urwid >= 2.1.2
     urwid-readline >= 0.13
@@ -68,7 +68,7 @@ console_scripts =
     qemu-ga-client = qemu.utils.qemu_ga_client:main
     qmp-shell = qemu.qmp.qmp_shell:main
     qmp-shell-wrap = qemu.qmp.qmp_shell:main_wrap
-    aqmp-tui = qemu.qmp.aqmp_tui:main [tui]
+    qmp-tui = qemu.qmp.qmp_tui:main [tui]
 
 [flake8]
 extend-ignore = E722  # Prefer pylint's bare-except checks to flake8's
@@ -84,7 +84,7 @@ namespace_packages = True
 # fusepy has no type stubs:
 allow_subclassing_any = True
 
-[mypy-qemu.qmp.aqmp_tui]
+[mypy-qemu.qmp.qmp_tui]
 # urwid and urwid_readline have no type stubs:
 allow_subclassing_any = True
 
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH 09/10] python: rename qemu.aqmp to qemu.qmp
  2022-03-21 21:08 ` [PATCH 09/10] python: rename qemu.aqmp to qemu.qmp John Snow
@ 2022-03-23 18:19   ` Hanna Reitz
  2022-03-23 21:25     ` John Snow
  0 siblings, 1 reply; 25+ messages in thread
From: Hanna Reitz @ 2022-03-23 18:19 UTC (permalink / raw)
  To: John Snow, qemu-devel
  Cc: Kevin Wolf, Vladimir Sementsov-Ogievskiy, Beraldo Leal,
	qemu-block, Markus Armbruster, Cleber Rosa

On 21.03.22 22:08, John Snow wrote:
> Now that we are fully switched over to the new QMP library, move it back
> over the old namespace. This is being done primarily so that we may
> upload this package simply as "qemu.qmp" without introducing confusion
> over whether or not "aqmp" is a new protocol or not.
>
> The trade-off is increased confusion inside the QEMU developer
> tree. Sorry!
>
> Note: the 'private' member "_aqmp" in legacy.py also changes to "_qmp";
> not out of necessity, but just to remove any traces of the "aqmp"
> name.
>
> Signed-off-by: John Snow <jsnow@redhat.com>
> Reviewed-by: Beraldo Leal <bleal@redhat.com>
> ---

I guess this is the one for which I’m CC-ed?

[...]

> diff --git a/scripts/render_block_graph.py b/scripts/render_block_graph.py
> index b33fb70d5e..8f731a5cfe 100755
> --- a/scripts/render_block_graph.py
> +++ b/scripts/render_block_graph.py
> @@ -25,8 +25,8 @@
>   from graphviz import Digraph
>   
>   sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'python'))
> -from qemu.aqmp import QMPError
> -from qemu.aqmp.legacy import QEMUMonitorProtocol
> +from qemu.qmp import QMPError
> +from qemu.qmp.legacy import QEMUMonitorProtocol
>   
>   
>   def perm(arr):
> diff --git a/scripts/simplebench/bench_block_job.py b/scripts/simplebench/bench_block_job.py
> index af9d1646a4..56191db44b 100755
> --- a/scripts/simplebench/bench_block_job.py
> +++ b/scripts/simplebench/bench_block_job.py
> @@ -27,7 +27,7 @@
>   
>   sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
>   from qemu.machine import QEMUMachine
> -from qemu.aqmp import ConnectError
> +from qemu.qmp import ConnectError
>   
>   
>   def bench_block_job(cmd, cmd_args, qemu_args):
> diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
> index 8760e2c310..9563749709 100644
> --- a/tests/qemu-iotests/iotests.py
> +++ b/tests/qemu-iotests/iotests.py
> @@ -38,7 +38,7 @@
>   from contextlib import contextmanager
>   
>   from qemu.machine import qtest
> -from qemu.aqmp.legacy import QMPMessage, QEMUMonitorProtocol
> +from qemu.qmp.legacy import QMPMessage, QEMUMonitorProtocol

(Rebasing will change the order of imports; you fixed the (alphabetic) 
ordering in 2882ccf86a9, now you’re going to have to restore the 
original ordering here :))

>   # Use this logger for logging messages directly from the iotests module
>   logger = logging.getLogger('qemu.iotests')
> diff --git a/tests/qemu-iotests/tests/mirror-top-perms b/tests/qemu-iotests/tests/mirror-top-perms
> index 223f3c1620..d538579961 100755
> --- a/tests/qemu-iotests/tests/mirror-top-perms
> +++ b/tests/qemu-iotests/tests/mirror-top-perms
> @@ -99,7 +99,7 @@ class TestMirrorTopPerms(iotests.QMPTestCase):
>           self.vm_b.add_device('virtio-blk,drive=drive0,share-rw=on')
>           try:
>               # Silence AQMP logging errors temporarily.

Probably should just be “QMP” now, too.  Anyway:

Acked-by: Hanna Reitz <hreitz@redhat.com>

> -            with change_log_level('qemu.aqmp'):
> +            with change_log_level('qemu.qmp'):
>                   self.vm_b.launch()
>                   print('ERROR: VM B launched successfully, '
>                         'this should not have happened')



^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 06/10] python/aqmp: copy qmp docstrings to qemu.aqmp.legacy
  2022-03-21 21:08 ` [PATCH 06/10] python/aqmp: copy qmp docstrings to qemu.aqmp.legacy John Snow
@ 2022-03-23 18:24   ` Hanna Reitz
  2022-03-23 19:36     ` John Snow
  0 siblings, 1 reply; 25+ messages in thread
From: Hanna Reitz @ 2022-03-23 18:24 UTC (permalink / raw)
  To: John Snow, qemu-devel
  Cc: Kevin Wolf, Vladimir Sementsov-Ogievskiy, Beraldo Leal,
	qemu-block, Markus Armbruster, Cleber Rosa

On 21.03.22 22:08, John Snow wrote:
> Copy the docstrings out of qemu.qmp, adjusting them as necessary to
> more accurately reflect the current state of this class.
>
> (Licensing: This is copying and modifying GPLv2-only licensed docstrings
> into a GPLv2-only file.)
>
> Signed-off-by: John Snow <jsnow@redhat.com>
> Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
> Reviewed-by: Beraldo Leal <bleal@redhat.com>
> ---
>   python/qemu/aqmp/legacy.py | 102 ++++++++++++++++++++++++++++++++++---
>   1 file changed, 94 insertions(+), 8 deletions(-)
>
> diff --git a/python/qemu/aqmp/legacy.py b/python/qemu/aqmp/legacy.py
> index 10c7c99c4f..20ffdd8956 100644
> --- a/python/qemu/aqmp/legacy.py
> +++ b/python/qemu/aqmp/legacy.py

[...]

> @@ -60,6 +63,21 @@ class QMPBadPortError(QMPError):
>   
>   
>   class QEMUMonitorProtocol:
> +    """
> +    Provide an API to connect to QEMU via QEMU Monitor Protocol (QMP)
> +    and then allow to handle commands and events.
> +
> +    :param address:  QEMU address, can be either a unix socket path (string)
> +                     or a tuple in the form ( address, port ) for a TCP
> +                     connection
> +    :param server:   Deprecated, ignored. (See 'accept')

Can’t help but notice that this is (technically) just wrong, because it 
isn’t ignored.  Are you afraid people might not be sufficiently 
dissuaded by the “deprecated” keyword?  (I mean, if that were the case, 
I’d suggest you write “Deprecated, because setting this to true might 
make your computer explode” instead.)

Hanna

> +    :param nickname: Optional nickname used for logging.
> +
> +    ..note::
> +        No connection is established during `__init__`, this is done by
> +        the `connect()` or `accept()` methods.
> +    """
> +
>       def __init__(self, address: SocketAddrT,
>                    server: bool = False,
>                    nickname: Optional[str] = None):



^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 06/10] python/aqmp: copy qmp docstrings to qemu.aqmp.legacy
  2022-03-23 18:24   ` Hanna Reitz
@ 2022-03-23 19:36     ` John Snow
  0 siblings, 0 replies; 25+ messages in thread
From: John Snow @ 2022-03-23 19:36 UTC (permalink / raw)
  To: Hanna Reitz
  Cc: Kevin Wolf, Vladimir Sementsov-Ogievskiy, Beraldo Leal,
	Qemu-block, qemu-devel, Markus Armbruster, Cleber Rosa

On Wed, Mar 23, 2022 at 2:24 PM Hanna Reitz <hreitz@redhat.com> wrote:
>
> On 21.03.22 22:08, John Snow wrote:
> > Copy the docstrings out of qemu.qmp, adjusting them as necessary to
> > more accurately reflect the current state of this class.
> >
> > (Licensing: This is copying and modifying GPLv2-only licensed docstrings
> > into a GPLv2-only file.)
> >
> > Signed-off-by: John Snow <jsnow@redhat.com>
> > Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
> > Reviewed-by: Beraldo Leal <bleal@redhat.com>
> > ---
> >   python/qemu/aqmp/legacy.py | 102 ++++++++++++++++++++++++++++++++++---
> >   1 file changed, 94 insertions(+), 8 deletions(-)
> >
> > diff --git a/python/qemu/aqmp/legacy.py b/python/qemu/aqmp/legacy.py
> > index 10c7c99c4f..20ffdd8956 100644
> > --- a/python/qemu/aqmp/legacy.py
> > +++ b/python/qemu/aqmp/legacy.py
>
> [...]
>
> > @@ -60,6 +63,21 @@ class QMPBadPortError(QMPError):
> >
> >
> >   class QEMUMonitorProtocol:
> > +    """
> > +    Provide an API to connect to QEMU via QEMU Monitor Protocol (QMP)
> > +    and then allow to handle commands and events.
> > +
> > +    :param address:  QEMU address, can be either a unix socket path (string)
> > +                     or a tuple in the form ( address, port ) for a TCP
> > +                     connection
> > +    :param server:   Deprecated, ignored. (See 'accept')
>
> Can’t help but notice that this is (technically) just wrong, because it
> isn’t ignored.  Are you afraid people might not be sufficiently
> dissuaded by the “deprecated” keyword?  (I mean, if that were the case,
> I’d suggest you write “Deprecated, because setting this to true might
> make your computer explode” instead.)
>

Oops, this is outdated. I *did* drop this parameter. once. And then I
re-added it.

Thanks for noticing.

--js



^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 09/10] python: rename qemu.aqmp to qemu.qmp
  2022-03-23 18:19   ` Hanna Reitz
@ 2022-03-23 21:25     ` John Snow
  0 siblings, 0 replies; 25+ messages in thread
From: John Snow @ 2022-03-23 21:25 UTC (permalink / raw)
  To: Hanna Reitz
  Cc: Kevin Wolf, Vladimir Sementsov-Ogievskiy, Beraldo Leal,
	Qemu-block, qemu-devel, Markus Armbruster, Cleber Rosa

On Wed, Mar 23, 2022 at 2:20 PM Hanna Reitz <hreitz@redhat.com> wrote:
>
> On 21.03.22 22:08, John Snow wrote:
> > Now that we are fully switched over to the new QMP library, move it back
> > over the old namespace. This is being done primarily so that we may
> > upload this package simply as "qemu.qmp" without introducing confusion
> > over whether or not "aqmp" is a new protocol or not.
> >
> > The trade-off is increased confusion inside the QEMU developer
> > tree. Sorry!
> >
> > Note: the 'private' member "_aqmp" in legacy.py also changes to "_qmp";
> > not out of necessity, but just to remove any traces of the "aqmp"
> > name.
> >
> > Signed-off-by: John Snow <jsnow@redhat.com>
> > Reviewed-by: Beraldo Leal <bleal@redhat.com>
> > ---
>
> I guess this is the one for which I’m CC-ed?

Probably.

>
> [...]
>
> > diff --git a/scripts/render_block_graph.py b/scripts/render_block_graph.py
> > index b33fb70d5e..8f731a5cfe 100755
> > --- a/scripts/render_block_graph.py
> > +++ b/scripts/render_block_graph.py
> > @@ -25,8 +25,8 @@
> >   from graphviz import Digraph
> >
> >   sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'python'))
> > -from qemu.aqmp import QMPError
> > -from qemu.aqmp.legacy import QEMUMonitorProtocol
> > +from qemu.qmp import QMPError
> > +from qemu.qmp.legacy import QEMUMonitorProtocol
> >
> >
> >   def perm(arr):
> > diff --git a/scripts/simplebench/bench_block_job.py b/scripts/simplebench/bench_block_job.py
> > index af9d1646a4..56191db44b 100755
> > --- a/scripts/simplebench/bench_block_job.py
> > +++ b/scripts/simplebench/bench_block_job.py
> > @@ -27,7 +27,7 @@
> >
> >   sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
> >   from qemu.machine import QEMUMachine
> > -from qemu.aqmp import ConnectError
> > +from qemu.qmp import ConnectError
> >
> >
> >   def bench_block_job(cmd, cmd_args, qemu_args):
> > diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
> > index 8760e2c310..9563749709 100644
> > --- a/tests/qemu-iotests/iotests.py
> > +++ b/tests/qemu-iotests/iotests.py
> > @@ -38,7 +38,7 @@
> >   from contextlib import contextmanager
> >
> >   from qemu.machine import qtest
> > -from qemu.aqmp.legacy import QMPMessage, QEMUMonitorProtocol
> > +from qemu.qmp.legacy import QMPMessage, QEMUMonitorProtocol
>
> (Rebasing will change the order of imports; you fixed the (alphabetic)
> ordering in 2882ccf86a9, now you’re going to have to restore the
> original ordering here :))

I'll probably just fix stuff like this on merge when I go to send my
PR for this. Too fiddly otherwise.

>
> >   # Use this logger for logging messages directly from the iotests module
> >   logger = logging.getLogger('qemu.iotests')
> > diff --git a/tests/qemu-iotests/tests/mirror-top-perms b/tests/qemu-iotests/tests/mirror-top-perms
> > index 223f3c1620..d538579961 100755
> > --- a/tests/qemu-iotests/tests/mirror-top-perms
> > +++ b/tests/qemu-iotests/tests/mirror-top-perms
> > @@ -99,7 +99,7 @@ class TestMirrorTopPerms(iotests.QMPTestCase):
> >           self.vm_b.add_device('virtio-blk,drive=drive0,share-rw=on')
> >           try:
> >               # Silence AQMP logging errors temporarily.
>
> Probably should just be “QMP” now, too.  Anyway:

Yep, oops. I didn't refresh this series as much as I should have. It
was good the last time I checked it, I swear! ... three months ago.

>
> Acked-by: Hanna Reitz <hreitz@redhat.com>

Thanks.

>
> > -            with change_log_level('qemu.aqmp'):
> > +            with change_log_level('qemu.qmp'):
> >                   self.vm_b.launch()
> >                   print('ERROR: VM B launched successfully, '
> >                         'this should not have happened')
>



^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 01/10] python/aqmp: add explicit GPLv2 license to legacy.py
  2022-03-21 21:08 ` [PATCH 01/10] python/aqmp: add explicit GPLv2 license to legacy.py John Snow
@ 2022-03-23 21:47   ` John Snow
  2022-03-24  8:59     ` Daniel P. Berrangé
  0 siblings, 1 reply; 25+ messages in thread
From: John Snow @ 2022-03-23 21:47 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Vladimir Sementsov-Ogievskiy, Daniel Berrange,
	Beraldo Leal, Qemu-block, Markus Armbruster, Andrea Bolognani,
	Hanna Reitz, Cleber Rosa, Luiz Capitulino

On Mon, Mar 21, 2022 at 5:08 PM John Snow <jsnow@redhat.com> wrote:
>
> The legacy.py module is heavily based on the QMP module by Luiz
> Capitulino (et al) which is licensed as explicit GPLv2-only. The async
> QMP package is currently licensed similarly, but I intend to relicense
> the async package to the more flexible GPLv2+.
>
> In preparation for that change, make the license on legacy.py explicit.
>
> Signed-off-by: John Snow <jsnow@redhat.com>
> ---
>  python/qemu/aqmp/legacy.py | 11 +++++++++++
>  1 file changed, 11 insertions(+)
>
> diff --git a/python/qemu/aqmp/legacy.py b/python/qemu/aqmp/legacy.py
> index 46026e9fdc..f86cb29804 100644
> --- a/python/qemu/aqmp/legacy.py
> +++ b/python/qemu/aqmp/legacy.py
> @@ -4,6 +4,17 @@
>  This class pretends to be qemu.qmp.QEMUMonitorProtocol.
>  """
>
> +#
> +# Copyright (C) 2009-2022 Red Hat Inc.
> +#
> +# Authors:
> +#  Luiz Capitulino <lcapitulino@redhat.com>
> +#  John Snow <jsnow@redhat.com>
> +#
> +# This work is licensed under the terms of the GNU GPL, version 2.  See
> +# the COPYING file in the top-level directory.
> +#
> +
>  import asyncio
>  from typing import (
>      Any,
> --
> 2.34.1
>

Anyone have any strong feelings on me doing this? CC'ing people with
known strong feelings on licenses.

I'm:

(1) Re-affirming that the legacy interface for async QMP is GPLv2
(like the classic QMP library is), because the interface and
docstrings here are largely copy-pasted from that library. It's
heavily remixed and modified, but it is undeniably derivative. (This
patch)

(2) Re-licensing async QMP as GPLv2+. (Next patch)

(3) Someday, eventually, adding a different sync interface that
doesn't re-mix this specific compatibility interface and will provide
better event-waiting primitives and so on. legacy.py will get dropped
at that point and the sub-project will become wholly GPLv2+. Until
then, it will be mixed.

--js



^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 01/10] python/aqmp: add explicit GPLv2 license to legacy.py
  2022-03-23 21:47   ` John Snow
@ 2022-03-24  8:59     ` Daniel P. Berrangé
  2022-03-24  9:03       ` Daniel P. Berrangé
  0 siblings, 1 reply; 25+ messages in thread
From: Daniel P. Berrangé @ 2022-03-24  8:59 UTC (permalink / raw)
  To: John Snow
  Cc: Kevin Wolf, Vladimir Sementsov-Ogievskiy, Beraldo Leal,
	Qemu-block, qemu-devel, Markus Armbruster, Hanna Reitz,
	Andrea Bolognani, Cleber Rosa, Luiz Capitulino

On Wed, Mar 23, 2022 at 05:47:48PM -0400, John Snow wrote:
> On Mon, Mar 21, 2022 at 5:08 PM John Snow <jsnow@redhat.com> wrote:
> >
> > The legacy.py module is heavily based on the QMP module by Luiz
> > Capitulino (et al) which is licensed as explicit GPLv2-only. The async
> > QMP package is currently licensed similarly, but I intend to relicense
> > the async package to the more flexible GPLv2+.
> >
> > In preparation for that change, make the license on legacy.py explicit.
> >
> > Signed-off-by: John Snow <jsnow@redhat.com>
> > ---
> >  python/qemu/aqmp/legacy.py | 11 +++++++++++
> >  1 file changed, 11 insertions(+)
> >
> > diff --git a/python/qemu/aqmp/legacy.py b/python/qemu/aqmp/legacy.py
> > index 46026e9fdc..f86cb29804 100644
> > --- a/python/qemu/aqmp/legacy.py
> > +++ b/python/qemu/aqmp/legacy.py
> > @@ -4,6 +4,17 @@
> >  This class pretends to be qemu.qmp.QEMUMonitorProtocol.
> >  """
> >
> > +#
> > +# Copyright (C) 2009-2022 Red Hat Inc.
> > +#
> > +# Authors:
> > +#  Luiz Capitulino <lcapitulino@redhat.com>
> > +#  John Snow <jsnow@redhat.com>
> > +#
> > +# This work is licensed under the terms of the GNU GPL, version 2.  See
> > +# the COPYING file in the top-level directory.
> > +#
> > +
> >  import asyncio
> >  from typing import (
> >      Any,
> > --
> > 2.34.1
> >
> 
> Anyone have any strong feelings on me doing this? CC'ing people with
> known strong feelings on licenses.
> 
> I'm:
> 
> (1) Re-affirming that the legacy interface for async QMP is GPLv2
> (like the classic QMP library is), because the interface and
> docstrings here are largely copy-pasted from that library. It's
> heavily remixed and modified, but it is undeniably derivative. (This
> patch)

If this is going to live for any length of time it is desirable to
relience the legacy code to GPLv2+ too.

I've not fully audited the git history, but what little I've looked
at, the relicensing doesn't look too hard. The overwhealming majority
of code was by @redhat.com authors, so we can cope with that fairly
easily. There are a handful of other contributors still around in
QEMU, and some of the patches are so trivial you couldn't claim
copyright on them ie where adding 1 parameter to a method call is 
literally the only possible way you could implmenent the change.
It is never fun to contact everyone, but it looks viable.

> (2) Re-licensing async QMP as GPLv2+. (Next patch)
> 
> (3) Someday, eventually, adding a different sync interface that
> doesn't re-mix this specific compatibility interface and will provide
> better event-waiting primitives and so on. legacy.py will get dropped
> at that point and the sub-project will become wholly GPLv2+. Until
> then, it will be mixed.

Overall making it *all* GPLv2+ compat is going to be important if you
want people to be comfortable using it. If it has a mix of GPLv2+
and GPLv2-only code in the source tarball, then the overall combined
work will have to be considered GPLv2-only and that will put people
off using it. Even if they could theoreticallly restrict their usage
to only the GPLv2+ parts, many won't get that far before moving on.

With 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 :|



^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 01/10] python/aqmp: add explicit GPLv2 license to legacy.py
  2022-03-24  8:59     ` Daniel P. Berrangé
@ 2022-03-24  9:03       ` Daniel P. Berrangé
  2022-03-24 14:29         ` Andrea Bolognani
  2022-03-24 15:03         ` John Snow
  0 siblings, 2 replies; 25+ messages in thread
From: Daniel P. Berrangé @ 2022-03-24  9:03 UTC (permalink / raw)
  To: John Snow, qemu-devel, Hanna Reitz, Cleber Rosa,
	Vladimir Sementsov-Ogievskiy, Qemu-block, Kevin Wolf,
	Beraldo Leal, Markus Armbruster, Andrea Bolognani,
	Luiz Capitulino

On Thu, Mar 24, 2022 at 09:00:05AM +0000, Daniel P. Berrangé wrote:
> On Wed, Mar 23, 2022 at 05:47:48PM -0400, John Snow wrote:
> > On Mon, Mar 21, 2022 at 5:08 PM John Snow <jsnow@redhat.com> wrote:
> > >
> > > The legacy.py module is heavily based on the QMP module by Luiz
> > > Capitulino (et al) which is licensed as explicit GPLv2-only. The async
> > > QMP package is currently licensed similarly, but I intend to relicense
> > > the async package to the more flexible GPLv2+.
> > >
> > > In preparation for that change, make the license on legacy.py explicit.
> > >
> > > Signed-off-by: John Snow <jsnow@redhat.com>
> > > ---
> > >  python/qemu/aqmp/legacy.py | 11 +++++++++++
> > >  1 file changed, 11 insertions(+)
> > >
> > > diff --git a/python/qemu/aqmp/legacy.py b/python/qemu/aqmp/legacy.py
> > > index 46026e9fdc..f86cb29804 100644
> > > --- a/python/qemu/aqmp/legacy.py
> > > +++ b/python/qemu/aqmp/legacy.py
> > > @@ -4,6 +4,17 @@
> > >  This class pretends to be qemu.qmp.QEMUMonitorProtocol.
> > >  """
> > >
> > > +#
> > > +# Copyright (C) 2009-2022 Red Hat Inc.
> > > +#
> > > +# Authors:
> > > +#  Luiz Capitulino <lcapitulino@redhat.com>
> > > +#  John Snow <jsnow@redhat.com>
> > > +#
> > > +# This work is licensed under the terms of the GNU GPL, version 2.  See
> > > +# the COPYING file in the top-level directory.
> > > +#
> > > +
> > >  import asyncio
> > >  from typing import (
> > >      Any,
> > > --
> > > 2.34.1
> > >
> > 
> > Anyone have any strong feelings on me doing this? CC'ing people with
> > known strong feelings on licenses.
> > 
> > I'm:
> > 
> > (1) Re-affirming that the legacy interface for async QMP is GPLv2
> > (like the classic QMP library is), because the interface and
> > docstrings here are largely copy-pasted from that library. It's
> > heavily remixed and modified, but it is undeniably derivative. (This
> > patch)
> 
> If this is going to live for any length of time it is desirable to
> relience the legacy code to GPLv2+ too.
> 
> I've not fully audited the git history, but what little I've looked
> at, the relicensing doesn't look too hard. The overwhealming majority
> of code was by @redhat.com authors, so we can cope with that fairly
> easily. There are a handful of other contributors still around in
> QEMU, and some of the patches are so trivial you couldn't claim
> copyright on them ie where adding 1 parameter to a method call is 
> literally the only possible way you could implmenent the change.
> It is never fun to contact everyone, but it looks viable.
> 
> > (2) Re-licensing async QMP as GPLv2+. (Next patch)
> > 
> > (3) Someday, eventually, adding a different sync interface that
> > doesn't re-mix this specific compatibility interface and will provide
> > better event-waiting primitives and so on. legacy.py will get dropped
> > at that point and the sub-project will become wholly GPLv2+. Until
> > then, it will be mixed.
> 
> Overall making it *all* GPLv2+ compat is going to be important if you
> want people to be comfortable using it. If it has a mix of GPLv2+
> and GPLv2-only code in the source tarball, then the overall combined
> work will have to be considered GPLv2-only and that will put people
> off using it. Even if they could theoreticallly restrict their usage
> to only the GPLv2+ parts, many won't get that far before moving on.

Actually I'll go furthuer and suggest that if we're going to do a
relicensing at all, and your goal is to encourage usage, then GPLv2+
is the wrong choice. Use LGPLv2+ if you want to facilitate usage, while
retaining a copyleft license.

With 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 :|



^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 01/10] python/aqmp: add explicit GPLv2 license to legacy.py
  2022-03-24  9:03       ` Daniel P. Berrangé
@ 2022-03-24 14:29         ` Andrea Bolognani
  2022-03-24 14:47           ` Daniel P. Berrangé
  2022-03-24 15:03         ` John Snow
  1 sibling, 1 reply; 25+ messages in thread
From: Andrea Bolognani @ 2022-03-24 14:29 UTC (permalink / raw)
  To: Daniel P. Berrangé
  Cc: Kevin Wolf, Vladimir Sementsov-Ogievskiy, Beraldo Leal,
	Qemu-block, qemu-devel, Markus Armbruster, Hanna Reitz,
	Cleber Rosa, Luiz Capitulino, John Snow

On Thu, Mar 24, 2022 at 09:03:07AM +0000, Daniel P. Berrangé wrote:
> > Overall making it *all* GPLv2+ compat is going to be important if you
> > want people to be comfortable using it. If it has a mix of GPLv2+
> > and GPLv2-only code in the source tarball, then the overall combined
> > work will have to be considered GPLv2-only and that will put people
> > off using it. Even if they could theoreticallly restrict their usage
> > to only the GPLv2+ parts, many won't get that far before moving on.

Agreed.

> Actually I'll go furthuer and suggest that if we're going to do a
> relicensing at all, and your goal is to encourage usage, then GPLv2+
> is the wrong choice. Use LGPLv2+ if you want to facilitate usage, while
> retaining a copyleft license.

Does LGPL make sense in the context of Python, where there is no
linking?

-- 
Andrea Bolognani / Red Hat / Virtualization



^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 01/10] python/aqmp: add explicit GPLv2 license to legacy.py
  2022-03-24 14:29         ` Andrea Bolognani
@ 2022-03-24 14:47           ` Daniel P. Berrangé
  0 siblings, 0 replies; 25+ messages in thread
From: Daniel P. Berrangé @ 2022-03-24 14:47 UTC (permalink / raw)
  To: Andrea Bolognani
  Cc: Kevin Wolf, Vladimir Sementsov-Ogievskiy, Beraldo Leal,
	Qemu-block, qemu-devel, Markus Armbruster, Hanna Reitz,
	Cleber Rosa, Luiz Capitulino, John Snow

On Thu, Mar 24, 2022 at 02:29:25PM +0000, Andrea Bolognani wrote:
> On Thu, Mar 24, 2022 at 09:03:07AM +0000, Daniel P. Berrangé wrote:
> > > Overall making it *all* GPLv2+ compat is going to be important if you
> > > want people to be comfortable using it. If it has a mix of GPLv2+
> > > and GPLv2-only code in the source tarball, then the overall combined
> > > work will have to be considered GPLv2-only and that will put people
> > > off using it. Even if they could theoreticallly restrict their usage
> > > to only the GPLv2+ parts, many won't get that far before moving on.
> 
> Agreed.
> 
> > Actually I'll go furthuer and suggest that if we're going to do a
> > relicensing at all, and your goal is to encourage usage, then GPLv2+
> > is the wrong choice. Use LGPLv2+ if you want to facilitate usage, while
> > retaining a copyleft license.
> 
> Does LGPL make sense in the context of Python, where there is no
> linking?

It isn't linking in the native binary sense of the word, but I'd
still consider in "linking" in the more general sense that you're
combining two distinct pieces of work, one of which is a library.

BSD/MIT is more common in the arbitrary snapshot of installed pyton
mods on my system, but there are still a decent number of GPL and
LGPL licensed python modules, and I'd consider the distinction
between GPL and LGPL to still be valid for Python apps.

Ultimately QEMU has been a copyleft licenses project, so I feel
that's a preferrable choice to stick with for the python code,
over the totally permissive licenses.

With 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 :|



^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 01/10] python/aqmp: add explicit GPLv2 license to legacy.py
  2022-03-24  9:03       ` Daniel P. Berrangé
  2022-03-24 14:29         ` Andrea Bolognani
@ 2022-03-24 15:03         ` John Snow
  2022-03-24 15:25           ` Daniel P. Berrangé
  1 sibling, 1 reply; 25+ messages in thread
From: John Snow @ 2022-03-24 15:03 UTC (permalink / raw)
  To: Daniel P. Berrangé
  Cc: Kevin Wolf, Vladimir Sementsov-Ogievskiy, Beraldo Leal,
	Qemu-block, qemu-devel, Markus Armbruster, Hanna Reitz,
	Andrea Bolognani, Cleber Rosa, Luiz Capitulino

[-- Attachment #1: Type: text/plain, Size: 5634 bytes --]

On Thu, Mar 24, 2022, 5:03 AM Daniel P. Berrangé <berrange@redhat.com>
wrote:

> On Thu, Mar 24, 2022 at 09:00:05AM +0000, Daniel P. Berrangé wrote:
> > On Wed, Mar 23, 2022 at 05:47:48PM -0400, John Snow wrote:
> > > On Mon, Mar 21, 2022 at 5:08 PM John Snow <jsnow@redhat.com> wrote:
> > > >
> > > > The legacy.py module is heavily based on the QMP module by Luiz
> > > > Capitulino (et al) which is licensed as explicit GPLv2-only. The
> async
> > > > QMP package is currently licensed similarly, but I intend to
> relicense
> > > > the async package to the more flexible GPLv2+.
> > > >
> > > > In preparation for that change, make the license on legacy.py
> explicit.
> > > >
> > > > Signed-off-by: John Snow <jsnow@redhat.com>
> > > > ---
> > > >  python/qemu/aqmp/legacy.py | 11 +++++++++++
> > > >  1 file changed, 11 insertions(+)
> > > >
> > > > diff --git a/python/qemu/aqmp/legacy.py b/python/qemu/aqmp/legacy.py
> > > > index 46026e9fdc..f86cb29804 100644
> > > > --- a/python/qemu/aqmp/legacy.py
> > > > +++ b/python/qemu/aqmp/legacy.py
> > > > @@ -4,6 +4,17 @@
> > > >  This class pretends to be qemu.qmp.QEMUMonitorProtocol.
> > > >  """
> > > >
> > > > +#
> > > > +# Copyright (C) 2009-2022 Red Hat Inc.
> > > > +#
> > > > +# Authors:
> > > > +#  Luiz Capitulino <lcapitulino@redhat.com>
> > > > +#  John Snow <jsnow@redhat.com>
> > > > +#
> > > > +# This work is licensed under the terms of the GNU GPL, version 2.
> See
> > > > +# the COPYING file in the top-level directory.
> > > > +#
> > > > +
> > > >  import asyncio
> > > >  from typing import (
> > > >      Any,
> > > > --
> > > > 2.34.1
> > > >
> > >
> > > Anyone have any strong feelings on me doing this? CC'ing people with
> > > known strong feelings on licenses.
> > >
> > > I'm:
> > >
> > > (1) Re-affirming that the legacy interface for async QMP is GPLv2
> > > (like the classic QMP library is), because the interface and
> > > docstrings here are largely copy-pasted from that library. It's
> > > heavily remixed and modified, but it is undeniably derivative. (This
> > > patch)
> >
> > If this is going to live for any length of time it is desirable to
> > relience the legacy code to GPLv2+ too.
>

I do intend to drop legacy.py, replacing it with a sync.py module that's
similar, but provides an API that resembles the async API more closely.

I have patches, so it shouldn't be *too* far out, but I wanted to fork the
repo first, since it's kind of involved and fiddly.

It's genuinely a question of "What can I achieve faster?"

It's unclear, but before I fork the async code out into its own repository,
I wanted a better license on it while I'm still the sole author. So I
figured "Mostly new license, tiny bits of old" would be the best, quickest
way to prevent a backslide.

>
> > I've not fully audited the git history, but what little I've looked
> > at, the relicensing doesn't look too hard. The overwhealming majority
> > of code was by @redhat.com authors, so we can cope with that fairly
> > easily. There are a handful of other contributors still around in
> > QEMU, and some of the patches are so trivial you couldn't claim
> > copyright on them ie where adding 1 parameter to a method call is
> > literally the only possible way you could implmenent the change.
> > It is never fun to contact everyone, but it looks viable.
> >
> > > (2) Re-licensing async QMP as GPLv2+. (Next patch)
> > >
> > > (3) Someday, eventually, adding a different sync interface that
> > > doesn't re-mix this specific compatibility interface and will provide
> > > better event-waiting primitives and so on. legacy.py will get dropped
> > > at that point and the sub-project will become wholly GPLv2+. Until
> > > then, it will be mixed.
> >
> > Overall making it *all* GPLv2+ compat is going to be important if you
> > want people to be comfortable using it. If it has a mix of GPLv2+
> > and GPLv2-only code in the source tarball, then the overall combined
> > work will have to be considered GPLv2-only and that will put people
> > off using it. Even if they could theoreticallly restrict their usage
> > to only the GPLv2+ parts, many won't get that far before moving on.
>

I agree. Just a matter of which intermediate states we'll see enroute.


> Actually I'll go furthuer and suggest that if we're going to do a
> relicensing at all, and your goal is to encourage usage, then GPLv2+
> is the wrong choice. Use LGPLv2+ if you want to facilitate usage, while
> retaining a copyleft license.
>

Same question as Andrea. Does the linking exception matter for Python? (The
lawyer seemed to intuit to me that it was somewhat untested. I don't think
the answer was clear.)

I have no opposition towards LGPL whatsoever, so I guess if it doesn't hurt
anything I can just do that instead.

(The lawyer did suggest that MIT was likely the absolute most compatible
license I could choose here; but I'm unsure I want to open the floodgates
that wide without strong reason. MIT feels like an off-ramp out of open
source, and I like to avoid it when possible. That said, the point of this
package is to get people to use QEMU and drive them towards our GPL project
and ecosystem, so... Maybe MIT would be reasonable. Still, if this
component grows in complexity and becomes integrated into a commercial
product, I'd be *pretty upset* if any improvements were not published for
everyone to benefit from. I think that's why I lean GPL, even though I want
to maximize use.)


> With regards,
> Daniel
> --


Thanks,
--js

[-- Attachment #2: Type: text/html, Size: 8097 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 01/10] python/aqmp: add explicit GPLv2 license to legacy.py
  2022-03-24 15:03         ` John Snow
@ 2022-03-24 15:25           ` Daniel P. Berrangé
  2022-03-24 16:07             ` John Snow
  0 siblings, 1 reply; 25+ messages in thread
From: Daniel P. Berrangé @ 2022-03-24 15:25 UTC (permalink / raw)
  To: John Snow
  Cc: Kevin Wolf, Vladimir Sementsov-Ogievskiy, Beraldo Leal,
	Qemu-block, qemu-devel, Markus Armbruster, Hanna Reitz,
	Andrea Bolognani, Cleber Rosa, Luiz Capitulino

On Thu, Mar 24, 2022 at 11:03:12AM -0400, John Snow wrote:
> On Thu, Mar 24, 2022, 5:03 AM Daniel P. Berrangé <berrange@redhat.com>
> wrote:
> 
> > On Thu, Mar 24, 2022 at 09:00:05AM +0000, Daniel P. Berrangé wrote:
> > > I've not fully audited the git history, but what little I've looked
> > > at, the relicensing doesn't look too hard. The overwhealming majority
> > > of code was by @redhat.com authors, so we can cope with that fairly
> > > easily. There are a handful of other contributors still around in
> > > QEMU, and some of the patches are so trivial you couldn't claim
> > > copyright on them ie where adding 1 parameter to a method call is
> > > literally the only possible way you could implmenent the change.
> > > It is never fun to contact everyone, but it looks viable.
> > >
> > > > (2) Re-licensing async QMP as GPLv2+. (Next patch)
> > > >
> > > > (3) Someday, eventually, adding a different sync interface that
> > > > doesn't re-mix this specific compatibility interface and will provide
> > > > better event-waiting primitives and so on. legacy.py will get dropped
> > > > at that point and the sub-project will become wholly GPLv2+. Until
> > > > then, it will be mixed.
> > >
> > > Overall making it *all* GPLv2+ compat is going to be important if you
> > > want people to be comfortable using it. If it has a mix of GPLv2+
> > > and GPLv2-only code in the source tarball, then the overall combined
> > > work will have to be considered GPLv2-only and that will put people
> > > off using it. Even if they could theoreticallly restrict their usage
> > > to only the GPLv2+ parts, many won't get that far before moving on.
> >
> 
> I agree. Just a matter of which intermediate states we'll see enroute.
> 
> 
> > Actually I'll go furthuer and suggest that if we're going to do a
> > relicensing at all, and your goal is to encourage usage, then GPLv2+
> > is the wrong choice. Use LGPLv2+ if you want to facilitate usage, while
> > retaining a copyleft license.
> >
> 
> Same question as Andrea. Does the linking exception matter for Python? (The
> lawyer seemed to intuit to me that it was somewhat untested. I don't think
> the answer was clear.)
> 
> I have no opposition towards LGPL whatsoever, so I guess if it doesn't hurt
> anything I can just do that instead.

Let us contemplate two scenarios

 - GPL vs LGPL  *does* make a legal difference for Python, in the
   same way it does for C

      => Using LGPL over GPL is therefore a benefit for QEMU users

 - GPL vs LGPL does *not* make  a legal difference for Python, in
   the same way it does for C

      => Using LGPL over GPL makes zero differnce for QEMU users

In the absence of information that can confidently predict
which scenario applies, then the right answer is to pick LGPL.
It might be a benefit, and if no, it has no downside [1].


[1] Yes, there could be some subtle reason why LGPL is worse
    than GPL in Python than in C, but I've not seen sign of
    that being raised, and I have seen plenty of POVs saying
    LGPL is still a benefit.

> (The lawyer did suggest that MIT was likely the absolute most compatible
> license I could choose here; but I'm unsure I want to open the floodgates
> that wide without strong reason. MIT feels like an off-ramp out of open
> source, and I like to avoid it when possible. That said, the point of this
> package is to get people to use QEMU and drive them towards our GPL project
> and ecosystem, so... Maybe MIT would be reasonable. Still, if this
> component grows in complexity and becomes integrated into a commercial
> product, I'd be *pretty upset* if any improvements were not published for
> everyone to benefit from. I think that's why I lean GPL, even though I want
> to maximize use.)

Yep, as I mentioned, I don't want to see us abandon copyleft either.

Of course everyone has their own preferred license, so I'm sure
people who write apps with MIT, will think we should use MIT
too. Ultimately though, if we choose LGPL, they can still use
our module from an MIT licensed app, or any other licensed app
for that matter.

With 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 :|



^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 01/10] python/aqmp: add explicit GPLv2 license to legacy.py
  2022-03-24 15:25           ` Daniel P. Berrangé
@ 2022-03-24 16:07             ` John Snow
  2022-03-25 14:55               ` Eric Blake
  0 siblings, 1 reply; 25+ messages in thread
From: John Snow @ 2022-03-24 16:07 UTC (permalink / raw)
  To: Daniel P. Berrangé
  Cc: Kevin Wolf, Vladimir Sementsov-Ogievskiy, Beraldo Leal,
	Qemu-block, qemu-devel, Markus Armbruster, Hanna Reitz,
	Andrea Bolognani, Cleber Rosa, Luiz Capitulino

On Thu, Mar 24, 2022 at 11:25 AM Daniel P. Berrangé <berrange@redhat.com> wrote:
>
> On Thu, Mar 24, 2022 at 11:03:12AM -0400, John Snow wrote:
> > On Thu, Mar 24, 2022, 5:03 AM Daniel P. Berrangé <berrange@redhat.com>
> > wrote:
> >
> > > On Thu, Mar 24, 2022 at 09:00:05AM +0000, Daniel P. Berrangé wrote:
> > > > I've not fully audited the git history, but what little I've looked
> > > > at, the relicensing doesn't look too hard. The overwhealming majority
> > > > of code was by @redhat.com authors, so we can cope with that fairly
> > > > easily. There are a handful of other contributors still around in
> > > > QEMU, and some of the patches are so trivial you couldn't claim
> > > > copyright on them ie where adding 1 parameter to a method call is
> > > > literally the only possible way you could implmenent the change.
> > > > It is never fun to contact everyone, but it looks viable.
> > > >
> > > > > (2) Re-licensing async QMP as GPLv2+. (Next patch)
> > > > >
> > > > > (3) Someday, eventually, adding a different sync interface that
> > > > > doesn't re-mix this specific compatibility interface and will provide
> > > > > better event-waiting primitives and so on. legacy.py will get dropped
> > > > > at that point and the sub-project will become wholly GPLv2+. Until
> > > > > then, it will be mixed.
> > > >
> > > > Overall making it *all* GPLv2+ compat is going to be important if you
> > > > want people to be comfortable using it. If it has a mix of GPLv2+
> > > > and GPLv2-only code in the source tarball, then the overall combined
> > > > work will have to be considered GPLv2-only and that will put people
> > > > off using it. Even if they could theoreticallly restrict their usage
> > > > to only the GPLv2+ parts, many won't get that far before moving on.
> > >
> >
> > I agree. Just a matter of which intermediate states we'll see enroute.
> >
> >
> > > Actually I'll go furthuer and suggest that if we're going to do a
> > > relicensing at all, and your goal is to encourage usage, then GPLv2+
> > > is the wrong choice. Use LGPLv2+ if you want to facilitate usage, while
> > > retaining a copyleft license.
> > >
> >
> > Same question as Andrea. Does the linking exception matter for Python? (The
> > lawyer seemed to intuit to me that it was somewhat untested. I don't think
> > the answer was clear.)
> >
> > I have no opposition towards LGPL whatsoever, so I guess if it doesn't hurt
> > anything I can just do that instead.
>
> Let us contemplate two scenarios
>
>  - GPL vs LGPL  *does* make a legal difference for Python, in the
>    same way it does for C
>
>       => Using LGPL over GPL is therefore a benefit for QEMU users
>
>  - GPL vs LGPL does *not* make  a legal difference for Python, in
>    the same way it does for C
>
>       => Using LGPL over GPL makes zero differnce for QEMU users
>
> In the absence of information that can confidently predict
> which scenario applies, then the right answer is to pick LGPL.
> It might be a benefit, and if no, it has no downside [1].
>
>
> [1] Yes, there could be some subtle reason why LGPL is worse
>     than GPL in Python than in C, but I've not seen sign of
>     that being raised, and I have seen plenty of POVs saying
>     LGPL is still a benefit.
>
> > (The lawyer did suggest that MIT was likely the absolute most compatible
> > license I could choose here; but I'm unsure I want to open the floodgates
> > that wide without strong reason. MIT feels like an off-ramp out of open
> > source, and I like to avoid it when possible. That said, the point of this
> > package is to get people to use QEMU and drive them towards our GPL project
> > and ecosystem, so... Maybe MIT would be reasonable. Still, if this
> > component grows in complexity and becomes integrated into a commercial
> > product, I'd be *pretty upset* if any improvements were not published for
> > everyone to benefit from. I think that's why I lean GPL, even though I want
> > to maximize use.)
>
> Yep, as I mentioned, I don't want to see us abandon copyleft either.
>
> Of course everyone has their own preferred license, so I'm sure
> people who write apps with MIT, will think we should use MIT
> too. Ultimately though, if we choose LGPL, they can still use
> our module from an MIT licensed app, or any other licensed app
> for that matter.
>

OK, thanks for your input here. My plan right now, then, is:

(1) Relicense aqmp as LGPLv2+
(2) Fork into new repo as discussed previously on qemu-devel
(3) Work on dropping legacy.py (GPLv2) in favor of sync.py (LGPLv2+)

I plan to version the fledgling forked repo as 0.0.z until I drop
legacy.py, and then I'll version as 0.y.z for "a while", (A release or
two for QEMU?), and then tag v1.0.0.
(As we discussed earlier, with a non-finalized API, I'll be pinning
QEMU to use specific versions until it stabilizes.)

I think you're right that we probably could relicense legacy.py
without too much fuss, I think the most significant contributions that
didn't come from Luiz or myself were made to docstrings, and only
extremely few contributions came from non-RH addresses. Still, I plan
to drop the whole file anyway, so I figured I'd side-step the
relicensing justification there, even if it's doable.

--js



^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 01/10] python/aqmp: add explicit GPLv2 license to legacy.py
  2022-03-24 16:07             ` John Snow
@ 2022-03-25 14:55               ` Eric Blake
  2022-03-25 17:32                 ` John Snow
  0 siblings, 1 reply; 25+ messages in thread
From: Eric Blake @ 2022-03-25 14:55 UTC (permalink / raw)
  To: John Snow
  Cc: Kevin Wolf, Vladimir Sementsov-Ogievskiy, Daniel P. Berrangé,
	Beraldo Leal, Qemu-block, qemu-devel, Markus Armbruster,
	Hanna Reitz, Andrea Bolognani, Cleber Rosa, Luiz Capitulino

On Thu, Mar 24, 2022 at 12:07:24PM -0400, John Snow wrote:
...
> > Yep, as I mentioned, I don't want to see us abandon copyleft either.
> >
> > Of course everyone has their own preferred license, so I'm sure
> > people who write apps with MIT, will think we should use MIT
> > too. Ultimately though, if we choose LGPL, they can still use
> > our module from an MIT licensed app, or any other licensed app
> > for that matter.
> >
> 
> OK, thanks for your input here. My plan right now, then, is:
> 
> (1) Relicense aqmp as LGPLv2+
> (2) Fork into new repo as discussed previously on qemu-devel
> (3) Work on dropping legacy.py (GPLv2) in favor of sync.py (LGPLv2+)

That plan works for me.  I'm happy for any of my contributions to be
widened to LGPLv2+, but not with the thought of abandoning copyleft by
going all the way to MIT.

> 
> I plan to version the fledgling forked repo as 0.0.z until I drop
> legacy.py, and then I'll version as 0.y.z for "a while", (A release or
> two for QEMU?), and then tag v1.0.0.
> (As we discussed earlier, with a non-finalized API, I'll be pinning
> QEMU to use specific versions until it stabilizes.)
> 
> I think you're right that we probably could relicense legacy.py
> without too much fuss, I think the most significant contributions that
> didn't come from Luiz or myself were made to docstrings, and only
> extremely few contributions came from non-RH addresses. Still, I plan
> to drop the whole file anyway, so I figured I'd side-step the
> relicensing justification there, even if it's doable.

I'm happy to relicense any of my contributions as needed (did I
actually write any, or just provide reviews?), but as you say,
sidestepping the process may get to the same end goal even faster.

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org



^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 01/10] python/aqmp: add explicit GPLv2 license to legacy.py
  2022-03-25 14:55               ` Eric Blake
@ 2022-03-25 17:32                 ` John Snow
  0 siblings, 0 replies; 25+ messages in thread
From: John Snow @ 2022-03-25 17:32 UTC (permalink / raw)
  To: Eric Blake
  Cc: Kevin Wolf, Vladimir Sementsov-Ogievskiy, Daniel P. Berrangé,
	Beraldo Leal, Qemu-block, qemu-devel, Markus Armbruster,
	Hanna Reitz, Andrea Bolognani, Cleber Rosa, Luiz Capitulino

[-- Attachment #1: Type: text/plain, Size: 4894 bytes --]

On Fri, Mar 25, 2022, 10:55 AM Eric Blake <eblake@redhat.com> wrote:

> On Thu, Mar 24, 2022 at 12:07:24PM -0400, John Snow wrote:
> ...
> > > Yep, as I mentioned, I don't want to see us abandon copyleft either.
> > >
> > > Of course everyone has their own preferred license, so I'm sure
> > > people who write apps with MIT, will think we should use MIT
> > > too. Ultimately though, if we choose LGPL, they can still use
> > > our module from an MIT licensed app, or any other licensed app
> > > for that matter.
> > >
> >
> > OK, thanks for your input here. My plan right now, then, is:
> >
> > (1) Relicense aqmp as LGPLv2+
> > (2) Fork into new repo as discussed previously on qemu-devel
> > (3) Work on dropping legacy.py (GPLv2) in favor of sync.py (LGPLv2+)
>
> That plan works for me.  I'm happy for any of my contributions to be
> widened to LGPLv2+, but not with the thought of abandoning copyleft by
> going all the way to MIT.
>

Thanks, it's helpful to know where people sit on this; it makes me feel
more comfortable with the choice.

In the future, we're probably going to work on Apache/MIT licensed QMP
libraries for other languages, but for a lib that is used in and grew out
of the QEMU tree itself, it didn't feel right to abandon copyleft, even for
a library.


> >
> > I plan to version the fledgling forked repo as 0.0.z until I drop
> > legacy.py, and then I'll version as 0.y.z for "a while", (A release or
> > two for QEMU?), and then tag v1.0.0.
> > (As we discussed earlier, with a non-finalized API, I'll be pinning
> > QEMU to use specific versions until it stabilizes.)
> >
> > I think you're right that we probably could relicense legacy.py
> > without too much fuss, I think the most significant contributions that
> > didn't come from Luiz or myself were made to docstrings, and only
> > extremely few contributions came from non-RH addresses. Still, I plan
> > to drop the whole file anyway, so I figured I'd side-step the
> > relicensing justification there, even if it's doable.
>
> I'm happy to relicense any of my contributions as needed (did I
> actually write any, or just provide reviews?), but as you say,
> sidestepping the process may get to the same end goal even faster.
>

Yeah. Part of it is that I intend to drop legacy.py *anyway*, as I had
always intended not to support this exact API - I have always considered it
compat glue for iotests.

(Increasingly off-topic below this point,)

The reason I haven't done this *yet* is because:

(1) I wanted to avoid even more churn in iotests, and I only recently got
aqmp fully stable as a replacement. I didn't want to move too much around
all at once.

(2) I am still waffling a little bit on the design of the sync interface. I
am planning to base my initial design of it based on "what comes up" as I
now wean machine.py off of legacy.py. I expect there will be cases where
some things that are very easy in asyncio will be cumbersome in the sync
interface, and I'll learn a lot just by *doing the replacement*.

Easier to make changes now than later, so ... even if I don't upstream the
switchover right away, the exercise will be informative.

(The goal is actually similar to the qemu_img and qemu_io changes: make qmp
stuff error by default, but add nice facilities for declaring anticipated
errors. This delves into json structure matching, event handling/waiting,
etc. I wanna make it *really* painless to write very thorough and rigorous
tests that give very good feedback on failure.)

(3) There are still a few design bugs in aqmp itself; we just avoid them.
There's a few loose ends and rough edges here and there. I'm not sure what
will happen to the overall design as I embark on fixing them. Maybe
nothing, maybe significant changes; It's too early for me to tell. I just
know where there's some ugly spots that I want to take a serious crack at
fixing before v1.0.

[If anyone is wondering what the flaws are, they're in my qemu fork issues
tracker. They'll be moved when I fork qemu.qmp out of qemu.git. I track
both ideas and actual bugs here.
https://gitlab.com/jsnow/qemu/-/issues?sort=created_date&state=opened ]

That said, I do have a prototype; I add a sync.py and then rebase legacy.py
on top of sync.py. It seems to work fine, but for due diligence I want to
try the exercise of doing a full native replacement without any compat
shims to see what I can learn about what patterns will be helpful and where
the ugly spots are.

(Maybe I should give a micro-talk and walk people through how to write
async native tests and really try to encourage participation there. This
obviously has uses outside of just "io"tests.

Do you think this is useful outside of / ahead of KVM Forum? I want to get
people writing lots and lots of tests.)


> --
> Eric Blake, Principal Software Engineer
> Red Hat, Inc.           +1-919-301-3266
> Virtualization:  qemu.org | libvirt.org
>
>

[-- Attachment #2: Type: text/html, Size: 6815 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2022-03-25 17:34 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-21 21:08 [PATCH 00/10] Python: Remove synchronous QMP library John Snow
2022-03-21 21:08 ` [PATCH 01/10] python/aqmp: add explicit GPLv2 license to legacy.py John Snow
2022-03-23 21:47   ` John Snow
2022-03-24  8:59     ` Daniel P. Berrangé
2022-03-24  9:03       ` Daniel P. Berrangé
2022-03-24 14:29         ` Andrea Bolognani
2022-03-24 14:47           ` Daniel P. Berrangé
2022-03-24 15:03         ` John Snow
2022-03-24 15:25           ` Daniel P. Berrangé
2022-03-24 16:07             ` John Snow
2022-03-25 14:55               ` Eric Blake
2022-03-25 17:32                 ` John Snow
2022-03-21 21:08 ` [PATCH 02/10] python/aqmp: relicense as GPLv2+ John Snow
2022-03-21 21:08 ` [PATCH 03/10] python: temporarily silence pylint duplicate-code warnings John Snow
2022-03-21 21:08 ` [PATCH 04/10] python/aqmp: take QMPBadPortError and parse_address from qemu.qmp John Snow
2022-03-21 21:08 ` [PATCH 05/10] python/aqmp: fully separate from qmp.QEMUMonitorProtocol John Snow
2022-03-21 21:08 ` [PATCH 06/10] python/aqmp: copy qmp docstrings to qemu.aqmp.legacy John Snow
2022-03-23 18:24   ` Hanna Reitz
2022-03-23 19:36     ` John Snow
2022-03-21 21:08 ` [PATCH 07/10] python: remove the old QMP package John Snow
2022-03-21 21:08 ` [PATCH 08/10] python: re-enable pylint duplicate-code warnings John Snow
2022-03-21 21:08 ` [PATCH 09/10] python: rename qemu.aqmp to qemu.qmp John Snow
2022-03-23 18:19   ` Hanna Reitz
2022-03-23 21:25     ` John Snow
2022-03-21 21:08 ` [PATCH 10/10] python: rename 'aqmp-tui' to 'qmp-tui' John Snow

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.