diff --git a/docs/versionhistory.rst b/docs/versionhistory.rst index 2660524b..a571bfd1 100644 --- a/docs/versionhistory.rst +++ b/docs/versionhistory.rst @@ -3,6 +3,11 @@ Version history This library adheres to `Semantic Versioning 2.0 `_. +**UNRELEASED** + +- Fixed ``RuntimeError`` on asyncio when a ``CancelledError`` is raised from a task spawned through + a ``BlockingPortal`` (`#357 `_) + **3.3.0** - Added asynchronous ``Path`` class diff --git a/src/anyio/from_thread.py b/src/anyio/from_thread.py index 26d4a262..d845f993 100644 --- a/src/anyio/from_thread.py +++ b/src/anyio/from_thread.py @@ -162,7 +162,7 @@ async def stop(self, cancel_remaining: bool = False) -> None: async def _call_func(self, func: Callable, args: tuple, kwargs: Dict[str, Any], future: Future) -> None: def callback(f: Future) -> None: - if f.cancelled(): + if f.cancelled() and self._event_loop_thread_id not in (None, threading.get_ident()): self.call(scope.cancel) try: diff --git a/tests/test_from_thread.py b/tests/test_from_thread.py index 5339ea88..63fbc36c 100644 --- a/tests/test_from_thread.py +++ b/tests/test_from_thread.py @@ -376,3 +376,14 @@ def taskfunc(*, task_status: TaskStatus) -> None: future, start_value = portal.start_task( taskfunc, name='testname') # type: ignore[arg-type] assert start_value == 'testname' + + @pytest.mark.parametrize('anyio_backend', ['asyncio']) + async def test_asyncio_run_sync_called(self, caplog): + """Regression test for #357.""" + async def in_loop(): + raise CancelledError + + async with BlockingPortal() as portal: + await to_thread.run_sync(portal.start_task_soon, in_loop) + + assert not caplog.text