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

trio_asyncio.open_loop() in a fixture? #71

Open
SillyFreak opened this issue Nov 15, 2018 · 7 comments
Open

trio_asyncio.open_loop() in a fixture? #71

SillyFreak opened this issue Nov 15, 2018 · 7 comments

Comments

@SillyFreak
Copy link

I hoped to be able to do the following for my test cases requiring trio-asyncio:

@pytest_trio.trio_fixture
async def trio_aio_loop():
    async with trio_asyncio.open_loop() as loop:
        yield loop

@pytest.mark.trio
async def test_aio_funcs(trio_aio_loop, autojump_clock):
    @trio_asyncio.aio_as_trio
    async def func():
        await asyncio.sleep(0.1)
        return 1

    assert await func() == 1

However the fixture blows up:

test setup failed
@pytest_trio.trio_fixture
    async def trio_aio_loop():
>       async with trio_asyncio.open_loop() as loop:

tests/test_loop.py:261: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.../env/lib/python3.7/site-packages/async_generator/_util.py:34: in __aenter__
    return await self._agen.asend(None)
.../env/lib/python3.7/site-packages/async_generator/_impl.py:366: in step
    return await ANextIter(self._it, start_fn, *args)
.../env/lib/python3.7/site-packages/async_generator/_impl.py:197: in __next__
    return self._invoke(first_fn, *first_args)
.../env/lib/python3.7/site-packages/async_generator/_impl.py:209: in _invoke
    result = fn(*args)
.../env/lib/python3.7/site-packages/trio_asyncio/async_.py:108: in open_loop
    async with trio.open_nursery() as nursery:
.../env/lib/python3.7/site-packages/trio/_core/_run.py:378: in __aenter__
    self._scope = CancelScope._create(deadline=inf, shield=False)
.../env/lib/python3.7/site-packages/trio/_core/_run.py:130: in _create
    task = _core.current_task()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

    def current_task():
        """Return the :class:`Task` object representing the current task.
    
        Returns:
          Task: the :class:`Task` that called :func:`current_task`.
    
        """
    
        try:
            return GLOBAL_RUN_CONTEXT.task
        except AttributeError:
>           raise RuntimeError("must be called from async context") from None
E           RuntimeError: must be called from async context

.../env/lib/python3.7/site-packages/trio/_core/_run.py:1534: RuntimeError

I assume that has to do something with the description of fixture handling here (I admit not having read it in full). It seems rather intricate, so I have no idea how hard this would be to fix. I think it would be a valuable addition, though.

@touilleMan
Copy link
Member

Hi,

You should have a look here:

https://github.com/Scille/parsec-cloud/blob/e1e25366d07425312712c01950440476a7322608/tests/conftest.py#L133-L140

Btw trio-asyncio is tricky because it creates relationship between two event loops, which can end up in hard to track deadlocks. For instance you should avoid using the nursery fitxure along with an asyncio_loop fixture (because there are both disconnected from trio point of view, but once the asyncio_loop is torndown, coroutines belonging to the nursery fixture and using asyncio code won't work anymore without explanation...)

@SillyFreak
Copy link
Author

thanks for the hint! could you very shortly explain why it has to be @pytest.fixture instead of @pytest_trio.trio_fixture, even though trio_asyncio.open_loop() is a trio-style async context manager? The shielded cancel scope is separate from that, for the issue you pointed out above, right?

@touilleMan
Copy link
Member

@SillyFreak @pytest_trio.trio_fixture is just a small wrapper around @pytest.fixture to flag the test using it as trio (in my tests I use the @pytest.mark.trio decorator to add this trio flag)

@njsmith
Copy link
Member

njsmith commented Jan 12, 2019

If you have trio-mode enabled, then @pytest.fixture and @pytest_trio.trio_fixture are equivalent when applied to an async def; it doesn't matter which one you use. You can also use @pytest_trio.trio_fixture on synchronous fixtures, or when trio mode isn't enabled, and in that case it makes a difference.

@lordi
Copy link

lordi commented Feb 2, 2019

I think we currently can't use trio_asyncio.open_loop at all with pytest_trio, because it would require that the test is ran with trio_asyncio.run instead of trio.run. Is that assumption correct?

@njsmith
Copy link
Member

njsmith commented Feb 2, 2019

@lordi No, trio_asyncio.run is just a confusing shorthand for doing trio.run and then trio_asyncio.open_loop. So you don't need it; you can just do open_loop yourself. I'm not sure why we have trio_asyncio.run, honestly; trio_asyncio's core is pretty solid but the API still needs some fine tuning.

@lordi
Copy link

lordi commented Feb 2, 2019

Ok, thanks, that's good to know.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants