Shells

Internal shell

At any point while debugging, press Ctrl-x to switch to the built in interactive shell. From here, you can execute Python commands at the current point of the debugger. Press Ctrl-x again to move back to the debugger.

Keyboard shortcuts defined in the internal shell:

Enter Execute the current command
Ctrl-v Insert a newline (for multiline commands)
Ctrl-n/p Browse command history
Up/down arrow Select history
TAB Tab completion
+/- grow/shrink the shell (when a history item is selected)
_/= minimize/maximize the shell (when a history item is selected)

External shells

To open the external shell, press the ! key while debugging. Unlike the internal shell, external shells close the debugger UI while the shell is active. Press Ctrl-d at any time to exit the shell and return to the debugger.

To configure the shell used by PuDB, open the settings (Ctrl-p) and select the shell.

PuDB supports the following external shells.

  • Internal (same as pressing Ctrl-x). This is the default.
  • Classic (similar to the default python interactive shell)
  • IPython
  • bpython
  • ptpython

Custom shells

To define a custom external shell, create a file with a function pudb_shell(_globals, _locals) at the module level. Then, in the settings (Ctrl-p), select “Custom” under the shell settings, and add the path to the file.

Here is an example custom shell file:

"""
This file shows how you can define a custom shell for PuDB. This is the
shell used when pressing the ! key in the debugger (it does not affect the
Ctrl-x shell that is built into PuDB).

To create a custom shell, create a file like this one with a function called
pudb_shell(_globals, _locals) defined at the module level. Note
that the file will be execfile'd.

Then, go to the PuDB preferences window (type Ctrl-p inside of PuDB) and add
the path to the file in the "Custom" field under the "Shell" heading.

The example in this file

"""

# Define this a function with this name and signature at the module level.
def pudb_shell(_globals, _locals):
    """
    This example shell runs a classic Python shell. It is based on
    run_classic_shell in pudb.shell.

    """
    # Many shells only let you pass in a single locals dictionary, rather than
    # separate globals and locals dictionaries. In this case, you can use
    # pudb.shell.SetPropagatingDict to automatically merge the two into a
    # single dictionary. It does this in such a way that assignments propogate
    # to _locals, so that when the debugger is at the module level, variables
    # can be reassigned in the shell.
    from pudb.shell import SetPropagatingDict
    ns = SetPropagatingDict([_locals, _globals], _locals)

    try:
        import readline
        import rlcompleter
        HAVE_READLINE = True
    except ImportError:
        HAVE_READLINE = False

    if HAVE_READLINE:
        readline.set_completer(
                rlcompleter.Completer(ns).complete)
        readline.parse_and_bind("tab: complete")
        readline.clear_history()

    from code import InteractiveConsole
    cons = InteractiveConsole(ns)
    cons.interact("Press Ctrl-D to return to the debugger")
    # When the function returns, control will be returned to the debugger.

Note, many shells do not allow passing in globals and locals dictionaries separately. In this case, you can merge the two with

from pudb.shell import SetPropagatingDict
ns = SetPropagatingDict([_locals, _globals], _locals)

Here is more information on SetPropagatingDict:

class pudb.shell.SetPropagatingDict(source_dicts, target_dict)

Combine dict into one, with assignments affecting a target dict

The source dicts are combined so that early dicts in the list have higher precedence.

Typical usage is SetPropagatingDict([locals, globals], locals). This is used for functions like rlcompleter.Completer and code.InteractiveConsole, which only take a single dictionary. This way, changes made to it are propagated to locals. Note that assigning to locals only actually works at the module level, when locals() is the same as globals(), so propagation doesn’t happen at all if the debugger is inside a function frame.