Save breakpoints to file - python

When debugging my Python code, I run a script through ipdb from the commandline, and set a number of breakpoints. Then I make some changes in one or more modules, and rerun. However, if I simply use run modules do not get reloaded. To make sure they do, I can exist and restart Python completely, but then I need to reset all breakpoints, which is tedious if I have many and if done over and over again.
Is there a way to save breakpoint to a file in (i)pdb, so that after small changes that do not change line numbers, I can dump my breakpoints, restart Python + pdb, and reload my breakpoints? The equivalent to Matlabs X = dbstatus, saving/loading X, and setting dbstop(X).

You can save the breakpoints to .pdbrc file in a working path or globally to your home dir. File should have something like this:
# breakpoint 1
break /path/to/file:lineno
# breakpoint 2
break /path/to/file:lineno
You can define breakpoints various ways, just like in the interactive mode. So just break 4 or break method will work too.
This file works for both, pdb and ipdb, since later has everything pdb has and more.
Bonus:
You could use alias to more easily save breakpoints.
For example:
# append breakpoint to .pdbrc in current working directory
# usage: bs lineno
alias bs with open(".pdbrc", "a") as pdbrc: pdbrc.write("break " + __file__ + ":%1\n")
Put above to your global .pdbrc and use it like this:
> bs 15
This will append a breakpoint statement to a local .pdbrc file for a line 15 of current file.
It is not perfect solution, but close enough for me. Tune the command to your needs.
Read more about aliases here.

Related

how to disable pdb.set_trace() without stopping python program and edit the code

I suspect that I have issue in one of my loops, so I setup a break points with pdb.set_trace()
import pdb
for i in range(100):
print("a")
pdb.set_trace()
print("b")
after check variable in this loop for a few times, I decide continue this programming without further breaks. So I try to get the break number with b command, no breaks listed. I guess this line of code don't setup a break point. but How Do I get ride of this "break points" without stopping the program and change the code?
to my knowledge, you could not bypass set_trace, but you could neutralize it, once debugger stopped, type:
pdb.set_trace = lambda: 1
then continue, it wont break again.
Setting a breakpoint (requires Python 3.7):
breakpoint()
Disabling breakpoints set with the breakpoint() function:
import os
os.environ["PYTHONBREAKPOINT"] = "0"
Long story:
In the 3.7 version of Python, the breakpoint() built-in function for setting breakpoints was introduced. By default, it will call pdb.set_trace(). Also, since the 3.7 version of Python the PYTHONBREAKPOINT environment variable is available. It is considered when the breakpoint() function is used.
So, in order to disable these breakpoints (set with the breakpoint() function), one can just set the PYTHONBREAKPOINT environment variable like this:
import os
os.environ["PYTHONBREAKPOINT"] = "0"
It may be useful to mention here sys.breakpointhook() which was also added in the 3.7 version of Python and allows to customize breakpoints behavior.
Unfortunately pdb is missing a bunch of functionality (even basic stuff like display lists), and you've found another example of that here. The good news is that pdb++ is a great drop-in replacement for pdb, and one of the things it solves is exactly the problem of disabling set_trace. So you can simply do:
pip install pdbpp
and then at the (Pdb++) prompt, type
pdb.disable()
Easy! And you will get lots of other useful goodies on top of that.
It is possible to start a Python script without PDB control but then hit a stray set_trace() left there. To prevent breaking into debugger every time set_trace() is encountered, a similar trick as above (changing the symbol's reference to point to a harmless function) can be applied.
However, the namespace of the debuggee has to be modified, not one of the debugger itself. Simply overwriting pdb.set_trace = lambda:1 or set_trace = lambda:1 did not work for me.
The following trick worked from the pdb prompt:
pdb> globals()['set_trace'] = lambda:1
This line first calls globals() to get access to a dict of the program under debugging, and then modifies the reference of set_trace there.
One way around this is to not write the breakpoints in the script itself, but rather set breakpoints when you start python with python -m pdb my_script.py
You then get into a prompt first, before execution of the script starts, and you can write for example
(Pdb) b 321
to set a breakpoint on line 321 (you can also specify file and specify conditions b 321, i == 50)
Then
(Pdb) c
(for continue) to start the execution of the actual script. The breakpoints you set in this way, you can clear when you're done with them with:
(Pdb) cl
(for clear)

Python configuration of interactive shell

I'm trying to find out how to configure the "python interactive shell" on linux (i.e. the program executed when typing python in terminal). I'm looking forward to configure stuff such as coloring ps[12], tab completion (?), etc.
I'm aware of ipython/jupyter, bpython, etc. but I don't want fancy (unnecessary?) stuff but only some colored terminal :)
Is it possible to have a kind of config file?
There is an environment variable you can set, PYTHONSTARTUP:
If this is the name of a readable file, the Python commands in that file are executed before the first prompt is displayed in interactive mode. The file is executed in the same namespace where interactive commands are executed so that objects defined or imported in it can be used without qualification in the interactive session. You can also change the prompts sys.ps1 and sys.ps2 and the hook sys.__interactivehook__ in this file.
To set the environment variable, go to your terminal and type:
$ export PYTHONSTARTUP=/path/to/my/python/file.py
($ is the prompt, not something you should type.)
Since that won't last beyond the current session, you probably want to put it in your .bashrc file.
In your /path/to/my/file.py you can do whatever Python stuff you want. For example, you might want to have the primary and secondary prompts to be green:
import sys
color = "\x1b[32m{}\x1b[m"
sys.ps1 = color.format(sys.ps1)
sys.ps2 = color.format(sys.ps2)
# We don't want variables to be around in our interactive sessions.
del color
del sys
You can do whatever you want in there. In mine, I set a history file that is written to atexit. That way, Up can go beyond the current session. I also added tab completion.

ipython run without destroying global variables defined in the target file

I want to define some globals in some number crunching work I am doing, I am incrementally writing the script and don't want previous result to keep being loaded/recalculated. One approach is to split out mature code into a separate file and only python run interactively new code. However I just want to do it in a single file for speed of development.
I was under the assumption that a global defined in a file would persist between invocations of run, but they do not.
So my script has the following chunk if code :
if globals().has_key('all_post_freq') != True:
print "creating all post freq var"
global all_post_freq
all_post_freq = all_post_freq_("pickle/all_post_freq.pickle")
How do I retain all_post_freq between invocations of ipython run
edit
ok I have split stuff up into files, but I know there must be a way of doing what I need to do :D
When you %run a file, it is normally started in a blank namespace, and its globals are added to the interactive namespace when it finishes. There's a -i flag which will run it directly in the interactive namespace, so it will see variables you've already defined:
%run -i myscript.py

Running a python debug session from a program, not from the console

I'm writing a little python IDE, and I want to add simple debugging. I don't need all the features of winpdb.
How do I launch a python program (by file name) with a breakpoint set at a line number so that it runs until that line number and halts?
Note that I don't want to do this from the command-line, and I don't want to edit the source (by inserting set_trace, for example). And I don't want it to stop at the first line so I have to run the debugger from there. I've tried all the obvious ways with pdb and bdb, but I must be missing something.
Pretty much the only viable way to do it (as far as I know) is to run Python as a subprocess from within your IDE. This avoids "pollution" from the current Python interpreter, which makes it fairly likely that the program will run in the same way as if you had started it independently. (If you have issues with this, check the subprocess environment.) In this manner, you can run a script in "debug mode" using
p = subprocess.Popen(args=[sys.executable, '-m', 'pdb', 'scriptname.py', 'arg1'],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
This will start up Python at the debugger prompt. You'll need to run some debugger commands to set breakpoints, which you can do like so:
o,e = p.communicate('break scriptname.py:lineno')
If this works, o should be the normal output of the Python interpreter after it sets a breakpoint, and e should be empty. I'd suggest you play around with this and add some checks in your code to ensure whether the breakpoints were properly set.
After that, you can start the program running with
p.communicate('continue')
At this point you'd probably want to hook the input, output, and error streams up to the console that you're embedding in your IDE. You would probably need to do this with an event loop, roughly like so:
while p.returncode is None:
o,e = p.communicate(console.read())
console.write(o)
console.write(e)
You should consider that snippet to be effectively pseudocode, since depending on how exactly your console works, it'll probably take some tinkering to get it right.
If this seems excessively messy, you can probably simplify the process a bit using the features of Python's pdb and bdb modules (I'm guessing "Python debugger" and basic debugger" respectively). The best reference on how to do this is the source code of the pdb module itself. Basically, the way the responsibilities of the modules are split is that bdb handles "under the hood" debugger functionality, like setting breakpoints, or stopping and restarting execution; pdb is a wrapper around this that handles user interaction, i.e. reading commands and displaying output.
For your IDE-integrated debugger, it would make sense to adjust the behavior of the pdb module in two ways that I can think of:
have it automatically set breakpoints during initialization, without you having to explicity send the textual commands to do so
make it take input from and send output to your IDE's console
Just these two changes should be easy to implement by subclassing pdb.Pdb. You can create a subclass whose initializer takes a list of breakpoints as an additional argument:
class MyPDB(pdb.Pdb):
def __init__(self, breakpoints, completekey='tab',
stdin=None, stdout=None, skip=None):
pdb.Pdb.__init__(self, completekey, stdin, stdout, skip)
self._breakpoints = breakpoints
The logical place to actually set up the breakpoints is just after the debugger reads its .pdbrc file, which occurs in the pdb.Pdb.setup method. To perform the actual setup, use the set_break method inherited from bdb.Bdb:
def setInitialBreakpoints(self):
_breakpoints = self._breakpoints
self._breakpoints = None # to avoid setting breaks twice
for bp in _breakpoints:
self.set_break(filename=bp.filename, line=bp.line,
temporary=bp.temporary, conditional=bp.conditional,
funcname=bp.funcname)
def setup(self, f, t):
pdb.Pdb.setup(self, f, t)
self.setInitialBreakpoints()
This piece of code would work for each breakpoint being passed as e.g. a named tuple. You could also experiment with just constructing bdb.Breakpoint instances directly, but I'm not sure if that would work properly, since bdb.Bdb maintains its own information about breakpoints.
Next, you'll need to create a new main method for your module which runs it the same way pdb runs. To some extent, you can copy the main method from pdb (and the if __name__ == '__main__' statement of course), but you'll need to augment it with some way to pass in the information about your additional breakpoints. What I'd suggest is writing the breakpoints to a temporary file from your IDE, and passing the name of that file as a second argument:
tmpfilename = ...
# write breakpoint info
p = subprocess.Popen(args=[sys.executable, '-m', 'mypdb', tmpfilename, ...], ...)
# delete the temporary file
Then in mypdb.main(), you would add something like this:
def main():
# code excerpted from pdb.main()
...
del sys.argv[0]
# add this
bpfilename = sys.argv[0]
with open(bpfilename) as f:
# read breakpoint info
breakpoints = ...
del sys.argv[0]
# back to excerpt from pdb.main()
sys.path[0] = os.path.dirname(mainpyfile)
pdb = Pdb(breakpoints) # modified
Now you can use your new debugger module just like you would use pdb, except that you don't have to explicitly send break commands before the process starts. This has the advantage that you can directly hook the standard input and output of the Python subprocess to your console, if it allows you to do that.

Jump into a Python Interactive Session mid-program?

Hey I was wondering... I am using the pydev with eclipse and I'm really enjoying the powerful debugging features, but I was wondering:
Is it possible to set a breakpoint in eclipse and jump into the interactive python interpreter during execution?
I think that would be pretty handy ;)
edit: I want to emphasize that my goal is not to jump into a debugger. pydev/eclipse have a great debugger, and I can just look at the traceback and set break points.
What I want is to execute a script and jump into an interactive python interpreter during execution so I can do things like...
poke around
check the values of things
manipulate variables
figure out some code before I add it to the app
I know you can do this all with a debugger, but I can do it faster in the interactive interpreter because I can try something, see that it didn't work, and try something else without having get the app back to the point of executing that code again.
So roughly a year on from the OP's question, PyDev has this capability built in. I am not sure when this feature was introduced, but all I know is I've spent the last ~2hrs Googling... configuring iPython and whatever (which was looking like it would have done the job), but only to realise Eclipse/PyDev has what I want ootb.
As soon as you hit a breakpoint in debug mode, the console is right there ready and waiting!
I only didn't notice this as there is no prompt or blinking cursor; I had wrongly assumed it was a standard, output-only, console... but it's not. It even has code-completion.
Great stuff, see http://pydev.org/manual_adv_debug_console.html for more details.
This is from an old project, and I didn't write it, but it does something similar to what you want using ipython.
'''Start an IPython shell (for debugging) with current environment.
Runs Call db() to start a shell, e.g.
def foo(bar):
for x in bar:
if baz(x):
import ipydb; ipydb.db() # <-- start IPython here, with current value of x (ipydb is the name of this module).
.
'''
import inspect,IPython
def db():
'''Start IPython shell with callers environment.'''
# find callers
__up_frame = inspect.currentframe().f_back
eval('IPython.Shell.IPShellEmbed([])()', # Empty list arg is
# ipythons argv later args to dict take precedence, so
# f_globals() shadows globals(). Need globals() for IPython
# module.
dict(globals().items() + __up_frame.f_globals.items()),
__up_frame.f_locals)
edit by Jim Robert (question owner): If you place the above code into a file called my_debug.py for the sake of this example. Then place that file in your python path, and you can insert the following lines anywhere in your code to jump into a debugger (as long as you execute from a shell):
import my_debug
my_debug.db()
I've long been using this code in my sitecustomize.py to start a debugger on an exception. This can also be triggered by Ctrl+C. It works beautifully in the shell, don't know about eclipse.
import sys
def info(exception_type, value, tb):
if hasattr(sys, 'ps1') or not sys.stderr.isatty() or not sys.stdin.isatty() or not sys.stdout.isatty() or type==SyntaxError:
# we are in interactive mode or we don't have a tty-like
# device, so we call the default hook
sys.__excepthook__(exception_type, value, tb)
else:
import traceback
import pdb
if exception_type != KeyboardInterrupt:
try:
import growlnotify
growlnotify.growlNotify("Script crashed", sticky = False)
except ImportError:
pass
# we are NOT in interactive mode, print the exception...
traceback.print_exception(exception_type, value, tb)
print
# ...then start the debugger in post-mortem mode.
pdb.pm()
sys.excepthook = info
Here's the source and more discussion on StackOverflow.
You can jump into an interactive session using code.InteractiveConsole as described here; however I don't know how to trigger this from Eclipse.
A solution might be to intercept Ctrl+C to jump into this interactive console (using the signal module: signal.signal(signal.SIGINT, my_handler)), but it would probably change the execution context and you probably don't want this.
If you are already running in debug mode you can set an additional breakpoint if the program execution is currently paused (e.g. because you are already at a breakpoint). I just tried it out now with the latest Pydev - it works just fine.
If you are running normally (i.e. not in debug mode) all breakpoints will be ignored. No changes to breakpoints will alter the way a non-debug run works.

Categories