3

I'm trying to make a debugger function, which is called when an error is raised, and let me access a console so I can check what happened in my program. Here is the basic function:

def DEBUGGER(error):
    print(error)
    print("[DEBUGGER] Your program has failed, here is the debugger. Enter EXIT to end program.")
    while True:
        line = input(">>> ").lower()
        if line == 'exit':
            sys.exit(0)
        else:
            try:
                exec(line)
            except Exception as e:
                print(str(e))

The problem is that I can't enter something like print(var) because it's referenced in another function. Globals functions don't help me since I want to be able to call any variable in my program, and I can't globalize them all.. I know I can resolve it by putting all my functions in classes but I can't for many reasons.

Is there a way to get local variables of the running functions ? (When I call DEBUGGER(), the mother function is still running)

If no, can I export the local variables of the current function and pass it as an argument to DEBUGGER() ?

Thanks for your answers.

3
  • 1
    How about locals()? Commented Jul 30, 2018 at 12:12
  • 2
    Also, python has an entire pdb module for exactly this sort of debugging. Any special reason you don't want to use it? Commented Jul 30, 2018 at 12:13
  • 2
    You could probably do this using something in the traceback module, but why? There is already a debugger built into Python, pdb. Commented Jul 30, 2018 at 12:13

2 Answers 2

5

You are basically re-implementing the Python debugger pdb. If you want to go this route, you probably want to study the source code. pdb itself is a user-interface around the lower-level bdb (basic debugger) module, and the source code for that is also available.

To answer your direct question: when you catch an exception you have access to a traceback object (either via exception.__traceback__ or via sys.exc_info()), and tracebacks have access to both the local and global namespace of each frame in the stack, via the tb_frame attribute. That attribute is set to a frame object, which has f_locals and f_globals attributes.

The bdb.Bdb.get_stack() method could be an interesting example on how to treat a traceback, and the internal pdb.Pdb._select_frame() method then is used to pick a frame from the stack to use the locals and globals from.

If you don't want to re-implement the full debugger, you can use the pdb.pm() or pdb.port_mortem() functions. These take the last traceback raised and let you inspect the stack frame in an interactive environment:

try:
    exec(line)
except Exception as e:
    pdb.post_mortem(e.__traceback__)
Sign up to request clarification or add additional context in comments.

Comments

0

The correct way to "write" your "DEBUGGER" function is:

import pdb
DEBUGGER = pdb.set_trace

Now you can call DEBUGGER() wherever you want, you will be in an interactive environment with access not only to local vars but also to whole call stack, and the ability to execute the remaining code step by step (including stepping into other functions etc), change the control flow to continue executing from another line etc etc etc.

Oh and yes: you can of course just write import pdb; pdb.set_trace() instead ;-)

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.