Raise a python Exception and then continue

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?

Answer

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:UsersdavidDesktoptmp.py", line 21, in <module>
    print(myFunction(1, 0))
  File "c:UsersdavidDesktoptmp.py", line 4, in wrapper
    return func(*args, **kwargs)
  File "c:UsersdavidDesktoptmp.py", line 15, in myFunction
    return int_div(x, y)
  File "c:UsersdavidDesktoptmp.py", line 4, in wrapper
    return func(*args, **kwargs)
  File "c:UsersdavidDesktoptmp.py", line 19, in int_div
    return x//y
ZeroDivisionError: integer division or modulo by zero