1

I have a code snippet that I have wrapped in my own decorator. My decorator simply "catches" all exceptions, and then prints them, then re-raises them. However this is causing me an issue when I have multiple functions calling each other, as they're all getting printed. Example:

@error_wrapper def myFunction(x, y): return int_div(x, y) @error_wrapper def int_div(x, y): return x//y 

As you see from the code above, whenever y is 0, the function would error because of DivisionByZero. Now since both of these functions are wrapped in my error_wrapper, which is basically a decorator that does:

try: return func(*args, **kwargs) except Exception as e: print(e) raise 

The problem here is that the raise is happening in myFunction and in int_div, which is a side effect of wrapping both functions. So what solution I'm satisfied with is instead of raiseing the error again, I would just do a return with no return value, but this would make me lose the traceback, which is necessary for me to debug the code. I have seen the traceback module, and I've tried it, but now the problem I'm facing is the return is returning None, which is not the intended behavior. Any insight on how to tackle this?

3
  • just curious... why? uncaught exceptions get dumped to the command line anyway. Why not just catch the errors you might expect where you would expect them, and let the VM handle the rest Commented Aug 30, 2021 at 16:05
  • @DavidCulbreth Because this is going to end up in a GUI application, so eventually I would pop up a message box that contains the error details to the user, and it's currently popping up twice. Commented Aug 30, 2021 at 16:12
  • 2
    In that case, you should catch the error as far up the stack as you can go before needing to display it to the user. the answer I provided may function moderately, but I'm not happy about it. :P Commented Aug 30, 2021 at 16:19

1 Answer 1

3

You can simply set a flag on the error itself, and then check for said flag. I'm using something verbose to hopefully avoid any name collisions.

def error_wrapper(func): def wrapper(*args, **kwargs): try: return func(*args, **kwargs) except Exception as e: if not hasattr(e, "_error_wrapper_printed"): e._error_wrapper_printed = True print(e) raise return wrapper @error_wrapper def myFunction(x, y): return int_div(x, y) @error_wrapper def int_div(x, y): return x//y print(myFunction(1, 0)) 

The above yields behavior which (I believe) fits what you need.

integer division or modulo by zero Traceback (most recent call last): File "c:\Users\david\Desktop\tmp.py", line 21, in <module> print(myFunction(1, 0)) File "c:\Users\david\Desktop\tmp.py", line 4, in wrapper return func(*args, **kwargs) File "c:\Users\david\Desktop\tmp.py", line 15, in myFunction return int_div(x, y) File "c:\Users\david\Desktop\tmp.py", line 4, in wrapper return func(*args, **kwargs) File "c:\Users\david\Desktop\tmp.py", line 19, in int_div return x//y ZeroDivisionError: integer division or modulo by zero 
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you very much, I tried doing something similar but it didn't occur to me at all to add the flag into the exception itself! I was currently trying to create a new Exception class called DuckedException, but this flag solves everything!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.