Skip to content

Commit

Permalink
Catch RuntimeError in finalization of start_blocking_portal() (agronh…
Browse files Browse the repository at this point in the history
  • Loading branch information
agronholm committed Oct 18, 2022
1 parent bb3523a commit 446e246
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 3 deletions.
3 changes: 3 additions & 0 deletions docs/versionhistory.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ This library adheres to `Semantic Versioning 2.0 <http:https://semver.org/>`_.
``signal.Signals`` instances on the ``trio`` backend
- Fixed ``to_thread.run_sync()`` hanging on asyncio if the target callable raises
``StopIteration``
- Fixed ``start_blocking_portal()`` raising an unwarranted
``RuntimeError: This portal is not running`` if a task raises an exception that causes
the event loop to be closed

**3.6.1**

Expand Down
10 changes: 7 additions & 3 deletions src/anyio/from_thread.py
Original file line number Diff line number Diff line change
Expand Up @@ -406,12 +406,16 @@ async def run_portal() -> None:

if future.done():
portal = future.result()
cancel_remaining_tasks = False
try:
yield portal
except BaseException:
portal.call(portal.stop, True)
cancel_remaining_tasks = True
raise

portal.call(portal.stop, False)
finally:
try:
portal.call(portal.stop, cancel_remaining_tasks)
except RuntimeError:
pass

run_future.result()
21 changes: 21 additions & 0 deletions tests/test_from_thread.py
Original file line number Diff line number Diff line change
Expand Up @@ -503,3 +503,24 @@ async def in_loop() -> None:
await to_thread.run_sync(portal.start_task_soon, in_loop)

assert not caplog.text

def test_raise_baseexception_from_task(
self, anyio_backend_name: str, anyio_backend_options: dict[str, Any]
) -> None:
"""
Test that when a task raises a BaseException, it does not trigger additional
exceptions when trying to close the portal.
"""

async def raise_baseexception() -> None:
raise BaseException("fatal error")

with pytest.raises(BaseException, match="fatal error"):
with start_blocking_portal(
anyio_backend_name, anyio_backend_options
) as portal:
with pytest.raises(BaseException, match="fatal error") as exc:
portal.call(raise_baseexception)

assert exc.value.__context__ is None

0 comments on commit 446e246

Please sign in to comment.