This nice little Python decorator can configurably disabled decorated functions:
enabled = get_bool_from_config()
def run_if_enabled(fn):
def wrapped(*args, **kwargs):
try:
return fn(*args, **kwargs) if enabled else None
except Exception:
log.exception('')
return None
return wrapped
alas, if an exception is raised within fn() the traceback shows only up to the wrapper:
Traceback (most recent call last):
File "C:\my_proj\run.py", line 46, in wrapped
return fn(*args, **kwargs) if enabled else None
File "C:\my_proj\run.py", line 490, in a_decorated_function
some_dict['some_value']
KeyError: 'some_value'
- Why?
- Can I workaround to see the full traceback?
Ah! Ok, now this is an interesting question!
Here is is the same approximate function, but grabbing the exception directly from
sys.exc_info():And it’s true: no higher stack frames are included in the traceback that’s printed:
$ python test.py The exception: Traceback (most recent call last): File "x.py", line 21, in wrapped return fn(*args, **kwargs) if enabled else None File "x.py", line 29, in stuff raise Exception("stuff") Exception: stuffNow, to narrow this down a bit, I suspect it’s happening because the stack frame only includes stack information up until the most recent
try/exceptblock… So we should be able to recreate this without the decorator:Ah ha! Now, on reflection, this does make sense in a certain kind of way: at this point, the exception has only encountered two stack frames: that of
inner()and that ofouter()— the exception doesn’t yet know from whenceouter()was called.So, to get the complete stack, you’ll need to combine the current stack with the exception’s stack:
See also: