How do I check if current code is part of a try-except-block?
It's spectacularly possible I'm missing something here (I just eyeballed the dis.dis()
output for the catcher
function), but at least this catches simple cases of catching things on Python 3.7:
import sys
import dis
def are_we_being_caught():
frame = sys._getframe(1)
while frame:
bytecode = dis.Bytecode(frame.f_code)
except_stack = 0
for instr in bytecode:
if instr.opname == "SETUP_EXCEPT": # Going into a try: except: block
except_stack += 1
elif instr.opname == "POP_EXCEPT": # Exiting a try: except: block
except_stack -= 1
if instr.offset > frame.f_lasti: # Past the current instruction, bail out
break
if except_stack: # If we `break`ed in the middle of a SETUP/POP pair
print(frame, "may be catching exceptions now")
frame = frame.f_back
def catcher(fn):
try:
x = fn()
except:
x = None # YOLO :D
return x
def f1():
return 8
def f2():
are_we_being_caught()
raise ValueError("foo")
print(catcher(f1))
print(catcher(f2))
outputs
8
<frame at 0x109d2d238, file 'so55729254.py', line 24, code catcher> may be catching exceptions now
None
That's a pretty difficult one: internally, each frame maintains a stack of blocks but I don't think there's any API to access it (let alone from Python). So you'd have to walk the stackframes, disassemble the code to infer the span of your try blocks (see the SETUP_EXCEPT
and SETUP_FINALLY
opcodes), and see if the "current line" of the stack frame falls within that block.