Welcome, guest | Sign In | My Account | Store | Cart

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 (6 Jul 2009): import rlcompleter early and force output to stdout to ensure monkeypatch sticks Edit: updated to handle changes in local scope Edit: Fixed start via 'python -m pdb ...'. Check the comments for details.

Python, 28 lines
# save this in .pdbrc in your home directory
import os
import sys
# import rlcompleter early, as it contains side effects
import rlcompleter
# refresh the terminal
os.system("stty sane")
# this rc file takes single lines, so define our complete function here
# replace the Pdb class's complete method with ours
sys._getframe(1).f_globals['Pdb'].complete = complete
# set use_rawinput to 1 as tab completion relies on rawinput being used
sys._getframe(1).f_locals['self'].use_rawinput = 1

# 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'.
    # 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)
        self.completer.namespace = self.curframe.f_locals
    return self.completer.complete(text, state)

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!


sasa sasa 17 years, 5 months ago  # | flag

You need to import pdb in .pdbrc otherwise you get a pdb undefined error message.

sasa sasa 17 years, 5 months ago  # | flag

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.

Stephen Emslie (author) 17 years, 3 months ago  # | flag

python -m grabs our Pdb class! 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

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.

Stephen Emslie (author) 17 years, 3 months ago  # | flag

This is fixed! 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!
L P 14 years, 9 months ago  # | flag

Nice stuff!

But why not use the package ipdb which provides many more things beyond tab completion?

haridsv 14 years ago  # | flag

Doesn't work for me, either to complete variables or members (after "."). Anyone got this working with python 2.6?

"L P", the reason is ipdb works only when run from within ipython, which is not always convenient.