From 2adff239023846f2600d5f7da956d8951a9cc062 Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Sat, 3 Jul 2021 23:51:16 +0100 Subject: [PATCH 1/4] make BlockingPortal.stop sync --- src/anyio/from_thread.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/anyio/from_thread.py b/src/anyio/from_thread.py index 26d4a262..0941d2a1 100644 --- a/src/anyio/from_thread.py +++ b/src/anyio/from_thread.py @@ -9,6 +9,7 @@ from warnings import warn from ._core import _eventloop +from ._core._compat import DeprecatedAwaitable from ._core._eventloop import get_asynclib, get_cancelled_exc_class, threadlocals from ._core._synchronization import Event from ._core._tasks import CancelScope, create_task_group @@ -130,7 +131,7 @@ async def __aenter__(self) -> 'BlockingPortal': async def __aexit__(self, exc_type: Optional[Type[BaseException]], exc_val: Optional[BaseException], exc_tb: Optional[TracebackType]) -> Optional[bool]: - await self.stop() + self.stop() return await self._task_group.__aexit__(exc_type, exc_val, exc_tb) def _check_running(self) -> None: @@ -143,7 +144,7 @@ async def sleep_until_stopped(self) -> None: """Sleep until :meth:`stop` is called.""" await self._stop_event.wait() - async def stop(self, cancel_remaining: bool = False) -> None: + def stop(self, cancel_remaining: bool = False) -> DeprecatedAwaitable: """ Signal the portal to shut down. @@ -159,6 +160,8 @@ async def stop(self, cancel_remaining: bool = False) -> None: if cancel_remaining: self._task_group.cancel_scope.cancel() + return DeprecatedAwaitable(self.stop) + async def _call_func(self, func: Callable, args: tuple, kwargs: Dict[str, Any], future: Future) -> None: def callback(f: Future) -> None: From 00447f7af62ee1cef17b70a8002d5df02fd3e760 Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Sun, 4 Jul 2021 00:15:42 +0100 Subject: [PATCH 2/4] update news --- docs/versionhistory.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/versionhistory.rst b/docs/versionhistory.rst index d4bec99d..ccaffa31 100644 --- a/docs/versionhistory.rst +++ b/docs/versionhistory.rst @@ -10,6 +10,11 @@ This library adheres to `Semantic Versioning 2.0 `_. ``FileWriteStream``so they accept any path-like object (including the new asynchronous ``Path`` class) - Dropped unnecessary dependency on the ``async_generator`` library +- API changes: + * The following functions and methods are no longer asynchronous but can still be awaited on + (doing so will emit a deprecation warning): + + * ``abc.BlockingPortal.stop`` **3.2.1** From 26bca9bd542e23bd6c29330b5ea1333037faa14c Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Sun, 4 Jul 2021 11:35:56 +0100 Subject: [PATCH 3/4] swap task set and self._event_loop_thread_id assignment --- src/anyio/from_thread.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/anyio/from_thread.py b/src/anyio/from_thread.py index 0941d2a1..8b83935e 100644 --- a/src/anyio/from_thread.py +++ b/src/anyio/from_thread.py @@ -155,8 +155,8 @@ def stop(self, cancel_remaining: bool = False) -> DeprecatedAwaitable: finish before returning """ - self._event_loop_thread_id = None self._stop_event.set() + self._event_loop_thread_id = None if cancel_remaining: self._task_group.cancel_scope.cancel() From 6ed4b6696b5aa2910ec5c7e869b619effec045cf Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Mon, 5 Jul 2021 11:12:46 +0100 Subject: [PATCH 4/4] Update src/anyio/from_thread.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Alex Grönholm --- src/anyio/from_thread.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/anyio/from_thread.py b/src/anyio/from_thread.py index 8b83935e..a1cb0e95 100644 --- a/src/anyio/from_thread.py +++ b/src/anyio/from_thread.py @@ -155,8 +155,13 @@ def stop(self, cancel_remaining: bool = False) -> DeprecatedAwaitable: finish before returning """ - self._stop_event.set() + if self._event_loop_thread_id is None: + return + if threading.get_ident() != self._event_loop_thread_id: + raise RuntimeError('This method must be called from the event loop thread') + self._event_loop_thread_id = None + self._stop_event.set() if cancel_remaining: self._task_group.cancel_scope.cancel()