Make tests pass for catching exceptions.

May now use sys.excepthook to catch exceptions
from threaded handlers.
This commit is contained in:
Lance Stout 2010-12-17 13:11:03 -05:00
parent 506eccf84d
commit 34c374a1e1
3 changed files with 47 additions and 16 deletions

View file

@ -64,7 +64,7 @@ class RootStanza(StanzaBase):
log.exception('Error handling {%s}%s stanza' %
(self.namespace, self.name))
# Finally raise the exception, so it can be handled (or not)
# at a higher level
# at a higher level by using sys.excepthook.
raise e
register_stanza_plugin(RootStanza, Error)

View file

@ -682,6 +682,7 @@ class XMLStream(object):
Event handlers and the send queue will be threaded
regardless of this parameter's value.
"""
self._thread_excepthook()
self.scheduler.process(threaded=True)
def start_thread(name, target):
@ -954,3 +955,26 @@ class XMLStream(object):
self.disconnect()
self.event_queue.put(('quit', None, None))
return
def _thread_excepthook(self):
"""
If a threaded event handler raises an exception, there is no way to
catch it except with an excepthook. Currently, each thread has its own
excepthook, but ideally we could use the main sys.excepthook.
Modifies threading.Thread to use sys.excepthook when an exception
is not caught.
"""
init_old = threading.Thread.__init__
def init(self, *args, **kwargs):
init_old(self, *args, **kwargs)
run_old = self.run
def run_with_except_hook(*args, **kw):
try:
run_old(*args, **kw)
except (KeyboardInterrupt, SystemExit):
raise
except:
sys.excepthook(*sys.exc_info())
self.run = run_with_except_hook
threading.Thread.__init__ = init

View file

@ -10,6 +10,7 @@ class TestStreamExceptions(SleekTest):
"""
def tearDown(self):
sys.excepthook = sys.__excepthook__
self.stream_close()
def testXMPPErrorException(self):
@ -78,9 +79,16 @@ class TestStreamExceptions(SleekTest):
def testUnknownException(self):
"""Test raising an generic exception in a threaded handler."""
raised_errors = []
def message(msg):
raise ValueError("Did something wrong")
def catch_error(*args, **kwargs):
raised_errors.append(True)
sys.excepthook = catch_error
self.stream_start()
self.xmpp.add_event_handler('message', message)
@ -90,21 +98,20 @@ class TestStreamExceptions(SleekTest):
</message>
""")
if sys.version_info < (3, 0):
self.send("""
<message type="error">
<error type="cancel">
<undefined-condition
xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" />
<text xmlns="urn:ietf:params:xml:ns:xmpp-stanzas">
SleekXMPP got into trouble.
</text>
</error>
</message>
""")
else:
# Unfortunately, tracebacks do not make for very portable tests.
pass
self.send("""
<message type="error">
<error type="cancel">
<undefined-condition
xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" />
<text xmlns="urn:ietf:params:xml:ns:xmpp-stanzas">
SleekXMPP got into trouble.
</text>
</error>
</message>
""")
self.assertEqual(raised_errors, [True], "Exception was not raised: %s" % raised_errors)
suite = unittest.TestLoader().loadTestsFromTestCase(TestStreamExceptions)