62 lines
1.5 KiB
Python
62 lines
1.5 KiB
Python
|
'''
|
||
|
Implementation of exception-aware threads, including a listener to be put in
|
||
|
the top-level thread
|
||
|
'''
|
||
|
|
||
|
import queue
|
||
|
from threading import Thread, Event
|
||
|
|
||
|
# Killswitch for exception queue listener. Pass this to top-level thread so it
|
||
|
# can be called as part of clean up code
|
||
|
excStopper = Event()
|
||
|
|
||
|
# queue to shuttle exceptions from children to top-level thread
|
||
|
_excQueue = queue.Queue()
|
||
|
|
||
|
def excChildListener():
|
||
|
'''
|
||
|
Queue listener to intercept exceptions thrown in child threads that are
|
||
|
exception-aware
|
||
|
'''
|
||
|
while not excStopper.isSet():
|
||
|
try:
|
||
|
raise _excQueue.get(True)
|
||
|
_excQueue.task_done()
|
||
|
except queue.Empty:
|
||
|
pass
|
||
|
while 1:
|
||
|
try:
|
||
|
raise _excQueue.get(False)
|
||
|
_excQueue.task_done()
|
||
|
except queue.Empty:
|
||
|
break
|
||
|
|
||
|
class ExceptionThread(Thread):
|
||
|
'''
|
||
|
Thread that passes exceptions to a queue, which is handled by
|
||
|
excChildListener in top-level thread
|
||
|
'''
|
||
|
def __init__(self, group=None, target=None, name=None, args=(), kwargs=None, *, daemon=None):
|
||
|
super().__init__(group, target, name, args, kwargs, daemon=daemon)
|
||
|
self._queue = _excQueue
|
||
|
|
||
|
def run(self):
|
||
|
try:
|
||
|
Thread.run(self)
|
||
|
except BaseException as e:
|
||
|
self._queue.put(e)
|
||
|
|
||
|
class async:
|
||
|
'''
|
||
|
Wraps any function in an exception-aware thread and starts the thread.
|
||
|
Intended to be used as a decorator
|
||
|
'''
|
||
|
def __init__(self, daemon=False):
|
||
|
self._daemon = daemon
|
||
|
|
||
|
def __call__(self, f):
|
||
|
def wrapper(*args, **kwargs):
|
||
|
t = ExceptionThread(target=f, daemon=self._daemon, args=args, kwargs=kwargs)
|
||
|
t.start()
|
||
|
return wrapper
|