ASPN ActiveState Programmer Network  
ActiveState, a division of Sophos
/ Home / Perl / PHP / Python / Tcl / XSLT /
/ Safari / My ASPN /
Cookbooks | Documentation | Mailing Lists | Modules | News Feeds | Products | User Groups
Submit Recipe
My Recipes

All Recipes
All Cookbooks


View by Category

Title: sane tab completion in pdb
Submitter: Stephen Emslie (other recipes)
Last Updated: 2007/12/16
Version no: 1.4
Category: Debugging

 

5 stars 2 vote(s)


Description:

I make frequent use of python's built-in debugger, but one obvious feature seems to be missing - the bash-like tab completion that you can add to the interpreter. Fortunately pdb's interactive prompt is an instance of Cmd, so we can write our own completion function.

Note: this uses rlcompleter, which isn't available on windows

Edit: updated to handle changes in local scope
Edit: Fixed start via 'python -m pdb ...'. Check the comments for details.

Source: Text Source

# save this in .pdbrc in your home directory
import os
import sys
execfile(os.path.expanduser("~/.pdbrc.py"))
sys._getframe().f_back.f_globals['Pdb'].complete = complete

# save this in .pdbrc.py in your home directory
def complete(self, text, state):
    """return the next possible completion for text, using the current frame's local namespace

       This is called successively with state == 0, 1, 2, ... until it
       returns None.  The completion should begin with 'text'.
    """
    import rlcompleter
    # keep a completer class, and make sure that it uses the current local scope
    if not hasattr(self, 'completer'):
        self.completer = rlcompleter.Completer(self.curframe.f_locals)
    else:
        self.completer.namespace = self.curframe.f_locals
    return self.completer.complete(text, state)

Discussion:

Save the first part to a .pdbrc file in your home directory. If on startup pdb finds a .pdbrc file in either a user's home directory or in the current directory it runs each line as though it were typed into the prompt. Unfortunately that makes it impossible write multi-line functions in .pdbrc. So I have borrowed from http://wiki.python.org/moin/PdbRcIdea and used a separate file for the custom function that we want to do the real work.

When pdb starts, this replaces it's default completer function with that of rlcompleter before the completer function has been set. You should find that tab in pdb now completes names and provides proper object inspection, even as you move around the stack. pdb's default completer function only completes pdb commands, and most of those have single character abbreviations anyway. I got bored with typing "!dir([object])"

'complete' also tries to keep the completer class's namespace up to date, using curframe.f_locals.

If you would like to use tab completion, but not have it load for every session or reflect changes to the local scope then running:

import rlcompleter;import readline;readline.set_completer(rlcompleter.Completer(locals()).complete)

In a pdb prompt will enable tab completion. However, adding that to your .pdbrc file doesnt work as pdb seems to set its default completer function after the .pdbrc commands have been run.

Hope this saves you as much typing as me!



Add comment

Number of comments: 4

sasa sasa, 2006/11/01
You need to import pdb in .pdbrc otherwise you get a pdb undefined error message.
Add comment

sasa sasa, 2006/11/01
hmm, even with that, I can't get tab completion to work. It's fine if I do readline.set_completer(rlcompleter.Completer(locals()).complete) manually, but the .pdbrc method fails. This is with python-2.4.3 on Gentoo.
Add comment

python -m grabs our Pdb class!, Stephen Emslie, 2007/01/08
Thanks for the feedback. Here's what I think is going on: tab completion works fine without the import provided you're stepping into your code with

import pdb
pdb.set_trace()
However if you step in with "python -m pdb myscript.py" then python's pdb module creates an instance of the Pdb class before we can override it's complete function. Bummer.
Add comment

This is fixed!, Stephen Emslie, 2007/01/08
Thanks for the comments. After a bit of testing I discovered that this wasn't working with 'python -m myscript.py' because we are changing the complete function on the Pdb class object in our current code block. However, running pdb via "python -m" uses execfile to start your script, and that is executed in a new code block. The side effect of this is that from .pdbrc.py the Pdb class object is not the one that is being used to run this pdb session. To get a reference to the original class object one needs to jump out of the current frame back to the frame that spawned this script. sys._getframe().f_back does that and f_globals['Pdb'] then grabs the origional Pdb class.

Woot, it works!

Add comment



Highest rated recipes:

1. A simple XML-RPC server

2. Web service accessible ...

3. IPy Notify

4. Treat the Win32 Registry ...

5. a friendly mkdir()

6. Wrapping template engine ...

7. Assignment in expression

8. Changing return value ...

9. Implementation of sets ...

10. bag collection class




Privacy Policy | Email Opt-out | Feedback | Syndication
© 2006 ActiveState Software Inc. All rights reserved.