from tornado import gen
from tornado.testing import AsyncTestCase, gen_test
-from tornado.test.util import unittest, skipBefore33, exec_test
+from tornado.test.util import unittest, skipBefore33, skipBefore35, exec_test
try:
- from tornado.platform.asyncio import asyncio, AsyncIOLoop
+ from tornado.platform.asyncio import asyncio
except ImportError:
asyncio = None
+else:
+ from tornado.platform.asyncio import AsyncIOLoop, to_asyncio_future
+ # This is used in dynamically-evaluated code, so silence pyflakes.
+ to_asyncio_future
skipIfNoSingleDispatch = unittest.skipIf(
gen.singledispatch is None, "singledispatch module not present")
""")
result = yield namespace['f']()
self.assertEqual(result, 42)
+
+ @skipBefore35
+ def test_asyncio_adapter(self):
+ # This test demonstrates that when using the asyncio coroutine
+ # runner (i.e. run_until_complete), the to_asyncio_future
+ # adapter is needed. No adapter is needed in the other direction,
+ # as demonstrated by other tests in the package.
+ @gen.coroutine
+ def tornado_coroutine():
+ yield gen.Task(self.io_loop.add_callback)
+ raise gen.Return(42)
+ native_coroutine_without_adapter = exec_test(globals(), locals(), """
+ async def native_coroutine_without_adapter():
+ return await tornado_coroutine()
+ """)["native_coroutine_without_adapter"]
+
+ native_coroutine_with_adapter = exec_test(globals(), locals(), """
+ async def native_coroutine_with_adapter():
+ return await to_asyncio_future(tornado_coroutine())
+ """)["native_coroutine_with_adapter"]
+
+ # Use the adapter, but two degrees from the tornado coroutine.
+ native_coroutine_with_adapter2 = exec_test(globals(), locals(), """
+ async def native_coroutine_with_adapter2():
+ return await to_asyncio_future(native_coroutine_without_adapter())
+ """)["native_coroutine_with_adapter2"]
+
+ # Tornado supports native coroutines both with and without adapters
+ self.assertEqual(
+ self.io_loop.run_sync(native_coroutine_without_adapter),
+ 42)
+ self.assertEqual(
+ self.io_loop.run_sync(native_coroutine_with_adapter),
+ 42)
+ self.assertEqual(
+ self.io_loop.run_sync(native_coroutine_with_adapter2),
+ 42)
+
+ # Asyncio only supports coroutines that yield asyncio-compatible
+ # Futures.
+ with self.assertRaises(RuntimeError):
+ asyncio.get_event_loop().run_until_complete(
+ native_coroutine_without_adapter())
+ self.assertEqual(
+ asyncio.get_event_loop().run_until_complete(
+ native_coroutine_with_adapter()),
+ 42)
+ self.assertEqual(
+ asyncio.get_event_loop().run_until_complete(
+ native_coroutine_with_adapter2()),
+ 42)