summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbrian.quinlan <devnull@localhost>2010-07-30 05:50:09 +0000
committerbrian.quinlan <devnull@localhost>2010-07-30 05:50:09 +0000
commitec104f8f187cbcc962b0f720f72f03e3cd981aa5 (patch)
tree72b87dc1f4305c5abb0d355c4c3f5a160bc0353f
parent992e94f64f379b6c918469275758309ac753b6ff (diff)
downloadfutures-ec104f8f187cbcc962b0f720f72f03e3cd981aa5.tar.gz
Handles the case were a Future callback raises.
-rw-r--r--docs/index.rst11
-rw-r--r--python3/futures/_base.py5
-rw-r--r--python3/test_futures.py20
3 files changed, 32 insertions, 4 deletions
diff --git a/docs/index.rst b/docs/index.rst
index 27e429c..ac006a8 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -251,9 +251,14 @@ The :class:`Future` class encapulates the asynchronous execution of a callable.
Attaches the callable *fn* to the future. *fn* will be called, with the
future as its only argument, when the future is cancelled or finishes
- running. Added callables are called in the order that they were added and are
- always called in a thread belonging to the process that added them.
-
+ running.
+
+ Added callables are called in the order that they were added and are always
+ called in a thread belonging to the process that added them. If the callable
+ raises an :exc:`Exception` then it will be logged and ignored. If the
+ callable raises another :exc:`BaseException` then the behavior is not
+ defined.
+
If the future has already completed or been cancelled then *fn* will be
called immediately.
diff --git a/python3/futures/_base.py b/python3/futures/_base.py
index 7efc48b..c1181e9 100644
--- a/python3/futures/_base.py
+++ b/python3/futures/_base.py
@@ -261,7 +261,10 @@ class Future(object):
def _invoke_callbacks(self):
for callback in self._done_callbacks:
- callback(self)
+ try:
+ callback(self)
+ except Exception:
+ LOGGER.exception('exception calling callback for %r', self)
def __repr__(self):
with self._condition:
diff --git a/python3/test_futures.py b/python3/test_futures.py
index b032769..666adbf 100644
--- a/python3/test_futures.py
+++ b/python3/test_futures.py
@@ -618,6 +618,26 @@ class FutureTests(unittest.TestCase):
self.assertTrue(f.cancel())
self.assertTrue(was_cancelled)
+ def test_done_callback_raises(self):
+ raising_was_called = False
+ fn_was_called = False
+
+ def raising_fn(callback_future):
+ nonlocal raising_was_called
+ raising_was_called = True
+ raise Exception('doh!')
+
+ def fn(callback_future):
+ nonlocal fn_was_called
+ fn_was_called = True
+
+ f = Future()
+ f.add_done_callback(raising_fn)
+ f.add_done_callback(fn)
+ f.set_result(5)
+ self.assertTrue(raising_was_called)
+ self.assertTrue(fn_was_called)
+
def test_done_callback_already_successful(self):
callback_result = None
def fn(callback_future):