Skip to content

Instantly share code, notes, and snippets.

@psobot
Created April 14, 2012 19:05
Show Gist options
  • Save psobot/2386993 to your computer and use it in GitHub Desktop.
Save psobot/2386993 to your computer and use it in GitHub Desktop.
Exception-Raising Thread
import Queue
import threading
import sys
__author__ = 'psobot'
class ExceptionThread(threading.Thread):
def __init__(self, *args, **kwargs):
threading.Thread.__init__(self, *args, **kwargs)
self.__status_queue = Queue.Queue()
def run(self, *args, **kwargs):
try:
threading.Thread.run(self)
except Exception:
self.__status_queue.put(sys.exc_info())
self.__status_queue.put(None)
def join(self, num=None):
if not self.__status_queue:
return
try:
exc_info = self.__status_queue.get(True, num)
if exc_info:
raise exc_info[1], None, exc_info[2]
except Queue.Empty:
return
self.__status_queue = None
@cbhl
Copy link

cbhl commented Apr 14, 2012

Base class for a thread that tracks its own exceptions and raises them when joined by the main thread? Clever. I've always been tempted to just output them to stderr as they happen.

@psobot
Copy link
Author

psobot commented Apr 14, 2012

Useful when an app has exception-based flow control, as is somewhat common in Python. My situation was one where I had to run a couple parallel tasks, but any one of them could fail (and log error output gracefully), making the entire operation invalid. I can then also do a .join(0) to check if a thread has failed yet, before continuing on with the other threads' execution.

@psobot
Copy link
Author

psobot commented Apr 23, 2012

Fixed this to properly raise exceptions with their original context. Before, all exceptions raised here would print:

File "/var/www/helpers/exceptionthread.py", line 24, in join
    raise thread_exception

Now, they show the original raiser of the exception:

File "exceptiontest.py", line 4, in fun
    raise Exception("Hey, look at me, on line 4!")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment