eukaryote / pytest-tornasync

A pytest plugin for testing Tornado (version 5.0 or newer) apps using plain (undecoratored) native coroutine tests.
MIT License
25 stars 4 forks source link

Conflict with pytest-asyncio #13

Closed MetRonnie closed 2 years ago

MetRonnie commented 2 years ago

When running tests in a project that doesn't have pytest-tornasync as a dependency, with pytest-asyncio 0.17.2 and asyncio_mode = auto in pytest.ini, I get failures after removing @pytest.mark.asyncio decorators from my tests.

pyfuncitem = <Function test_something>

    @pytest.mark.tryfirst
    def pytest_pyfunc_call(pyfuncitem):
        funcargs = pyfuncitem.funcargs
        testargs = {arg: funcargs[arg] for arg in pyfuncitem._fixtureinfo.argnames}

        if not iscoroutinefunction(pyfuncitem.obj):
            pyfuncitem.obj(**testargs)
            return True

        try:
>           loop = funcargs["io_loop"]
E           KeyError: 'io_loop'

~/.conda/envs/myenv/lib/python3.9/site-packages/pytest_tornasync/plugin.py:49: KeyError

During handling of the above exception, another exception occurred:

pyfuncitem = <Function test_something>

    @pytest.mark.tryfirst
    def pytest_pyfunc_call(pyfuncitem):
        funcargs = pyfuncitem.funcargs
        testargs = {arg: funcargs[arg] for arg in pyfuncitem._fixtureinfo.argnames}

        if not iscoroutinefunction(pyfuncitem.obj):
            pyfuncitem.obj(**testargs)
            return True

        try:
            loop = funcargs["io_loop"]
        except KeyError:
>           loop = tornado.ioloop.IOLoop.current()

~/.conda/envs/myenv/lib/python3.9/site-packages/pytest_tornasync/plugin.py:51: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
~/.conda/envs/myenv/lib/python3.9/site-packages/tornado/ioloop.py:263: in current
    loop = asyncio.get_event_loop()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <asyncio.unix_events._UnixDefaultEventLoopPolicy object at 0x7fcc51c39760>

    def get_event_loop(self):
        """Get the event loop for the current context.

        Returns an instance of EventLoop or raises an exception.
        """
        if (self._local._loop is None and
                not self._local._set_called and
                threading.current_thread() is threading.main_thread()):
            self.set_event_loop(self.new_event_loop())

        if self._local._loop is None:
>           raise RuntimeError('There is no current event loop in thread %r.'
                               % threading.current_thread().name)
E           RuntimeError: There is no current event loop in thread 'MainThread'.

~/.conda/envs/myenv/lib/python3.9/asyncio/events.py:642: RuntimeError
MetRonnie commented 2 years ago

@MetRonnie After a brief look at pytest-tornasync it seems the plugin has a similar behaviour to pytest-asyncio with async_mode=auto: It tries to run all tests that are coroutines in a tornado.IoLoop. When both plugins try to do the same thing, unexpected things happen.

If your project is using both pytest-asyncio and pytest-tornasync, you should stick with asyncio_mode=strict.

https://github.com/pytest-dev/pytest-asyncio/issues/257#issuecomment-1017566870

However, seeing as the project does not have pytest-tornasync as a dependency, we were instead able to do

def pytest_addhooks(pluginmanager):
    pluginmanager.unregister('tornado')

in conftest.py.

Update: that conftest fix doesn't actually seem to work, instead this works in pytest.ini:

[pytest]
addopts =
    -p no:tornado