Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Strange behaviour with asyncio.create_task and fixture scope #904

Closed
Hernell12 opened this issue Jul 31, 2024 · 5 comments
Closed

Strange behaviour with asyncio.create_task and fixture scope #904

Hernell12 opened this issue Jul 31, 2024 · 5 comments
Labels
needsinfo Requires additional information from the issue author

Comments

@Hernell12
Copy link

Hernell12 commented Jul 31, 2024

In the following script I create a asyncio task in a fixture which should read the contents of a given queue in the background the moment something gets put into the queue. When the @fixture(scope="function", autouse=True) all the values get read from the queue as they are written to it (as expected). When I change the fixture to @fixture(scope="module", autouse=True) the values only get read from the queue at teardown - the task gets continued only while teardown. In fact this behavior appears for every scope!="function". This seems to be the case for every task created in a fixture and leads to not working tests for fixtures with scopes other than "function".
Am I missing something here and this is intended behavior? Or is this a bug?

from pytest_asyncio import fixture
from pytest import mark
from asyncio import sleep, create_task
from asyncio.queues import Queue
from logging import error


queue = Queue()


async def recv(queue: Queue):
    error(f'recv task started')
    await queue.put("test")
    while True:
        error(f'recv {await queue.get()}')


@fixture(scope="module", autouse=True)
async def fix():
    global queue
    task = create_task(recv(queue))
    yield
    task.cancel()


@mark.asyncio
async def test_test():
    global queue
    for i in range(5):
        error(f'send {i}')
        await queue.put(i)
        await sleep(0.1)
    assert False

image
(scope="function") Expected behavior. The messages get read while the test is running - The task gets continued while the test is running

image
(scope="module") Unexpected behavior. The messages get read at teardown - The task gets continued after the test is run

@seifertm
Copy link
Contributor

I see two issues here:

  1. You're running pytest-asyncio in strict mode (the default), but you expect pytest-asyncio to transform @pytest.fixture to an async fixture. This is probably not the behavior you expect (see asyncio modes).
  2. You expect the fixture and the test code to run in the same event loop, yet you use scope=module in the fixture, but scope=function (the default) in the test. Due to Breaking change in 0.23.* #706, this leads to the fixture and the test to run in different event loops ( see also asyncio event loops) and is probably the reason for your issue. You can try the pytest-asyncio v0.24.0a0 pre-release and see if it fixes this issue for you.

Let me know if this helps.

@seifertm seifertm added the needsinfo Requires additional information from the issue author label Jul 31, 2024
@Hernell12
Copy link
Author

Hernell12 commented Aug 1, 2024

  1. I didn't copy the first line of the script, I edited the first post. The fixture is/was async
from pytest_asyncio import fixture
  1. When I mark the test_test function with @mark.asyncio(scope='module') it works as expected. Thank you for your help! I wasn't aware that a loop is run for each scope. This explains the behavior. The same behavior is observed with v0.24.0a0. When the scope is specified in the @mark.asyncio(loop_scope=...) it works, otherwise it won't..

@seifertm
Copy link
Contributor

seifertm commented Aug 1, 2024

Thanks for reporting back!

The multiple event loops thing may not be immediately obvious. Do you have any suggestions what could be improved in the usage of pytest-asyncio or in docs to make this more understandable?

@Hernell12
Copy link
Author

Hernell12 commented Aug 1, 2024

Hmm.. After reading the docs carefully again it is quiet clearly stated there (my bad I guess)
Maybe throw a warning if an async_test is run with an async fixture and the scopes mismatch, and a option to disable those warnings (if possible and not too troublesome)?

@seifertm
Copy link
Contributor

seifertm commented Aug 1, 2024

I agree with the warning! #873 is aimed at notifying the user in more cases when the scopes don't match

@seifertm seifertm closed this as not planned Won't fix, can't repro, duplicate, stale Aug 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needsinfo Requires additional information from the issue author
Projects
None yet
Development

No branches or pull requests

2 participants