Permalink
Browse files

TwistedIOLoop now supports overriding handle_callback_exception.

  • Loading branch information...
1 parent 3c24b7b commit 5b4f02820287b78215b6d1f616b04d809b77de68 @bdarnell bdarnell committed Dec 9, 2012
Showing with 24 additions and 4 deletions.
  1. +9 −3 tornado/platform/twisted.py
  2. +15 −1 tornado/test/ioloop_test.py
@@ -446,21 +446,27 @@ def start(self):
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)
elif isinstance(deadline, datetime.timedelta):
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)
@@ -5,11 +5,12 @@
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 @@ def target():
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):

0 comments on commit 5b4f028

Please sign in to comment.