From: Ben Darnell Date: Sun, 9 Dec 2012 00:17:27 +0000 (-0500) Subject: TwistedIOLoop now supports overriding handle_callback_exception. X-Git-Tag: v3.0.0~198 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5b4f02820287b78215b6d1f616b04d809b77de68;p=thirdparty%2Ftornado.git TwistedIOLoop now supports overriding handle_callback_exception. --- diff --git a/tornado/platform/twisted.py b/tornado/platform/twisted.py index 8aec93775..1efc82b70 100644 --- a/tornado/platform/twisted.py +++ b/tornado/platform/twisted.py @@ -446,6 +446,12 @@ class TwistedIOLoop(tornado.ioloop.IOLoop): def stop(self): self.reactor.crash() + def _run_callback(self, callback, *args, **kwargs): + try: + callback(*args, **kwargs) + except Exception: + self.handle_callback_exception(callback) + def add_timeout(self, deadline, callback): if isinstance(deadline, (int, long, float)): delay = max(deadline - self.time(), 0) @@ -453,14 +459,14 @@ class TwistedIOLoop(tornado.ioloop.IOLoop): delay = deadline.total_seconds() else: raise TypeError("Unsupported deadline %r") - return self.reactor.callLater(delay, wrap(callback)) + return self.reactor.callLater(delay, self._run_callback, wrap(callback)) def remove_timeout(self, timeout): timeout.cancel() def add_callback(self, callback, *args, **kwargs): - self.reactor.callFromThread(functools.partial(wrap(callback), - *args, **kwargs)) + self.reactor.callFromThread(self._run_callback, + wrap(callback), *args, **kwargs) def add_callback_from_signal(self, callback, *args, **kwargs): self.add_callback(callback, *args, **kwargs) diff --git a/tornado/test/ioloop_test.py b/tornado/test/ioloop_test.py index 1f8e5401a..53bb8a449 100644 --- a/tornado/test/ioloop_test.py +++ b/tornado/test/ioloop_test.py @@ -5,11 +5,12 @@ from __future__ import absolute_import, division, with_statement import contextlib import datetime import functools +import sys import threading import time from tornado.ioloop import IOLoop -from tornado.stack_context import ExceptionStackContext, StackContext, wrap +from tornado.stack_context import ExceptionStackContext, StackContext, wrap, NullContext from tornado.testing import AsyncTestCase, bind_unused_port from tornado.test.util import unittest @@ -113,6 +114,19 @@ class TestIOLoop(AsyncTestCase): self.assertEqual("IOLoop is closing", str(e)) break + def test_handle_callback_exception(self): + # IOLoop.handle_callback_exception can be overridden to catch + # exceptions in callbacks. + def handle_callback_exception(callback): + self.assertIs(sys.exc_info()[0], ZeroDivisionError) + self.stop() + self.io_loop.handle_callback_exception = handle_callback_exception + with NullContext(): + # remove the test StackContext that would see this uncaught + # exception as a test failure. + self.io_loop.add_callback(lambda: 1 / 0) + self.wait() + class TestIOLoopAddCallback(AsyncTestCase): def setUp(self):