How do I manipulate a variable whose name conflicts with PDB commands? - python

My code is, for better or worse, rife with single letter variables (it's physics stuff, so those letters are meaningful), as well as NumPy's, which I'm often interacting with.
When using the Python debugger, occasionally I'll want to look at the value of, say, n. However, when I hit n<enter>, that's the PDB command for (n)ext, which has a higher priority. print n works around looking at it, but how can I set it?

Use an exclamation mark ! before a statement to have it run :
python -m pdb test.py
> /home/user/test.py(1)<module>()
-> print('foo')
(Pdb) !n = 77
(Pdb) !n
77
(Pdb) n
foo
> /home/user/test.py(2)<module>()
-> print('bar')
(Pdb)
The docs say:
! statement
Execute the (one-line) statement in the context of the current stack frame. The exclamation point can be omitted unless the first word of the statement resembles a debugger command. [...]

You can use semicolons, so just put something else in front of it:
ipdb> print n
2
ipdb> n
> 145 <some code here>
146
147
ipdb> 1; n=4
1
ipdb> print n
4

That is not the direct answer to your question, but it may help you: PuDB is a console-based visual interface for PDB which separates commands from variable manipulation by design.

Use brackets (variable_name).
For example, if you have one variable named q, and you want to check out its value.
If you directly input q in the prompt, then the ipdb debugging process will quit and break up.
>>> q
Instead, you should input (q) to check this variable:
>>> (q)
Then its value will be printed.

Eric IDE, Wing IDE & Spyder to mention just a few all have visual debuggers that are worth a go as they separate the display of values from the commands.

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)

How can I debug manually typed expression and statements in pdb?

In pdb (or ipdb) we can execute statements and evaluate expressions with the ! or p commands:
p expression
Evaluate the expression in the current context and print its value.
[!]statement
Execute the (one-line) statement in the context of the current stack frame. The exclamation point can be omitted unless the first word of the statement resembles a debugger command. To set a global variable, you can prefix the assignment command with a global command on the same line
So, for example, I can type p reddit.get_subreddits() while debugging in ipdb and the code will be executed in the current context and I will see the return value.
Is there a way I can debug the execution of such "manually typed" expressions?
Basically I would like to do is s reddit.get_subreddits(), but that just executes the step command and ignores the expression.
EDIT: A trivial example
Take this simple function:
import random
def get_value_for_weekday(weekday_index=None):
values = [10, 20, 20, 10, 30, 30, 30]
if not weekday_index:
# If no weekday provided, return the average of all weekdays
return sum(values) / 7
return averages[weekday_index]
if __name__ == '__main__':
while True:
import ipdb; ipdb.set_trace() # enter ipbd for debug
get_value_for_weekday(random.randint(0, 7))
Which is bugged because of the if not weekday_index (it should check weekday_index is not None.)
Let's assume I notice I get 10 half the number of times I was expecting. So I added a import ipdb; ipdb.set_trace() before the call to the function to try and debug the code.
So I'm in the ipdb console and I suddenly get the idea that maybe the problem is when I pass 0 as weekday_index.
I can test my hypothesis directly in ipdb:
ipdb> p get_value_for_weekday(0)
22
Ok, so I realize there's something wrong when weekday_index=0.
What I would like to do now is debug step by step the call to get_value_for_weekday(0), so that I could see that I erranously enter the if block.
Obviously I could exit ipdb, stop the script, change the code to always pass 0, relaunch the script and when I enter ipdb, debug the call with the ipdb step (s) command.
But wouldn't it be easier if I could just do s get_value_for_weekday(0) much the same way I was able to do p get_value_for_weekday(0)?
Is there a way do something like this?
I think you're looking for the (d)ebug command which, for some reason, is not specified in the Debugger Commands. Just for future reference, pdb has a nice set of commands specified (which you can see by typing help in the interactive prompt). On to the debug command:
(Pdb) help debug
debug code
Enter a recursive debugger that steps through the code
argument (which is an arbitrary expression or statement to be
executed in the current environment).
Which seems to do what you're after. Using your sample script from the terminal:
python -m pdb pdbscript.py
After issuing two n commands in order for the function to get parsed (I believe this is how pdb works). You can issue a debug get_value_for_weekday(0) command to recursively step in the function:
(Pdb) debug get_value_for_weekday(0)
ENTERING RECURSIVE DEBUGGER
> <string>(1)<module>()
((Pdb)) s
--Call--
> /home/jim/Desktop/pdbscript.py(3)get_value_for_weekday()
-> def get_value_for_weekday(weekday_index=None):
((Pdb)) n
> /home/jim/Desktop/pdbscript.py(4)get_value_for_weekday()
-> values = [10, 20, 20, 10, 30, 30, 30]
((Pdb)) n
> /home/jim/Desktop/pdbscript.py(5)get_value_for_weekday()
-> if not weekday_index:
((Pdb)) p weekday_index
0
((Pdb)) n
> /home/jim/Desktop/pdbscript.py(7)get_value_for_weekday()
-> return sum(values) / 7
Do note, I feel really sketchy about this form of meta-debugging but it seems to be what you're after.
With regards to your example,
you don't need to exit pdb and change the code.
You can step into the function (with 's') and set weekday_index=0 inside.
One solution to your original problem is to use the debugger's jump command as follows:
jump before the function call using 'j #line-number'
step in the function with 's'
set the input params, and continue debugging.
This worked when I tried it, but the debugger complained when I tried to do step 3 before step 2 for some reason.

conditional breakpoint using pdb

Sounds like I'm missing something extremely simple, I'm trying to set a breakpoint in my python code using:
if(some condition):
pdb.set_trace()
My error in the code comes after a large number of iterations..difficult to debug using print etc.
I am able to print stuff when the condition hits but I would like to set brk-pt.
--EDIT--
Actual code:
import pdb
if (node_num == 16):
print node_num
pdb.set_trace()
I see you found your solution Sanjay. But for those who arrived here looking for a means to set a conditional breakpoint with pdb read on:
Instead of hard coding conditions such as if node_num == 16:, run pdb in interactive mode. Sample code:
import pdb
for node_num in range(50):
do_something(node_num)
...
In the shell start the script in debug mode using -m pdb:
[rick#rolled ~]$ python -m pdb abc.py
> /home/dcadm/abc.py(1)<module>()
-> import pdb
(Pdb) l
1 -> import pdb
2
3 for node_num in range(50) :
4 foo = 2**node_num
[EOF]
(Pdb) b 4, node_num > 4
Breakpoint 1 at /home/dcadm/abc.py:4
(Pdb) c
> /home/dcadm/abc.py(4)<module>()
-> foo = 2**node_num
(Pdb) node_num
5
(Pdb)
The pdb shell command b 4, node_num > 4 breaks at line 4 when node_num is greater than 4.
To actually use conditional breakpoints in pdb, you can do the following:
b(reak) [([filename:]lineno | function) [, condition]]
https://docs.python.org/3/library/pdb.html#pdbcommand-break
Eg I'm running some test code that iterates over django views. I want to break only when the particular view I'm interested in is reached:
b C:\Users\powlo\project\tests\TestCase.py:350, view.view_name
== 'app.views.export'
I am not sure as to why your code isn't working, but what you can do is on your local machine, create a new file for your minimum example to see if you can do what you want to do
import pdb
for node_num in range(50):
if node_num == 16:
print(node_num)
pdb.set_trace()
Now running it:
16
> /tmp/tmp.py(3)<module>()
-> for node_num in range(50):
(Pdb) p node_num
16
As you can see this worked as intended with this trivial example, it's up to you to figure out how to adapt this to your code, and/or figure out what else did you do to your code/environment that prevented that prompt from showing up.
Alternatively, if you have a function that is dying in an exception and you want to know the exact line that caused it, you should use post_mortem instead. Wrap the problematic section of code with this
try:
problem_function()
except Exception: # or the specific exception type thrown
pdb.post_mortem()
raise
What post_mortem would do is dump a break point right at the point where the exception happened (specifically in that stack frame), and so this allows all values to be inspected and then let you continue execution. However I also put a raise at the end to allow the exception to continue as normal, and this is intended as execution doesn't normally from where it die but just pause at that exception handling block due to the post_mortem call. Might as well just give up after inspecting what went wrong.

In pdb (python debugger), can I set a breakpoint on a builtin function?

I want to set a breakpoint on the set.update() function, but when I try, I get an error message.
Example:
ss= set()
ss.update('a')
Breakpoint:
b set.update
b ss.update
Errors:
The specified object 'ss.update' is not a function
or was not found along sys.path.
The specified object 'set.update' is not a function
or was not found along sys.path.
(Note, I also tried with the parentheses at the end, e.g., b set.update(), but still got the error. I didn't print all the permutations of errors.)
Thanks! Using #avasal's answer and Doug Hellmann's pdb webpage, I came up with this:
Since I was trying to catch set.update, I had to edit the sets.py file, but that wasn't enough, since python was using the builtin set class rather than the one I edited. So I overwrote the builtin sets class:
import sets
locals()['__builtins__'].set=sets.Set
Then I could set conditional break points in the debugger:
b set.update, iterable=='a' #successful
b set.update, iterable=='b' #won't stop for ss.update('a')
My entire example file looks like this:
import pdb
import sets
locals()['__builtins__'].set=sets.Set
pdb.set_trace()
ss = set()
ss.update('a')
print "goodbye cruel world"
Then at the debugger prompt, enter this:
b set.update, iterable=='a'
Hope this helps others too.

Can I put a breakpoint in a running Python program that drops to the interactive terminal?

I'm not sure if what I'm asking is possible at all, but since python is an interpreter it might be. I'm trying to make changes in an open-source project but because there are no types in python it's difficult to know what the variables have as data and what they do. You can't just look up the documentation on the var's type since you can't be sure what type it is. I want to drop to the terminal so I can quickly examine the types of the variables and what they do by typing help(var) or print(var). I could do this by changing the code and then re-running the program each time but that would be much slower.
Let's say I have a program:
def foo():
a = 5
my_debug_shell()
print a
foo()
my_debug_shell is the function I'm asking about. It would drop me to the '>>>' shell of the python interpreter where I can type help(a), and it would tell me that a is an integer. Then I type 'a=7', and some 'continue' command, and the program goes on to print 7, not 5, because I changed it.
http://docs.python.org/library/pdb.html
import pdb
pdb.set_trace()
Here is a solution that doesn't require code changes:
python -m pdb prog.py <prog_args>
(pdb) b 3
Breakpoint 1 at prog.py:3
(pdb) c
...
(pdb) p a
5
(pdb) a=7
(pdb) ...
In short:
start your program under debugger control
set a break point at a given line of code
let the program run up to that point
you get an interactive prompt that let's you do what you want (type 'help' for all options)
Python 3.7 has a new builtin way of setting breakpoints.
breakpoint()
The implementation of breakpoint() will import pdb and call pdb.set_trace().
Remember to include the braces (), since breakpoint is a function, not a keyword.
A one-line partial solution is simply to put 1/0 where you want the breakpoint: this will raise an exception, which will be caught by the debugger. Two advantages of this approach are:
Breakpoints set this way are robust against code modification (no dependence on a particular line number);
One does not need to import pdb in every program to be debugged; one can instead directly insert "breakpoints" where needed.
In order to catch the exception automatically, you can simply do python -m pdb prog.py… and then type c(ontinue) in order to start the program. When the 1/0 is reached, the program exits, but variables can be inspected as usual with the pdb debugger (p my_var). Now, this does not allow you to fix things and keep running the program. Instead you can try to fix the bug and run the program again.
If you want to use the powerful IPython shell, ipython -pdb prog.py… does the same thing, but leads to IPython's better debugger interface. Alternatively, you can do everything from within the IPython shell:
In IPython, set up the "debug on exception" mode of IPython (%pdb).
Run the program from IPython with %run prog.py…. When an exception occurs, the debugger is automatically activated and you can inspect variables, etc.
The advantage of this latter approach is that (1) the IPython shell is almost a must; and (2) once it is installed, debugging can easily be done through it (instead of directly through the pdb module). The full documentation is available on the IPython pages.
You can run the program using pdb, and add breakpoints before starting execution.
In reality though, it's usually just as fast to edit the code and put in the set_trace() call, as another user stated.
Not sure what the real question is. Python gives you the 'pdb' debugger (google yourself) and in addition you can add logging and debug output as needed.

Categories