path = a (Pdb) list 68 B def join(a, *p): 69 """Join two or more pathname components, inserting '/' as needed. 70 If any component is an absolute path, all previous path components 71 will be discarded. An empty last part will result in a path that 72 ends with a separator.""" 73 -> path = a 74 for b in p: 75 if b.startswith('/'): 76 path = b 77 elif path == '' or path.endswith('/'): 78 path += b (Pdb) !a '/Users' (Pdb) !p ('nathan',) 5/67
make_server('', 8000, pfcalc.rpn_app) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/lib/python2.7/wsgiref/simple_server.py", line 144, in make_server server = server_class((host, port), handler_class) File "/usr/lib/python2.7/SocketServer.py", line 419, in __init__ self.server_bind() File "/usr/lib/python2.7/wsgiref/simple_server.py", line 48, in server_bind HTTPServer.server_bind(self) File "/usr/lib/python2.7/SocketServer.py", line 430, in server_bind self.socket.bind(self.server_address) socket.error: [Errno 98] Address already in use >>> import pdb >>> pdb.pm() > /usr/lib/python2.7/socket.py(224)meth() -> return getattr(self._sock,name)(*args) (Pdb) 6/67
======================================== EOF bt cont enable jump pp run unt a c continue exit l q s until alias cl d h list quit step up args clear debug help n r tbreak w b commands disable ignore next restart u whatis break condition down j p return unalias where Miscellaneous help topics: ========================== exec pdb Undocumented commands: ====================== retval rv 15/67
Django app under PDB: If you want to set a low level breakpoint in your application, that's a good way to get the PDB console before anything happens. $ python -m pdb django runserver --settings=pdbdemo.settings 18/67
postfix notation calculator. You pass your arguments as path elements, and it applies them to the stack and returns the result. $ curl "http://localhost:8000/2/1/+" The answer is 3 $ curl "http://localhost:8000/2/10/*" The answer is 20 curl "http://localhost:8000/2/10/+/2/*" The answer is 24 21/67
input. $ curl http://localhost:8000/2/abc/+/ Traceback (most recent call last): ... File "pfcalc_wsgi.py", line 39, in handle handler.run(self.server.get_app()) File "pfcalc_wsgi.py", line 17, in run self.result = application(self.environ, self.start_response) File "pfcalc.py", line 46, in rpn_app c.push(element) File "pfcalc.py", line 28, in push value = int(value_or_operator) ValueError: invalid literal for int() with base 10: 'abc' 22/67
see what's actually happening when it blows up. python -m pdb pfcalc.py > pfcalc.py(1)<module>() -> from wsgiref.simple_server import make_server (Pdb) cont Serving on port 8000... $ curl http://localhost:8000/2/abc/+ 23/67
with curl, Python drops into PDB. $ curl http://localhost:8000/2/abc/+/ Traceback (most recent call last): ... File "pfcalc_wsgi.py", line 17, in run self.result = application(self.environ, self.start_response) File "pfcalc.py", line 46, in rpn_app c.push(element) File "pfcalc.py", line 28, in push value = int(value_or_operator) ValueError: invalid literal for int() with base 10: 'abc' Uncaught exception. Entering post mortem debugging Running 'cont' or 'step' will restart the program > pfcalc.py(28)push() -> value = int(value_or_operator) (Pdb) 24/67
You can also look at what arguments were passed to the current function using args. > pfcalc.py(28)push() -> value = int(value_or_operator) (Pdb) p value_or_operator 'abc' (Pdb) args self = <__main__.Calculator object at 0x1047bff10> value_or_operator = abc 25/67
variable using the pp command. (Pdb) p self.OPERATORS {'*': <slot wrapper '__mul__' of 'int' objects>, '+': <slot wrapper '__add__' of 'int' objects> (Pdb) pp self.OPERATORS {'*': <slot wrapper '__mul__' of 'int' objects>, '+': <slot wrapper '__add__' of 'int' objects>, '/': <slot wrapper '__div__' of 'int' objects>} 28/67
command. def add(a, b, c): import pdb; pdb.set_trace() return a + b + c > add.py(5)add() -> return a + b + c (Pdb) b+c *** The specified object '+c' is not a function or was not found along sys.path. (Pdb) !b+c 5 29/67
move one frame up the stack. PDB shows that the current position is now the call to result. (Pdb) up > pfcalc.py(54)rpn_app() -> "The answer is %d" % (c.result(),), 34/67
and trigger an error, the difference will be obvious. $ curl http://localhost:8000/2/3/+/5 $ python pf_settrace.py --Return-- > pf_settrace.py(15)<module>()->None -> pdb.set_trace() (Pdb) 41/67
a line number. Note that we then exit the debugger by telling it to continue. def rpn_app(environ, start_response): c = Calculator() for element in environ['PATH_INFO'][1:].split('/'): c.push(element) status = '200 OK' headers = [('Content-type', 'text/plain')] start_response(status, headers) return [ "The answer is %d" % (c.result(),), ] $ python -m pdb pfcalc.py > pfcalc.py(1)<module>() -> from wsgiref.simple_server import make_server (Pdb) break pfcalc.py:41 Breakpoint 1 at pfcalc.py:41 (Pdb) cont 44/67
we'll see it drop into PDB. $ curl http://localhost:8000/2/3/+ > pfcalc.py(43)rpn_app() -> c = Calculator() (Pdb) n > pfcalc.py(45)rpn_app() (Pdb) !environ['PATH_INFO'] '/2/3/+' 46/67
since we're running under the PDB module. The breakpoint is still active. (Pdb) break Num Type Disp Enb Where 1 breakpoint keep yes at pfcalc.py:41 breakpoint already hit 4 times 48/67
to control its behavior with the following commands: disable [bpnum] Disables the given breakpoint. The breakpoint remains set, but will not be triggered when the line is encountered. enable [bpnum] Enables the given breakpoint. ignore bpnum [count] Ignore a breakpoint for [count] hits. clear [bpnum] Clears the breakpoints specified. If no breakpoints are specified, prompt to clear all breakpoints. · · · · 49/67
from wsgiref.simple_server import make_server (Pdb) break pfcalc.rpn_app, environ['REQUEST_METHOD'] != 'GET' Breakpoint 1 at pfcalc.py:40 (Pdb) break Num Type Disp Enb Where 1 breakpoint keep yes at pfcalc.py:40 stop only if environ['REQUEST_METHOD'] != 'GET' (Pdb) cont Serving on port 8000... 52/67
is encountered These commands can be anything you normally enter at the (Pdb) prompt The command list ends with either the end command, or any command that resumes execution (step, next, cont) · · · 59/67
alias loc locals().keys() alias printdict for key, value in %1.items(): print "%s: %s" % (key, value) alias pd printdict .pdbrc will be loaded from your home directory and current directory Executed line by line in PDB Define aliases, common breakpoints, etc at startup Comments can be included with # · · · · 63/67
highlighting and tab completion rdb: PDB over a socket pudb: Full screen, console debugger pdb++: Overrides PDB with some advanced functionality like watches wdb: PDB over WebSockets pdbtrack is included with modern distributions of python-mode, and allows Emacs to open files as they're debugged by PDB. · · · · · · 65/67