Search code examples
pythondecoratorpython-multithreadingpython-decorators

About catching errors with decorators


I am trying to catch threads errors with a decorator :

class cc:
    def catch_exceptions(job_func):
        @functools.wraps(job_func)
        def wrapper(*args, **kwargs):
            try:
                job_func(*args, **kwargs)
            except:
                import traceback
                print(traceback.format_exc())
            return wrapper

    @catch_exceptions
    def job(self, name, command):
        #print("I'm running on thread %s" % threading.current_thread())
        os.system(command)

    def run_threaded(self, job_func, name, command):
        job_thread = threading.Thread(target=job_func, args=(name, command,) )
        job_thread.start()

and I am having this problem :

File "/usr/local/lib/python2.7/dist-packages/schedule/__init__.py", line 320, in do
self.job_func = functools.partial(job_func, *args, **kwargs)
TypeError: the first argument must be callable

How can I make job_func callable ?


Solution

  • You got the indentation wrong in your decorator; unindent the return wrapper line.

    As it stands, your decorator returns None, so cc.job is set to None.

    The corrected version would be:

    def catch_exceptions(job_func):
        @functools.wraps(job_func)
        def wrapper(*args, **kwargs):
            try:
                job_func(*args, **kwargs)
            except:
                import traceback
                print(traceback.format_exc())
        return wrapper
    

    You probably want to avoid using an entirely bare except there; you are now catching keyboard interrupts and system exit exceptions too. In a thread that doesn't matter all that much (the exceptions, if uncaught, do not propagate to the main thread anyway), but usually you want to use except Exception: at the very least.