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,
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())
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
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):
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):