import Queue
import threading
import logging
import monocle

log = logging.getLogger(__name__)

class AsynchJob(object):
    failure = None

    @monocle.o
    def start(self):
        try:
            yield self.do_stuff()
        except Exception, e:
            self.failure = e
            log.exception("Error in asynch job")

    @monocle.o
    def do_stuff(self):
        pass

def call_on_main_thread(callback, result):
    raise NotImplementedError

def worker_loop(in_queue, worker):
    while True:
        msg = in_queue.get()
        if msg is None:
            return
        try:
            callback, method, args, kwargs = msg
            result = getattr(worker, method)(*args, **kwargs)
            call_on_main_thread(callback, result)
        except Exception, e:
            call_on_main_thread(callback, e)

class AsynchWorkerProxy(object):
    def __init__(self, in_queue, thread):
        self._in_queue = in_queue
        self._thread = thread

    def __getattr__(self, name):
        @monocle.o
        def method_proxy(*args, **kwargs):
            callback = monocle.callback.Callback()
            self._in_queue.put((callback, name, args, kwargs))
            return callback
        return method_proxy

    def done(self):
        self._in_queue.put(None)
        self._thread.join()

def start_worker(worker):
    in_queue = Queue.Queue()
    thread = threading.Thread(target=worker_loop, args=(in_queue, worker))
    thread.start()
    return AsynchWorkerProxy(in_queue, thread)

@@ -291,43 +291,155 @@
     
-log.exception(%22Error in asynch job%22
+if hasattr(e, '_monocle'):%0A                log.error(%22%25s%5Cn%25s%22, str(e), monocle.core.format_tb(e))%0A            else:%0A                log.exception(e
 )%0A%0A 

print monocle-style tracebacks