Search code examples
pythonunit-testingtornado

Where is proper place to install AsyncIOMainLoop() for Tornado application


So I have doubts what of 2 approaches to install AsyncIOMainLoop() I saw is more true. Which of them is more appropriate ?

1st When AsyncIOMainLoop() installed in make_app() code:

class MainHandler(tornado.web.RequestHandler):
    async def get(self, *args, **kwargs):
        return self.write("OK")

    async def post(self, *args, **kwargs):
        return self.write("OK")

def make_app():
    tornado.platform.asyncio.AsyncIOMainLoop().install()
    return tornado.web.Application([(r"/", MainHandler),],
                                   debug=False)

def start_app():
    app = make_app()
    app.listen(8888)
    asyncio.get_event_loop().run_forever()


if __name__ == "__main__":
    start_app()

2nd when AsyncIOMainLoop() installed in start_app() code:

class MainHandler(tornado.web.RequestHandler):
    async def get(self, *args, **kwargs):
        return self.write("OK")

    async def post(self, *args, **kwargs):
        return self.write("OK")

def make_app():
    return tornado.web.Application([(r"/", MainHandler),],
                                   debug=False)

def start_app():
    tornado.platform.asyncio.AsyncIOMainLoop().install()
    app = make_app()
    app.listen(8888)
    asyncio.get_event_loop().run_forever()


if __name__ == "__main__":
    start_app()

What do you think what of these 2 approaches is more appropriate ?

With 1st one I have troubles with running more than 2 tests in one AsyncHTTPTestCase suite with error like this:

Traceback (most recent call last):
  File "/home/kamyanskiy/.local/share/virtualenvs/test-0zFWLpVX/lib/python3.6/site-packages/tornado/testing.py", line 380, in setUp
    self._app = self.get_app()
  File "/home/kamyanskiy/work/test/test_app.py", line 10, in get_app
    return web1.make_app()
  File "/home/kamyanskiy/work/test/web1.py", line 74, in make_app
    tornado.platform.asyncio.AsyncIOMainLoop().install()
  File "/home/kamyanskiy/.local/share/virtualenvs/test-0zFWLpVX/lib/python3.6/site-packages/tornado/ioloop.py", line 181, in install
    assert not IOLoop.initialized()
AssertionError

With 2nd one, when AsyncIOMainLoop() is installed in start_app() code - tests are running ok, but here I have doubts that during tests AsyncIOMainLoop() is not used.

Tests looks like:

from tornado.testing import AsyncHTTPTestCase
import web1

class TestTornadoAppBase(AsyncHTTPTestCase):

    def get_app(self):
        return web1.make_app()

    # I have to uncomment this for 1st code example 
    # def tearDown(self):
    #    self.io_loop.clear_instance()  
    #    super().tearDown()

class TestGET(TestTornadoAppBase):
    def test_root_get_method(self):
        response = self.fetch("/")
        self.assertEqual(response.code, 200)
        self.assertEqual(response.body.decode(), 'OK')

    def test_root_post_method(self):
        response = self.fetch("/", method="POST", body='{"k": "v"}')
        self.assertEqual(response.code, 200)
        self.assertEqual(response.body.decode(), 'OK')

So what is true way to select where to init AsyncIOMainLoop() ?


Solution

  • Definitely the 2nd example as the documentation says:

    from tornado.platform.asyncio import AsyncIOMainLoop
    import asyncio
    AsyncIOMainLoop().install()
    asyncio.get_event_loop().run_forever()
    

    The point is that AsyncIOMainLoop has to be installed before you tell asyncio to run the loop.