1

I am working on a large web project (server-side) with some complex numerical algos that I work on at the core. The whole server-side code has extensive and elaborate error handling to give the UI a "good" feel.

While I am debugging in the development environment, however, it is useful if something goes wrong deep in the computational bowels to get a stack trace to my terminal. I wrote a small decorator/wrapper like so:

import traceback

def dbg(fn):
    def wrapper(*args, **kwargs):
        try:
            res = fn(*args, **kwargs)
            return res

        except Exception as what:
            print("caught trapped debug exception...")
            print(what)
            traceback.print_stack()
            print("re-raising...\n")
            raise what

    return wrapper

Then, before calling the numerical routines, I do like so:

@dbg
call_complex_numerical_routines(arg1, arg2, ...)

The goal is to get a traceback on my terminal, but pass the error back up so the complex error handling still works.

I may be losing my mind, but it seemed like when I had this in a separate file (dbg.py) and imported that, I got a stack trace that went to the point of what failed. But, now (or in any case), my stack trace stops at the wrapper, without telling me what failed inside the wrapper call, like so:

File "/home/utils.py", line 17, in wrapper
    result = func(*args, **kwargs)
File "/home/run.py", line 74, in wrapper
traceback.print_stack()

re-raising...

How do I get the rest of the traceback to print, so I can see what looks like a normal traceback that tells me what actually went wrong in the wrapped code?

1 Answer 1

2

You should raise without passing an exception so that the exception is passed through without being re-raised.

Change:

raise what

to:

raise
Sign up to request clarification or add additional context in comments.

4 Comments

OK, I'll try that...but can you explain the difference between using $raise$ with an exception, and why that is different from without one, and why that means it is 'passed through without being re-raised'?
With an exception instance as an argument, the raise statement will add the current frame to the exception instance and then re-raise the exception. Without the argument, the raise statement will instead simply pass on the exception in the current except block without altering it, so that the caller can handle it without having to deal with a frame unrelated to the cause of the exception.
Very insightful. Thanks.
I tried it, but it didn't make a difference. My stack trace still ends with the @dbg wrapper, not the failing line of source code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.