gotcha / ipdb

Integration of IPython pdb
BSD 3-Clause "New" or "Revised" License
1.85k stars 146 forks source link

(i)pdb _runscript clobbers locals? #225

Closed jdtsmith closed 3 years ago

jdtsmith commented 3 years ago

In this issue on iPython I pointed out that (i)pdb (and pdb._runscript) alter locals, but do not restore them after quit, leading to key error and other issues after a pdb session has completed, while iPython continues.

I'm confused by this behavior. Can anyone comment on a recommended strategy for:

  1. Working in an ipython REPL for some time, setting many local variables, etc.
  2. Debugging a script in (i)pdb, perhaps setting some breakpoints along the way.
  3. Finding the bugs in the script, fixing them.
  4. Exiting (i)pdb back to the main ipython level (via quit or continue off the end of your script).
  5. Re-loading the script.
  6. Goto step 1.
jdtsmith commented 3 years ago

OK I now realize I may be confusing ipdb for iPython's debugger that also calls itself ipdb. But if anyone has any thoughts on such a workflow I'd appreciate.

MrMino commented 3 years ago

@jdtsmith You're not in the right place, but not for the reason you think.

This repo is a home of a package that is a wrapper around IPython.terminal.debugger.Pdb (which subclasses pdb.Pdb). This wrapper makes it possible to use the said class from console and an import, so that it resembles pdb more closely:

# from console:
ipdb /path/to/your/script.py

# from code:
import ipdb; ipdb.set_trace()

As I mentioned in ipython/ipython#12883, the method in question is not implemented in neither ipython/ipython nor gotcha/ipdb. It's inherited from the builtin: pdb.Pdb._runscript. IIUC, this method does what you consider unwanted behavior by design - to make sure other script's __main__ run properly, it necessitates clearing up __main__.__dict__.

May I know why would you want to run _runscript from a REPL?

jdtsmith commented 3 years ago

I'm coming from IDL (like Matlab). In such tools the REPL is long-lived, and you can move in and out of debugging scripts without invoking any special mode. I'm trying to recover some of that capability in iPython. I understand that (i)pdb alters locals to provide stack-based inspection; that's definitely as expected! But since quiting inside ipdb> mode from within iPython leaves the iPython REPL running, it seems reasonable that the debugger would "clean up after itself" and leave the original locals it altered intact. Sadly pdb does not do so on its own (at least not that I've found).

I came across _runscript because that's what elpy-shell uses to run scripts; it suffers this complete loss of base locals as a result (even _oh is missing, leading to KeyError after most commands, and an unusable iPython REPL).

I've found that invoking the iPython debugger using %run -d cleans up after itself and restores locals as they were at the main iPython level, which is great.

Thanks.

MrMino commented 3 years ago

BTW. while %run -d takes a path to a runnable script, there's also %debug which takes an expression to eval & debug.