serhii.net

In the middle of the desert you can say anything you want

10 Sep 2025

pdb and pdbpp aliases and configs

~/.pdbrc gets read by both of them, and can import stuff and use aliases!

# ! makes it python code to be executed
!import rich

alias I rich.inspect(%1)
# # alternative if not !importing it above in one command
alias P !import rich; rich.print(%1)

print("Custom commands:")
print("\t I $thing — rich inspect $thing")
print("\t P $thing — rich pretty print $thing")

EDIT: the above works only if rich is already imported.

Better pretty printing

The above doesn’t do comprehensions well (+ needs imported rich in the running thing).

> [x for x in [2,4,5]]
[2, 4, 5]
> P [x for x in [2,4,5]]
*** SyntaxError: closing parenthesis ')' does not match opening parenthesis '['

Looking at:

Instead of doing alias ... which uses %1 which fails, we can use pdbpp’s pdb’s _getval() fn which does this in a smarter way.

THEN, in our ~/.pdbrc.py (NOT ~/.pdbrc!), adapting the code for pdbpp’s do_pp():

import pdb
import rich
import os, sys, traceback



class Config(pdb.DefaultConfig):
    def setup(self, pdb):
        Pdb = pdb.__class__
		# "do_xxx" methods automagically get parsed into commands
		
        # make 'l' an alias to 'longlist' -> existing method 
        Pdb.do_l = Pdb.do_longlist

		# new methods
        Pdb.do_P = _do_P

# defining a method with self outside a class feels so _wrong_...
def _do_P(self, arg):
    try:
        val = self._getval(arg)
    except:
        return
    try:
        rich.print(val)
    except:
        exc_info = sys.exc_info()[:2]
        self.error(traceback.format_exception_only(*exc_info)[-1].strip())
    # [x for x in [2,4,5]]

Then it works!

Even better:

import pdb
import os, sys, traceback

from pprint import pprint

try:
    # from rich import print as rprint
    from rich import inspect
    from rich.pretty import pprint
except ImportError:
    print("rich is not available, falling back to pprint")
    pass


class Config(pdb.DefaultConfig):
    prompt = "> "
    sticky_by_default = True
	
    def setup(self, pdb):
        Pdb = pdb.__class__
        Pdb.do_P = _do_P
        Pdb.do_I = _do_I


def do_with_arg(self, arg, func):
    try:
        val = self._getval(arg)
    except:
        return
    try:
        func(val)
    except:
        exc_info = sys.exc_info()[:2]
        self.error(traceback.format_exception_only(*exc_info)[-1].strip())


def _do_P(self, arg):
    do_with_arg(self, arg, pprint)

def _do_I(self, arg):
    try:
        do_with_arg(self, arg, inspect)
    except NameError:
        print("rich is not available, falling back to pprint")
        do_with_arg(self, arg, pprint)
Nel mezzo del deserto posso dire tutto quello che voglio.
comments powered by Disqus