Debugging Pyramid¶
This tutorial provides a brief introduction to using the python
debugger (pdb
) for debugging pyramid applications.
This scenario assume you've created a Pyramid project already. The scenario
assumes you've created a Pyramid project named buggy
using the
alchemy
scaffold.
Introducing PDB¶
This single line of python is your new friend:
import pdb; pdb.set_trace()
As valid python, that can be inserted practically anywhere in a Python source file. When the python interpreter hits it - execution will be suspended providing you with interactive control from the parent TTY.
PDB Commands¶
pdb exposes a number of standard interactive debugging commands, including:
1Documented commands (type help <topic>): 2======================================== 3EOF bt cont enable jump pp run unt 4a c continue exit l q s until 5alias cl d h list quit step up 6args clear debug help n r tbreak w 7b commands disable ignore next restart u whatis 8break condition down j p return unalias where 9 10Miscellaneous help topics: 11========================== 12exec pdb 13 14Undocumented commands: 15====================== 16retval rv
Debugging Our buggy
App¶
Back to our demo
buggy
application we generated from thealchemy
scaffold, lets see if we can learn anything debugging it.The traversal documentation describes how pyramid first acquires a root object, and then descends the resource tree using the
__getitem__
for each respective resource.
Huh?¶
Let's drop a pdb statement into our root factory object's
__getitem__
method and have a look. Edit the project'smodels.py
and add the aforementionedpdb
line inMyModel.__getitem__
:def __getitem__(self, key): import pdb; pdb.set_trace() session = DBSession() # ...
Restart the Pyramid application, and request a page. Note the request requires a path to hit our break-point:
http://localhost:6543/ <- misses the break-point, no traversal http://localhost:6543/1 <- should find an object http://localhost:6543/2 <- does not
For a very simple case, attempt to insert a missing key by default. Set item to a valid new MyModel in
MyRoot.__getitem__
if a match isn't found in the database:item = session.query(MyModel).get(id) if item is None: item = MyModel(name='test %d'%id, value=str(id)) # naive insertion
Move the break-point within the if clause to avoid the false positive hits:
if item is None: import pdb; pdb.set_trace() item = MyModel(name='test %d'%id, value=str(id)) # naive insertion
Run again, note multiple request to the same id continue to create new MyModel instances. That's not right!
Ah, of course, we forgot to add the new item to the session. Another line added to our
__getitem__
method:if item is None: import pdb; pdb.set_trace() item = MyModel(name='test %d'%id, value=str(id)) session.add(item)
Restart and test. Observe the stack; debug again. Examine the item returning from MyModel:
(pdb) session.query(MyModel).get(id)
Finally, we realize the item.id needs to be set as well before adding:
if item is None: item = MyModel(name='test %d'%id, value=str(id)) item.id = id session.add(item)
Many great resources can be found describing the details of using pdb. Try the interactive
help
(hit 'h') or a search engine near you.
注釈
There is a well known bug in PDB
in UNIX, when user cannot
see what he is typing in terminal window after any interruption during
PDB
session (it can be caused by CTRL-C
or when the server restarts
automatically). This can be fixed by launching any of this commands in broken
terminal: reset
, stty sane
. Also one can add one of this commands into
~/.pdbrc
file, so they will be launched before PDB
session:
from subprocess import Popen
Popen(["stty", "sane"])