Skip to content

Commit

Permalink
Fixed KeyboardInterrupt hanging the asyncio test runner (#779)
Browse files Browse the repository at this point in the history
  • Loading branch information
agronholm authored Sep 11, 2024
1 parent c1aff53 commit d1aea98
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/versionhistory.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ This library adheres to `Semantic Versioning 2.0 <http://semver.org/>`_.
arrives in an exception group)
- Fixed support for Linux abstract namespaces in UNIX sockets that was broken in v4.2
(#781 <https://github.com/agronholm/anyio/issues/781>_; PR by @tapetersen)
- Fixed ``KeyboardInterrupt`` (ctrl+c) hanging the asyncio pytest runner

**4.4.0**

Expand Down
10 changes: 10 additions & 0 deletions src/anyio/_backends/_asyncio.py
Original file line number Diff line number Diff line change
Expand Up @@ -2082,13 +2082,23 @@ async def _run_tests_and_fixtures(
tuple[Awaitable[T_Retval], asyncio.Future[T_Retval]]
],
) -> None:
from _pytest.outcomes import OutcomeException

with receive_stream, self._send_stream:
async for coro, future in receive_stream:
try:
retval = await coro
except CancelledError as exc:
if not future.cancelled():
future.cancel(*exc.args)

raise
except BaseException as exc:
if not future.cancelled():
future.set_exception(exc)

if not isinstance(exc, (Exception, OutcomeException)):
raise
else:
if not future.cancelled():
future.set_result(retval)
Expand Down
27 changes: 27 additions & 0 deletions tests/test_pytest_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -441,3 +441,30 @@ async def test_debugger_exit():

result = testdir.runpytest(*pytest_args)
result.assert_outcomes()


@pytest.mark.parametrize("anyio_backend", get_all_backends(), indirect=True)
def test_keyboardinterrupt_during_test(
testdir: Pytester, anyio_backend_name: str
) -> None:
testdir.makepyfile(
f"""
import pytest
from anyio import create_task_group, sleep
@pytest.fixture
def anyio_backend():
return {anyio_backend_name!r}
async def send_keyboardinterrupt():
raise KeyboardInterrupt
@pytest.mark.anyio
async def test_anyio_mark_first():
async with create_task_group() as tg:
tg.start_soon(send_keyboardinterrupt)
await sleep(10)
"""
)

testdir.runpytest_subprocess(*pytest_args, timeout=3)

0 comments on commit d1aea98

Please sign in to comment.