All of lore.kernel.org
 help / color / mirror / Atom feed
From: John Snow <jsnow@redhat.com>
To: qemu-devel@nongnu.org
Cc: "Kevin Wolf" <kwolf@redhat.com>,
	"Michael Roth" <michael.roth@amd.com>,
	"John Snow" <jsnow@redhat.com>, "Hanna Reitz" <hreitz@redhat.com>,
	"Peter Maydell" <peter.maydell@linaro.org>,
	"Cleber Rosa" <crosa@redhat.com>,
	qemu-block@nongnu.org, "Markus Armbruster" <armbru@redhat.com>,
	"Daniel P. Berrangé" <berrange@redhat.com>
Subject: [PULL 06/19] python: backport 'Use @asynciocontextmanager'
Date: Tue, 16 Sep 2025 12:23:51 -0400	[thread overview]
Message-ID: <20250916162404.9195-7-jsnow@redhat.com> (raw)
In-Reply-To: <20250916162404.9195-1-jsnow@redhat.com>

This removes a non-idiomatic use of a "coroutine callback" in favor of
something a bit more standardized.

Signed-off-by: John Snow <jsnow@redhat.com>
cherry picked from commit python-qemu-qmp@commit 97f7ffa3be17a50544b52767d14b6fd478c07b9e
Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
---
 python/qemu/qmp/protocol.py | 35 ++++++++++++++++-------------------
 1 file changed, 16 insertions(+), 19 deletions(-)

diff --git a/python/qemu/qmp/protocol.py b/python/qemu/qmp/protocol.py
index 208bdec5c89..958aeca08ac 100644
--- a/python/qemu/qmp/protocol.py
+++ b/python/qemu/qmp/protocol.py
@@ -15,6 +15,7 @@
 
 import asyncio
 from asyncio import StreamReader, StreamWriter
+from contextlib import asynccontextmanager
 from enum import Enum
 from functools import wraps
 import logging
@@ -22,6 +23,7 @@
 from ssl import SSLContext
 from typing import (
     Any,
+    AsyncGenerator,
     Awaitable,
     Callable,
     Generic,
@@ -337,9 +339,8 @@ async def start_server(self, address: SocketAddrT,
             This exception will wrap a more concrete one. In most cases,
             the wrapped exception will be `OSError`.
         """
-        await self._session_guard(
-            self._do_start_server(address, ssl),
-            'Failed to establish connection')
+        async with self._session_guard('Failed to establish connection'):
+            await self._do_start_server(address, ssl)
         assert self.runstate == Runstate.CONNECTING
 
     @upper_half
@@ -362,12 +363,10 @@ async def accept(self) -> None:
         """
         if self._accepted is None:
             raise QMPError("Cannot call accept() before start_server().")
-        await self._session_guard(
-            self._do_accept(),
-            'Failed to establish connection')
-        await self._session_guard(
-            self._establish_session(),
-            'Failed to establish session')
+        async with self._session_guard('Failed to establish connection'):
+            await self._do_accept()
+        async with self._session_guard('Failed to establish session'):
+            await self._establish_session()
         assert self.runstate == Runstate.RUNNING
 
     @upper_half
@@ -392,12 +391,10 @@ async def connect(self, address: Union[SocketAddrT, socket.socket],
             protocol-level failure occurs while establishing a new
             session, the wrapped error may also be an `QMPError`.
         """
-        await self._session_guard(
-            self._do_connect(address, ssl),
-            'Failed to establish connection')
-        await self._session_guard(
-            self._establish_session(),
-            'Failed to establish session')
+        async with self._session_guard('Failed to establish connection'):
+            await self._do_connect(address, ssl)
+        async with self._session_guard('Failed to establish session'):
+            await self._establish_session()
         assert self.runstate == Runstate.RUNNING
 
     @upper_half
@@ -418,7 +415,8 @@ async def disconnect(self) -> None:
     # Section: Session machinery
     # --------------------------
 
-    async def _session_guard(self, coro: Awaitable[None], emsg: str) -> None:
+    @asynccontextmanager
+    async def _session_guard(self, emsg: str) -> AsyncGenerator[None, None]:
         """
         Async guard function used to roll back to `IDLE` on any error.
 
@@ -435,10 +433,9 @@ async def _session_guard(self, coro: Awaitable[None], emsg: str) -> None:
         :raise ConnectError:
             When any other error is encountered in the guarded block.
         """
-        # Note: After Python 3.6 support is removed, this should be an
-        # @asynccontextmanager instead of accepting a callback.
         try:
-            await coro
+            # Caller's code runs here.
+            yield
         except BaseException as err:
             self.logger.error("%s: %s", emsg, exception_summary(err))
             self.logger.debug("%s:\n%s\n", emsg, pretty_traceback())
-- 
2.51.0



  parent reply	other threads:[~2025-09-16 16:28 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-09-16 16:23 [PULL 00/19] Python patches John Snow
2025-09-16 16:23 ` [PULL 01/19] python: backport 'Change error classes to have better repr methods' John Snow
2025-09-16 16:23 ` [PULL 02/19] python: backport 'EventListener: add __repr__ method' John Snow
2025-09-16 16:23 ` [PULL 03/19] python: backport 'kick event queue on legacy event_pull()' John Snow
2025-09-16 16:23 ` [PULL 04/19] python: backport 'protocol: adjust logging name when changing client name' John Snow
2025-10-15  7:11   ` Thomas Huth
2025-10-22  0:37     ` John Snow
2025-09-16 16:23 ` [PULL 05/19] python: backport 'drop Python3.6 workarounds' John Snow
2025-09-16 16:23 ` John Snow [this message]
2025-09-16 16:23 ` [PULL 07/19] python: backport 'qmp-shell: add common_parser()' John Snow
2025-09-16 16:23 ` [PULL 08/19] python: backport 'feat: allow setting read buffer limit' John Snow
2025-09-16 16:23 ` [PULL 09/19] python: backport 'make require() preserve async-ness' John Snow
2025-09-16 16:23 ` [PULL 10/19] python: backport 'qmp-shell-wrap: handle missing binary gracefully' John Snow
2025-09-16 16:23 ` [PULL 11/19] python: backport 'qmp-tui: Do not crash if optional dependencies are not met' John Snow
2025-09-16 16:23 ` [PULL 12/19] python: backport 'Remove deprecated get_event_loop calls' John Snow
2025-09-16 16:23 ` [PULL 13/19] python: backport 'avoid creating additional event loops per thread' John Snow
2025-09-16 16:23 ` [PULL 14/19] python: synchronize qemu.qmp documentation John Snow
2025-09-16 16:24 ` [PULL 15/19] iotests: drop compat for old version context manager John Snow
2025-09-16 16:24 ` [PULL 16/19] python: ensure QEMUQtestProtocol closes its socket John Snow
2025-09-16 16:24 ` [PULL 17/19] iotests/147: ensure temporary sockets are closed before exiting John Snow
2025-09-16 16:24 ` [PULL 18/19] iotests/151: ensure subprocesses are cleaned up John Snow
2025-09-16 16:24 ` [PULL 19/19] iotests/check: always enable all python warnings John Snow
2025-09-16 18:20 ` [PULL 00/19] Python patches John Snow
2025-09-16 19:22 ` Richard Henderson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250916162404.9195-7-jsnow@redhat.com \
    --to=jsnow@redhat.com \
    --cc=armbru@redhat.com \
    --cc=berrange@redhat.com \
    --cc=crosa@redhat.com \
    --cc=hreitz@redhat.com \
    --cc=kwolf@redhat.com \
    --cc=michael.roth@amd.com \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-block@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is 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.