I like testing functions in the Python interpreter. Is it possible to debug a function in the Python interpreter when I want to see more than a return value and a side effect?
If so, could you show basic debugger operations (launching the function with arguments, setting breakpoint, next step, step into, watching variable)? If not, how would you debug a function another way?
The point is, I want to debug only a particular function which will be supplied with arguments. I don't want to debug whole module code.
thank you for advice
If you want to debug specific function you can using this -
>>> import pdb
>>> import yourmodule
>>> pdb.run('yourmodule.foo()')
over the command line. pdb.set_trace() should be added in your function to break there.
More info on pdb can be seen here - http://docs.python.org/library/pdb.html
See pdb module. Insert into code:
import pdb
pdb.set_trace()
... makes a breakpoint.
The code-to-debug does not need to be modified to include pdb.set_trace(). That call can be made directly in the interpreter just before the code-to-debug:
>>> import pdb
>>> pdb.set_trace(); <code-to-debug>
For example, given test_script.py with the following code:
def some_func(text):
print 'Given text is {}'.format(repr(text))
for index,char in enumerate(text):
print ' '*index, char
an interpreter session to debug some_func using the debugger commands step-into (s), next (n) and continue (c) would look like:
>>> import pdb
>>> import test_script
>>> pdb.set_trace(); test_script.some_func('hello')
--Call--
> c:\src\test_script.py(1)some_func()
-> def some_func(text):
(Pdb) s
> c:\src\test_script.py(2)some_func()
-> print 'Given text is {}'.format(repr(text))
(Pdb) n
Given text is 'hello'
> c:\src\test_script.py(3)some_func()
-> for index,char in enumerate(text):
(Pdb) c
h
e
l
l
o
>>>
See the docs for the pdb module for more information on how to use the debugger: http://docs.python.org/library/pdb.html
Additionally, while using the debugger, the help command provides a nice list of commands and help <command> gives help specific to the given command.
Related
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.
I'm used to GDB, where b does that.
But in pdb, b just list breakpoints.
I can do b 123, but lazy to type 123.
Maybe a magic argument like b .?
I know PyCharm and __import__('pdb').set_trace(), just checking if there is an usable CLI alternative for those quick debugs.
if you accept adding a new pdb command, it is trivial:
def do_breakcurrent(self, arg):
cur_lineno = str(self.curframe.f_lineno)
return self.do_break(cur_lineno)
import pdb
pdb.Pdb.do_breakcurrent = pdb.Pdb.do_bc = do_breakcurrent
use breakcurrent or bc:
(Pdb) bc
Breakpoint 1 at /Users/georgexsh/workspace/so/52110534.py:11
if you want to put those code into .pdbrc to make it available automatically, need little tweak:
import pdb
pdb.Pdb.do_bc = lambda self,arg: self.do_break(str(self.curframe.f_lineno))
Why can't I define new functions when I run pdb?
For example take myscript.py:
#!/gpfs0/export/opt/anaconda-2.3.0/bin/python
print "Hello World"
print "I see you"
If I run python -m pdb myscript.py and try to interactively define a new function:
def foo():
I get the error:
*** SyntaxError: unexpected EOF while parsing (<stdin>, line 1)
Why is this?
I don't think it supports multi-line input. You can workaround by spawning up an interactive session from within pdb. Once you are done in the interactive session, exit it with Ctrl+D.
>>> import pdb
>>> pdb.set_trace()
(Pdb) !import code; code.interact(local=vars())
(InteractiveConsole)
In : def foo():
...: print('hello in pdb')
...:
In : # use ctrl+d here to return to pdb shell...
(Pdb) foo()
hello in pdb
You can define your function in a one line statement using ; instead of indentation, like this:
(Pdb) def foo(): print 'Hello world'; print 'I see you'
(Pdb) foo()
Hello world
I see you
i was able to import python modules from the pdb command line.
if you can import python modules, then you should be able to define your functions in a file and just do an import of the file.
If your application happens to have IPython as a dependency, you could drop yourself into a feature-rich IPython REPL right from ipdb:
import IPython; IPython.embed()
From inside, if you run IPython's magic command whos, you should see all the locally defined variables in the current pdb frame.
Say I have an IPython session, from which I call some script:
> run my_script.py
Is there a way to induce a breakpoint in my_script.py from which I can inspect my workspace from IPython?
I remember reading that in previous versions of IPython one could do:
from IPython.Debugger import Tracer;
def my_function():
x = 5
Tracer()
print 5;
but the submodule Debugger does not seem to be available anymore.
Assuming that I have an IPython session open already: how can I stop my program a location of my choice and inspect my workspace with IPython?
In general, I would prefer solutions that do not require me to pre-specify line numbers, since I would like to possibly have more than one such call to Tracer() above and not have to keep track of the line numbers where they are.
The Tracer() still exists in ipython in a different module. You can do the following:
from IPython.core.debugger import Tracer
def my_function():
x = 5
Tracer()()
print 5
Note the additional call parentheses around Tracer
edit: For IPython 6 onwards Tracer is deprecated so you should use set_trace() instead:
from IPython.core.debugger import set_trace
def my_function():
x = 5
set_trace()
print 5
You can run it and set a breakpoint at a given line with:
run -d -b12 myscript
Where -b12 sets a breakpoint at line 12. When you enter this line, you'll immediately drop into pdb, and you'll need to enter c to execute up to that breakpoint.
This is the version using the set_trace() method instead of the deprecated Tracer() one.
from IPython.core.debugger import Pdb
def my_function():
x = 5
Pdb().set_trace()
print 5
Inside the IPython shell, you can do
from IPython.core.debugger import Pdb
pdb = Pdb()
pdb.runcall(my_function)
for example, or do the normal pdb.set_trace() inside your function.
With Python 3 (v3.7+), there's the new breakpoint() function. You can modify it's behaviour so it'll call ipython's debugger for you.
Basically you can set an environment variable that points to a debugger function. (If you don't set the variable, breakpoint() defaults to calling pdb.)
To set breakpoint() to call ipython's debugger, set the environment variable (in your shell) like so:
# for bash/zsh users
export PYTHONBREAKPOINT='IPython.core.debugger.set_trace'
# powershell users
$env:PYTHONBREAKPOINT='IPython.core.debugger.set_trace'
(Note, obviously if you want to permanently set the environment variable, you'll need to modify your shell profile or system preferences.)
You can write:
def my_function():
x = 5
breakpoint()
print(5)
And it'll break into ipython's debugger for you. I think it's handier than having to import from IPython.core.debugger import set_trace and call set_trace().
I have always had the same question and the best workaround I have found which is pretty hackey is to add a line that will break my code, like so:
...
a = 1+2
STOP
...
Then when I run that code it will break, and I can do %debug to go there and inspect. You can also turn on %pdb to always go to point where your code breaks but this can be bothersome if you don't want to inspect everywhere and everytime your code breaks. I would love a more elegant solution.
I see a lot of options here, but maybe not the following simple option.
Fire up ipython in the directory where my_script.py is.
Turn the debugger on if you want the code to go into debug mode when it fails. Type %pdb.
In [1]: %pdb
Automatic pdb calling has been turned ON
Next type
In [2]: %run -d ./my_script.py
*** Blank or comment
*** Blank or comment
NOTE: Enter 'c' at the ipdb> prompt to continue execution.
> c:\users\c81196\lgd\mortgages-1\nmb\lgd\run_lgd.py(2)<module>()
1 # system imports
----> 2 from os.path import join
Now you can set a breakpoint where ever you want it.
Type b 100 to have a breakpoint at line 100, or b whatever.py:102 to have a breakpoint at line 102 in whatever.py.
For instance:
ipdb> b 100
Then continue to run, or continue.
ipdb> c
Once the code fails, or reaches the breakpoint you can start using the full power of the python debugger pdb.
Note that pdb also allows the setting of a breakpoint at a function.
b(reak) [([filename:]lineno | function) [, condition]]
So you do not necessarily need to use line numbers.
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.