]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
Support other yieldables in to_asyncio_future.
authorBen Darnell <ben@bendarnell.com>
Sun, 4 Oct 2015 01:57:33 +0000 (21:57 -0400)
committerBen Darnell <ben@bendarnell.com>
Sun, 4 Oct 2015 02:28:15 +0000 (22:28 -0400)
tornado/platform/asyncio.py
tornado/test/asyncio_test.py

index c95c207fb994ce5b0aef5fe293aaeca96c9fd9ae..bf0428ec511c3fbed7b7d236571ae78a10394cc0 100644 (file)
@@ -199,10 +199,15 @@ def to_tornado_future(asyncio_future):
 
 
 def to_asyncio_future(tornado_future):
-    """Convert a `tornado.concurrent.Future` to an `asyncio.Future`.
+    """Convert a Tornado yieldable object to an `asyncio.Future`.
 
     .. versionadded:: 4.1
+
+    .. versionchanged:: 4.3
+       Now accepts any yieldable object, not just
+       `tornado.concurrent.Future`.
     """
+    tornado_future = convert_yielded(tornado_future)
     af = asyncio.Future()
     tornado.concurrent.chain_future(tornado_future, af)
     return af
index 94a569104117ae11c475241fe134cba777c46f0e..52ba9d353b73e501d2e97fc815f7009b2e3695b9 100644 (file)
@@ -14,12 +14,16 @@ from __future__ import absolute_import, division, print_function, with_statement
 
 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")
@@ -61,3 +65,54 @@ class AsyncIOLoopTest(AsyncTestCase):
         """)
         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)