From: Ben Darnell Date: Sun, 4 Oct 2015 00:42:48 +0000 (-0400) Subject: Recognize other yieldables in IOLoop._run_callback. X-Git-Tag: v4.3.0b1~8^2~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2237a72af711c49b020922c0f33a3fe63f6f8ee8;p=thirdparty%2Ftornado.git Recognize other yieldables in IOLoop._run_callback. --- diff --git a/tornado/ioloop.py b/tornado/ioloop.py index 742a84879..c23cb33e4 100644 --- a/tornado/ioloop.py +++ b/tornado/ioloop.py @@ -598,12 +598,21 @@ class IOLoop(Configurable): """ try: ret = callback() - if ret is not None and is_future(ret): + if ret is not None: + from tornado import gen # Functions that return Futures typically swallow all # exceptions and store them in the Future. If a Future # makes it out to the IOLoop, ensure its exception (if any) # gets logged too. - self.add_future(ret, lambda f: f.result()) + try: + ret = gen.convert_yielded(ret) + except gen.BadYieldError: + # It's not unusual for add_callback to be used with + # methods returning a non-None and non-yieldable + # result, which should just be ignored. + pass + else: + self.add_future(ret, lambda f: f.result()) except Exception: self.handle_callback_exception(callback) diff --git a/tornado/test/ioloop_test.py b/tornado/test/ioloop_test.py index 8c2edd2f9..71b4ef873 100644 --- a/tornado/test/ioloop_test.py +++ b/tornado/test/ioloop_test.py @@ -363,6 +363,18 @@ class TestIOLoop(AsyncTestCase): with ExpectLog(app_log, "Exception in callback"): self.wait() + @skipBefore35 + def test_exception_logging_native_coro(self): + """The IOLoop examines exceptions from awaitables and logs them.""" + namespace = exec_test(globals(), locals(), """ + async def callback(): + self.io_loop.add_callback(self.stop) + 1 / 0 + """) + with NullContext(): + self.io_loop.add_callback(namespace["callback"]) + with ExpectLog(app_log, "Exception in callback"): + self.wait() def test_spawn_callback(self): # An added callback runs in the test's stack_context, so will be # re-arised in wait().