[Checkins] SVN: zc.thread/trunk/ - If a thread raises an exception (subclass of Exception), the
jim
cvs-admin at zope.org
Tue Jan 1 21:40:01 UTC 2013
Log message for revision 128985:
- If a thread raises an exception (subclass of Exception), the
exception is logged and a traceback is printed to standard error.
- A restart argument can be used to rerun a thread target function if
there's an uncaught exception. Value passed to the restart argument
is passed to time.sleep before restarting the function.
Changed:
U zc.thread/trunk/README.txt
U zc.thread/trunk/src/zc/thread/__init__.py
U zc.thread/trunk/src/zc/thread/tests.py
-=-
Modified: zc.thread/trunk/README.txt
===================================================================
--- zc.thread/trunk/README.txt 2013-01-01 21:08:21 UTC (rev 128984)
+++ zc.thread/trunk/README.txt 2013-01-01 21:40:00 UTC (rev 128985)
@@ -55,11 +55,17 @@
Changes
*******
-0.1.1 (2013-01-01)
+0.1.1 (2013-01-??)
==================
- Thread names now include a function's module name.
+- Unhandled exceptions in thread and process targets are now logged
+ and printed with tracebacks.
+
+- A restart argument can be used to automatically restart thread
+ targets after a rest.
+
0.1.0 (2011-11-27)
==================
Modified: zc.thread/trunk/src/zc/thread/__init__.py
===================================================================
--- zc.thread/trunk/src/zc/thread/__init__.py 2013-01-01 21:08:21 UTC (rev 128984)
+++ zc.thread/trunk/src/zc/thread/__init__.py 2013-01-01 21:40:00 UTC (rev 128985)
@@ -17,7 +17,7 @@
exiting = False
@atexit.register
-def _():
+def set_exiting():
global exiting
exiting = True
@@ -42,7 +42,7 @@
return
import logging
logging.getLogger(name).exception(
- 'Exception in %s', class_.name)
+ 'Exception in %s', class_.__name__)
import traceback
traceback.print_exc()
if not restart:
Modified: zc.thread/trunk/src/zc/thread/tests.py
===================================================================
--- zc.thread/trunk/src/zc/thread/tests.py 2013-01-01 21:08:21 UTC (rev 128984)
+++ zc.thread/trunk/src/zc/thread/tests.py 2013-01-01 21:40:00 UTC (rev 128985)
@@ -33,20 +33,30 @@
foo.setDaemon.assert_called_with(True)
foo.start.assert_called_with()
- def test_undecorated_and_exception_return(self):
+ @mock.patch('logging.getLogger')
+ @mock.patch('traceback.print_exc')
+ def test_undecorated_and_exception_return(self, print_exc, getLogger):
with mock.patch('threading.Thread') as Thread:
def foo2():
raise ValueError(42)
+ Thread.__name__ = 'Thread'
t = zc.thread.Thread(foo2)
Thread.call_args[1].pop('target')()
- Thread.assert_called_with(name='zc.thread.tests.foo2', args=(), kwargs=dict())
+ Thread.assert_called_with(
+ name='zc.thread.tests.foo2', args=(), kwargs=dict())
t.setDaemon.assert_called_with(True)
t.start.assert_called_with()
self.assert_(t.value is None)
self.assert_(isinstance(t.exception, ValueError))
self.assert_(t.exception.args == (42,))
+ getLogger.assert_called_with('zc.thread.tests.foo2')
+ getLogger.return_value.exception.assert_called_with(
+ "Exception in %s", "Thread")
+
+ print_exc.assert_called_with()
+
t = zc.thread.Thread(foo2, args=(1, 2))
Thread.call_args[1].pop('target')(1, 2)
Thread.assert_called_with(name='zc.thread.tests.foo2',
@@ -56,6 +66,44 @@
self.assert_(t.value is None)
self.assert_(isinstance(t.exception, TypeError))
+
+ @mock.patch('logging.getLogger')
+ @mock.patch('traceback.print_exc')
+ @mock.patch('threading.Thread')
+ def test_no_exceotion_handling_if_exiting(
+ self, Thread, print_exc, getLogger):
+ self.assertEqual(zc.thread.exiting, False)
+ zc.thread.set_exiting()
+ self.assertEqual(zc.thread.exiting, True)
+
+ @zc.thread.Thread
+ def foo2():
+ raise ValueError(42)
+ Thread.call_args[1].pop('target')()
+ getLogger.assert_not_called()
+ print_exc.assert_not_called()
+ zc.thread.exiting = False
+
+ @mock.patch('time.sleep')
+ @mock.patch('logging.getLogger')
+ @mock.patch('traceback.print_exc')
+ @mock.patch('threading.Thread')
+ def test_restart(self, Thread, print_exc, getLogger, sleep):
+ called = []
+ Thread.__name__ = 'Thread'
+
+ @zc.thread.Thread(restart=9)
+ def foo2():
+ called.append(0)
+ if len(called) < 3:
+ raise ValueError(42)
+ else:
+ raise BaseException
+
+ self.assertRaises(BaseException, Thread.call_args[1].pop('target'))
+ self.assertEqual(len(called), 3)
+ sleep.assert_called_with(9)
+
def test_passing_arguments(self):
with mock.patch('threading.Thread') as Thread:
@zc.thread.Thread(args=(1, 2), kwargs=dict(a=1), daemon=False,
More information about the checkins
mailing list