From: Ben Darnell Date: Sun, 4 Oct 2015 00:31:20 +0000 (-0400) Subject: Add support for native coroutines in IOLoop.run_sync. X-Git-Tag: v4.3.0b1~8^2~6 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7bdbd0b2aba3ccbc46792ff9da38203027941246;p=thirdparty%2Ftornado.git Add support for native coroutines in IOLoop.run_sync. Remove support for synchronous functions with non-None results. --- diff --git a/tornado/ioloop.py b/tornado/ioloop.py index 195475ba0..742a84879 100644 --- a/tornado/ioloop.py +++ b/tornado/ioloop.py @@ -400,10 +400,12 @@ class IOLoop(Configurable): def run_sync(self, func, timeout=None): """Starts the `IOLoop`, runs the given function, and stops the loop. - If the function returns a `.Future`, the `IOLoop` will run - until the future is resolved. If it raises an exception, the - `IOLoop` will stop and the exception will be re-raised to the - caller. + The function must return either a yieldable object or + ``None``. If the function returns a yieldable object, the + `IOLoop` will run until the yieldable is resolved (and + `run_sync()` will return the yieldable's result). If it raises + an exception, the `IOLoop` will stop and the exception will be + re-raised to the caller. The keyword-only argument ``timeout`` may be used to set a maximum duration for the function. If the timeout expires, @@ -418,12 +420,18 @@ class IOLoop(Configurable): if __name__ == '__main__': IOLoop.current().run_sync(main) + + .. versionchanged:: 4.3 + Returning a non-``None``, non-yieldable value is now an error. """ future_cell = [None] def run(): try: result = func() + if result is not None: + from tornado.gen import convert_yielded + result = convert_yielded(result) except Exception: future_cell[0] = TracebackFuture() future_cell[0].set_exc_info(sys.exc_info()) diff --git a/tornado/test/ioloop_test.py b/tornado/test/ioloop_test.py index 0711282e3..8c2edd2f9 100644 --- a/tornado/test/ioloop_test.py +++ b/tornado/test/ioloop_test.py @@ -16,7 +16,7 @@ from tornado.log import app_log from tornado.platform.select import _Select from tornado.stack_context import ExceptionStackContext, StackContext, wrap, NullContext from tornado.testing import AsyncTestCase, bind_unused_port, ExpectLog -from tornado.test.util import unittest, skipIfNonUnix, skipOnTravis +from tornado.test.util import unittest, skipIfNonUnix, skipOnTravis, skipBefore35, exec_test try: from concurrent import futures @@ -558,7 +558,8 @@ class TestIOLoopRunSync(unittest.TestCase): self.io_loop.close() def test_sync_result(self): - self.assertEqual(self.io_loop.run_sync(lambda: 42), 42) + with self.assertRaises(gen.BadYieldError): + self.io_loop.run_sync(lambda: 42) def test_sync_exception(self): with self.assertRaises(ZeroDivisionError): @@ -590,6 +591,14 @@ class TestIOLoopRunSync(unittest.TestCase): yield gen.Task(self.io_loop.add_timeout, self.io_loop.time() + 1) self.assertRaises(TimeoutError, self.io_loop.run_sync, f, timeout=0.01) + @skipBefore35 + def test_native_coroutine(self): + namespace = exec_test(globals(), locals(), """ + async def f(): + await gen.Task(self.io_loop.add_callback) + """) + self.io_loop.run_sync(namespace['f']) + class TestPeriodicCallback(unittest.TestCase): def setUp(self):