Our minimum python is now 3.9, so back compat with python
3.6 is no longer required.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
python/qemu/qmp/protocol.py | 7 +++----
python/qemu/qmp/qmp_tui.py | 8 ++++----
python/qemu/qmp/util.py | 33 +--------------------------------
python/tests/protocol.py | 7 +++----
4 files changed, 11 insertions(+), 44 deletions(-)
diff --git a/python/qemu/qmp/protocol.py b/python/qemu/qmp/protocol.py
index deb6b20d29..4aff0ea423 100644
--- a/python/qemu/qmp/protocol.py
+++ b/python/qemu/qmp/protocol.py
@@ -36,7 +36,6 @@
from .error import QMPError
from .util import (
bottom_half,
- create_task,
exception_summary,
flush,
pretty_traceback,
@@ -661,8 +660,8 @@ async def _establish_session(self) -> None:
reader_coro = self._bh_loop_forever(self._bh_recv_message, 'Reader')
writer_coro = self._bh_loop_forever(self._bh_send_message, 'Writer')
- self._reader_task = create_task(reader_coro)
- self._writer_task = create_task(writer_coro)
+ self._reader_task = asyncio.create_task(reader_coro)
+ self._writer_task = asyncio.create_task(writer_coro)
self._bh_tasks = asyncio.gather(
self._reader_task,
@@ -687,7 +686,7 @@ def _schedule_disconnect(self) -> None:
if not self._dc_task:
self._set_state(Runstate.DISCONNECTING)
self.logger.debug("Scheduling disconnect.")
- self._dc_task = create_task(self._bh_disconnect())
+ self._dc_task = asyncio.create_task(self._bh_disconnect())
@upper_half
async def _wait_disconnect(self) -> None:
diff --git a/python/qemu/qmp/qmp_tui.py b/python/qemu/qmp/qmp_tui.py
index 7dfb03c9ad..61e8b3773c 100644
--- a/python/qemu/qmp/qmp_tui.py
+++ b/python/qemu/qmp/qmp_tui.py
@@ -40,7 +40,7 @@
from .message import DeserializationError, Message, UnexpectedTypeError
from .protocol import ConnectError, Runstate
from .qmp_client import ExecInterruptedError, QMPClient
-from .util import create_task, pretty_traceback
+from .util import pretty_traceback
# The name of the signal that is used to update the history list
@@ -225,7 +225,7 @@ def cb_send_to_server(self, raw_msg: str) -> None:
"""
try:
msg = Message(bytes(raw_msg, encoding='utf-8'))
- create_task(self._send_to_server(msg))
+ asyncio.create_task(self._send_to_server(msg))
except (DeserializationError, UnexpectedTypeError) as err:
raw_msg = format_json(raw_msg)
logging.info('Invalid message: %s', err.error_message)
@@ -246,7 +246,7 @@ def kill_app(self) -> None:
Initiates killing of app. A bridge between asynchronous and synchronous
code.
"""
- create_task(self._kill_app())
+ asyncio.create_task(self._kill_app())
async def _kill_app(self) -> None:
"""
@@ -393,7 +393,7 @@ def run(self, debug: bool = False) -> None:
handle_mouse=True,
event_loop=event_loop)
- create_task(self.manage_connection(), self.aloop)
+ self.aloop.create_task(self.manage_connection())
try:
main_loop.run()
except Exception as err:
diff --git a/python/qemu/qmp/util.py b/python/qemu/qmp/util.py
index 7f9e718154..c44a5aacbc 100644
--- a/python/qemu/qmp/util.py
+++ b/python/qemu/qmp/util.py
@@ -13,13 +13,7 @@
import asyncio
import sys
import traceback
-from typing import (
- Any,
- Coroutine,
- Optional,
- TypeVar,
- cast,
-)
+from typing import TypeVar, cast
T = TypeVar('T')
@@ -79,31 +73,6 @@ def bottom_half(func: T) -> T:
return func
-# -------------------------------
-# Section: Compatibility Wrappers
-# -------------------------------
-
-
-def create_task(coro: Coroutine[Any, Any, T],
- loop: Optional[asyncio.AbstractEventLoop] = None
- ) -> 'asyncio.Future[T]':
- """
- Python 3.6-compatible `asyncio.create_task` wrapper.
-
- :param coro: The coroutine to execute in a task.
- :param loop: Optionally, the loop to create the task in.
-
- :return: An `asyncio.Future` object.
- """
- if sys.version_info >= (3, 7):
- if loop is not None:
- return loop.create_task(coro)
- return asyncio.create_task(coro) # pylint: disable=no-member
-
- # Python 3.6:
- return asyncio.ensure_future(coro, loop=loop)
-
-
# ----------------------------
# Section: Logging & Debugging
# ----------------------------
diff --git a/python/tests/protocol.py b/python/tests/protocol.py
index 4a0ee94727..9bb23b6a7b 100644
--- a/python/tests/protocol.py
+++ b/python/tests/protocol.py
@@ -8,7 +8,6 @@
from qemu.qmp import ConnectError, Runstate
from qemu.qmp.protocol import AsyncProtocol, StateError
-from qemu.qmp.util import create_task
class NullProtocol(AsyncProtocol[None]):
@@ -124,7 +123,7 @@ async def _runner():
if allow_cancellation:
return
raise
- return create_task(_runner())
+ return asyncio.create_task(_runner())
@contextmanager
@@ -271,7 +270,7 @@ async def _watcher():
msg=f"Expected state '{state.name}'",
)
- self.runstate_watcher = create_task(_watcher())
+ self.runstate_watcher = asyncio.create_task(_watcher())
# Kick the loop and force the task to block on the event.
await asyncio.sleep(0)
@@ -589,7 +588,7 @@ async def _asyncTearDown(self):
async def testSmoke(self):
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))
+ server_task = asyncio.create_task(self.server.start_server_and_accept(sock))
# give the server a chance to start listening [...]
await asyncio.sleep(0)
--
2.49.0
On Tue, Jul 15, 2025 at 10:31 AM Daniel P. Berrangé <berrange@redhat.com> wrote:
>
> Our minimum python is now 3.9, so back compat with python
> 3.6 is no longer required.
>
> Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: John Snow <jsnow@redhat.com>
> ---
> python/qemu/qmp/protocol.py | 7 +++----
> python/qemu/qmp/qmp_tui.py | 8 ++++----
> python/qemu/qmp/util.py | 33 +--------------------------------
> python/tests/protocol.py | 7 +++----
> 4 files changed, 11 insertions(+), 44 deletions(-)
>
> diff --git a/python/qemu/qmp/protocol.py b/python/qemu/qmp/protocol.py
> index deb6b20d29..4aff0ea423 100644
> --- a/python/qemu/qmp/protocol.py
> +++ b/python/qemu/qmp/protocol.py
> @@ -36,7 +36,6 @@
> from .error import QMPError
> from .util import (
> bottom_half,
> - create_task,
> exception_summary,
> flush,
> pretty_traceback,
> @@ -661,8 +660,8 @@ async def _establish_session(self) -> None:
> reader_coro = self._bh_loop_forever(self._bh_recv_message, 'Reader')
> writer_coro = self._bh_loop_forever(self._bh_send_message, 'Writer')
>
> - self._reader_task = create_task(reader_coro)
> - self._writer_task = create_task(writer_coro)
> + self._reader_task = asyncio.create_task(reader_coro)
> + self._writer_task = asyncio.create_task(writer_coro)
>
> self._bh_tasks = asyncio.gather(
> self._reader_task,
> @@ -687,7 +686,7 @@ def _schedule_disconnect(self) -> None:
> if not self._dc_task:
> self._set_state(Runstate.DISCONNECTING)
> self.logger.debug("Scheduling disconnect.")
> - self._dc_task = create_task(self._bh_disconnect())
> + self._dc_task = asyncio.create_task(self._bh_disconnect())
>
> @upper_half
> async def _wait_disconnect(self) -> None:
> diff --git a/python/qemu/qmp/qmp_tui.py b/python/qemu/qmp/qmp_tui.py
> index 7dfb03c9ad..61e8b3773c 100644
> --- a/python/qemu/qmp/qmp_tui.py
> +++ b/python/qemu/qmp/qmp_tui.py
> @@ -40,7 +40,7 @@
> from .message import DeserializationError, Message, UnexpectedTypeError
> from .protocol import ConnectError, Runstate
> from .qmp_client import ExecInterruptedError, QMPClient
> -from .util import create_task, pretty_traceback
> +from .util import pretty_traceback
>
>
> # The name of the signal that is used to update the history list
> @@ -225,7 +225,7 @@ def cb_send_to_server(self, raw_msg: str) -> None:
> """
> try:
> msg = Message(bytes(raw_msg, encoding='utf-8'))
> - create_task(self._send_to_server(msg))
> + asyncio.create_task(self._send_to_server(msg))
> except (DeserializationError, UnexpectedTypeError) as err:
> raw_msg = format_json(raw_msg)
> logging.info('Invalid message: %s', err.error_message)
> @@ -246,7 +246,7 @@ def kill_app(self) -> None:
> Initiates killing of app. A bridge between asynchronous and synchronous
> code.
> """
> - create_task(self._kill_app())
> + asyncio.create_task(self._kill_app())
>
> async def _kill_app(self) -> None:
> """
> @@ -393,7 +393,7 @@ def run(self, debug: bool = False) -> None:
> handle_mouse=True,
> event_loop=event_loop)
>
> - create_task(self.manage_connection(), self.aloop)
> + self.aloop.create_task(self.manage_connection())
> try:
> main_loop.run()
> except Exception as err:
> diff --git a/python/qemu/qmp/util.py b/python/qemu/qmp/util.py
> index 7f9e718154..c44a5aacbc 100644
> --- a/python/qemu/qmp/util.py
> +++ b/python/qemu/qmp/util.py
> @@ -13,13 +13,7 @@
> import asyncio
> import sys
> import traceback
> -from typing import (
> - Any,
> - Coroutine,
> - Optional,
> - TypeVar,
> - cast,
> -)
> +from typing import TypeVar, cast
>
>
> T = TypeVar('T')
> @@ -79,31 +73,6 @@ def bottom_half(func: T) -> T:
> return func
>
>
> -# -------------------------------
> -# Section: Compatibility Wrappers
> -# -------------------------------
> -
> -
> -def create_task(coro: Coroutine[Any, Any, T],
> - loop: Optional[asyncio.AbstractEventLoop] = None
> - ) -> 'asyncio.Future[T]':
> - """
> - Python 3.6-compatible `asyncio.create_task` wrapper.
> -
> - :param coro: The coroutine to execute in a task.
> - :param loop: Optionally, the loop to create the task in.
> -
> - :return: An `asyncio.Future` object.
> - """
> - if sys.version_info >= (3, 7):
> - if loop is not None:
> - return loop.create_task(coro)
> - return asyncio.create_task(coro) # pylint: disable=no-member
> -
> - # Python 3.6:
> - return asyncio.ensure_future(coro, loop=loop)
> -
> -
> # ----------------------------
> # Section: Logging & Debugging
> # ----------------------------
> diff --git a/python/tests/protocol.py b/python/tests/protocol.py
> index 4a0ee94727..9bb23b6a7b 100644
> --- a/python/tests/protocol.py
> +++ b/python/tests/protocol.py
> @@ -8,7 +8,6 @@
>
> from qemu.qmp import ConnectError, Runstate
> from qemu.qmp.protocol import AsyncProtocol, StateError
> -from qemu.qmp.util import create_task
>
>
> class NullProtocol(AsyncProtocol[None]):
> @@ -124,7 +123,7 @@ async def _runner():
> if allow_cancellation:
> return
> raise
> - return create_task(_runner())
> + return asyncio.create_task(_runner())
>
>
> @contextmanager
> @@ -271,7 +270,7 @@ async def _watcher():
> msg=f"Expected state '{state.name}'",
> )
>
> - self.runstate_watcher = create_task(_watcher())
> + self.runstate_watcher = asyncio.create_task(_watcher())
> # Kick the loop and force the task to block on the event.
> await asyncio.sleep(0)
>
> @@ -589,7 +588,7 @@ async def _asyncTearDown(self):
> async def testSmoke(self):
> 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))
> + server_task = asyncio.create_task(self.server.start_server_and_accept(sock))
>
> # give the server a chance to start listening [...]
> await asyncio.sleep(0)
> --
> 2.49.0
>
© 2016 - 2025 Red Hat, Inc.