error propagation
If you want to propagate the exception you can use use from clause
all the information ca be check here https://docs.python.org/3/reference/simple_stmts.html#grammar-token-raise-stmt
def c(x, y):
try:
return int(x), int(y)
except Exception as e:
msg = "x or y is probably not a number"
raise Exception(msg) from e
def b(x, y):
try:
x, y = c(x, y)
return x + y
except Exception as e:
msg = "issue during sum of x and y"
raise Exception(msg) from e
def a(x, y):
try:
return b(x, y)
except Exception as e:
msg = "some unknown error occured"
raise Exception(msg) from e
result = a('test', 10)
That way you have tracked all way back all errors and their origins
this is the output:
https://i.stack.imgur.com/2ho5K.png
supresion of traceback
in case you want to supress all the traceback of the error you need to use
from None
def a(x, y):
try:
return b(x, y)
except Exception as e:
msg = "some unknown error occured"
raise Exception(msg) from None
Now running the code will supress all previos errors, this is the output:
https://i.stack.imgur.com/loFis.png
Recovering the error as a string
The best way to capture the error I found so far and thanks to the comments of @anton who suggested using traceback is using a decorator
from functools import wraps, partial
import traceback
import sys
def error_handler(func=None, *, raise_error=False):
if not func:
return partial(error_handler, raise_error=raise_error)
@wraps(func)
def func_exectutor(*args, **kwargs):
try:
out = func(*args, **kwargs)
exception = False
except Exception as error:
exception = True
string = ''.join(traceback.format_exception(None, error, error.__traceback__))
out = string, error
finally:
if not exception:
return out
else:
if raise_error:
raise out[1]
else:
return out[0]
return func_exectutor
after decorating the function:
@error_handler(raise_error=False)
def a(x, y):
try:
return b(x, y)
except Exception as e:
msg = "some unknown error occured"
raise Exception(msg) from e
The output of the function if fails, is a string that contains the traceback of all the possible errors that occurred. If not the output is the expected one
a(4, 10)
>>> 14
a('test', 10)
>>> 'Traceback (most recent call last):\n File "/tmp/ipykernel_60630/2959315277.py", line 3, in c\n return int(x), int(y)\nValueError: invalid literal for int() with base 10: \'test\'\n\nThe above exception was the direct cause of the following exception:\n\nTraceback (most recent call last):\n File "/tmp/ipykernel_60630/2959315277.py", line 10, in b\n x, y = c(x, y)\n File "/tmp/ipykernel_60630/2959315277.py", line 6, in c\n raise Exception(msg) from e\nException: x or y is probably not a number\n\nThe above exception was the direct cause of the following exception:\n\nTraceback (most recent call last):\n File "/tmp/ipykernel_60630/2959315277.py", line 19, in a\n return b(x, y)\n File "/tmp/ipykernel_60630/2959315277.py", line 14, in b\n raise Exception(msg) from e\nException: issue during sum of x and y\n\nThe above exception was the direct cause of the following exception:\n\nTraceback (most recent call last):\n File "/tmp/ipykernel_60630/879165569.py", line 13, in func_exectutor\n out = func(*args, **kwargs)\n File "/tmp/ipykernel_60630/2959315277.py", line 22, in a\n raise Exception(msg) from e\nException: some unknown error occured\n'