Skip to content

KeyboardInterrupt during async generator fixture setup results in RuntimeError #219

Closed
@kriek

Description

@kriek

Hello there,

I'm using asyncio-0.15.1 and it seems there is a bug when pytest is interrupted during the setup code of an async generator fixture.

Minimal reproduction test module:

import pytest
import asyncio

@pytest.fixture
async def fixture():
	await asyncio.sleep(5)
	yield
	await asyncio.sleep(1)

@pytest.mark.asyncio
async def test_keyboard_interrupt(fixture):
	pass

If I hit Ctrl-C during fixture setup, it results in:

D:\python>pytest test_keyboard_interrupt.py
============================================================================================ test session starts ============================================================================================
platform win32 -- Python 3.8.5, pytest-6.1.2, py-1.9.0, pluggy-0.13.1
rootdir: D:\python
plugins: asyncio-0.15.1
collected 1 item

test_keyboard_interrupt.py
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! KeyboardInterrupt !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
c:\users\kasyc\appdata\local\programs\python\python38\lib\asyncio\windows_events.py:779: KeyboardInterrupt
(to show a full traceback on KeyboardInterrupt use --full-trace)
Traceback (most recent call last):
  File "c:\users\kasyc\appdata\local\programs\python\python38\lib\runpy.py", line 194, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "c:\users\kasyc\appdata\local\programs\python\python38\lib\runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "C:\Users\kasyc\AppData\Local\Programs\Python\Python38\Scripts\pytest.exe\__main__.py", line 7, in <module>
  File "c:\users\kasyc\appdata\local\programs\python\python38\lib\site-packages\_pytest\config\__init__.py", line 187, in console_main
    code = main()
  File "c:\users\kasyc\appdata\local\programs\python\python38\lib\site-packages\_pytest\config\__init__.py", line 164, in main
    ret = config.hook.pytest_cmdline_main(
  File "c:\users\kasyc\appdata\local\programs\python\python38\lib\site-packages\pluggy\hooks.py", line 286, in __call__
    return self._hookexec(self, self.get_hookimpls(), kwargs)
  File "c:\users\kasyc\appdata\local\programs\python\python38\lib\site-packages\pluggy\manager.py", line 93, in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
  File "c:\users\kasyc\appdata\local\programs\python\python38\lib\site-packages\pluggy\manager.py", line 84, in <lambda>
    self._inner_hookexec = lambda hook, methods, kwargs: hook.multicall(
  File "c:\users\kasyc\appdata\local\programs\python\python38\lib\site-packages\pluggy\callers.py", line 208, in _multicall
    return outcome.get_result()
  File "c:\users\kasyc\appdata\local\programs\python\python38\lib\site-packages\pluggy\callers.py", line 80, in get_result
    raise ex[1].with_traceback(ex[2])
  File "c:\users\kasyc\appdata\local\programs\python\python38\lib\site-packages\pluggy\callers.py", line 187, in _multicall
    res = hook_impl.function(*args)
  File "c:\users\kasyc\appdata\local\programs\python\python38\lib\site-packages\_pytest\main.py", line 306, in pytest_cmdline_main
    return wrap_session(config, _main)
  File "c:\users\kasyc\appdata\local\programs\python\python38\lib\site-packages\_pytest\main.py", line 294, in wrap_session
    config.hook.pytest_sessionfinish(
  File "c:\users\kasyc\appdata\local\programs\python\python38\lib\site-packages\pluggy\hooks.py", line 286, in __call__
    return self._hookexec(self, self.get_hookimpls(), kwargs)
  File "c:\users\kasyc\appdata\local\programs\python\python38\lib\site-packages\pluggy\manager.py", line 93, in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
  File "c:\users\kasyc\appdata\local\programs\python\python38\lib\site-packages\pluggy\manager.py", line 84, in <lambda>
    self._inner_hookexec = lambda hook, methods, kwargs: hook.multicall(
  File "c:\users\kasyc\appdata\local\programs\python\python38\lib\site-packages\pluggy\callers.py", line 203, in _multicall
    gen.send(outcome)
  File "c:\users\kasyc\appdata\local\programs\python\python38\lib\site-packages\_pytest\terminal.py", line 794, in pytest_sessionfinish
    outcome.get_result()
  File "c:\users\kasyc\appdata\local\programs\python\python38\lib\site-packages\pluggy\callers.py", line 80, in get_result
    raise ex[1].with_traceback(ex[2])
  File "c:\users\kasyc\appdata\local\programs\python\python38\lib\site-packages\pluggy\callers.py", line 187, in _multicall
    res = hook_impl.function(*args)
  File "c:\users\kasyc\appdata\local\programs\python\python38\lib\site-packages\_pytest\runner.py", line 104, in pytest_sessionfinish
    session._setupstate.teardown_all()
  File "c:\users\kasyc\appdata\local\programs\python\python38\lib\site-packages\_pytest\runner.py", line 411, in teardown_all
    self._pop_and_teardown()
  File "c:\users\kasyc\appdata\local\programs\python\python38\lib\site-packages\_pytest\runner.py", line 386, in _pop_and_teardown
    self._teardown_with_finalization(colitem)
  File "c:\users\kasyc\appdata\local\programs\python\python38\lib\site-packages\_pytest\runner.py", line 404, in _teardown_with_finalization
    self._callfinalizers(colitem)
  File "c:\users\kasyc\appdata\local\programs\python\python38\lib\site-packages\_pytest\runner.py", line 401, in _callfinalizers
    raise exc
  File "c:\users\kasyc\appdata\local\programs\python\python38\lib\site-packages\_pytest\runner.py", line 394, in _callfinalizers
    fin()
  File "c:\users\kasyc\appdata\local\programs\python\python38\lib\site-packages\_pytest\fixtures.py", line 1032, in finish
    raise exc
  File "c:\users\kasyc\appdata\local\programs\python\python38\lib\site-packages\_pytest\fixtures.py", line 1025, in finish
    func()
  File "c:\users\kasyc\appdata\local\programs\python\python38\lib\site-packages\pytest_asyncio\plugin.py", line 139, in finalizer
    loop.run_until_complete(async_finalizer())
  File "c:\users\kasyc\appdata\local\programs\python\python38\lib\asyncio\base_events.py", line 616, in run_until_complete
    return future.result()
  File "c:\users\kasyc\appdata\local\programs\python\python38\lib\site-packages\pytest_asyncio\plugin.py", line 131, in async_finalizer
    await gen_obj.__anext__()
RuntimeError: anext(): asynchronous generator is already running

It seems we would need to transform:

            request.addfinalizer(finalizer)
            return loop.run_until_complete(setup())

into:

            result = loop.run_until_complete(setup())
            request.addfinalizer(finalizer)
            return result

so that the cleanup code will only be executed if the setup code is finished.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions