I'm debugging a function that I wrote as part of some form of plug-in framework. The function does not appear to be doing what it should, and I have the suspicion that, somewhere up the stack, someone is catching exceptions, or raise (either a very specific or a very generic) exception and test what happens (but if it's swallowed, it still doesn't tell me where). I could enter the debugger and inspect the source code at every stack level. Is there a more direct way to list any try-except blocks that the current code may be part of — specifically, the try-part of any such block?
This is, of course, exclusively for debugging purposes.
A try and except block is used for error handling in Python. Try : Helps to test the code. If the code inside the try block is error free it is executed. Otherwise the error gets caught and control goes to the except block.
When an exception occurs inside a try block, control goes directly to the catch block, so no other code will be executed inside the try block and the value of res will not change. Also when a method throws an exception it does not return anything.
Catching Exceptions in Python In Python, exceptions can be handled using a try statement. The critical operation which can raise an exception is placed inside the try clause. The code that handles the exceptions is written in the except clause.
When a catch -block is used, the catch -block is executed when any exception is thrown from within the try -block. For example, when the exception occurs in the following code, control transfers to the catch -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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With