Skip to content

Instantly share code, notes, and snippets.

@akuhn
Last active June 9, 2024 09:51
Show Gist options
  • Save akuhn/195b4ec4305e809af2074b07d4628b14 to your computer and use it in GitHub Desktop.
Save akuhn/195b4ec4305e809af2074b07d4628b14 to your computer and use it in GitHub Desktop.
# My patches for ipdb debugger.
#
# - Use file history
# - Magic lambda expressions
# - Safe assignments (avoid collision with commands)
# - Print assignments
# - ls command (a better dir)
# - dollar command (a better pinfo)
# - fix debug command
#
# How to install this?
#
# Save this file somewhere and import it with execfile(...) in your ~/.pdbrc file.
#
# Thank you for using my code!
def patch_ipdb():
import os
import re
import sys
from IPython.terminal.debugger import TerminalPdb
from prompt_toolkit.history import FileHistory
precmd = TerminalPdb.precmd
cmdloop = TerminalPdb.cmdloop
lambda_pattern = re.compile('(\.[a-z]+\()([a-z]+:)')
assignment_pattern = re.compile('^([a-z][_a-z0-9]*) = ')
def precmd_prime(self, original_line):
line = precmd(self, original_line)
# Magic lambda expressions
line = lambda_pattern.sub('\\1lambda \\2', line)
# Safe assignments (avoid collision with commands)
assignment = assignment_pattern.match(line)
if assignment:
line = "!{}".format(line)
# Print assignments
if assignment and not line.endswith(';'):
self.cmdqueue.append("!" + assignment.group(1))
# if original_line != line:
# print '------>', line
# for cmd in self.cmdqueue:
# print '------>', cmd
return line
def cmdloop_prime(self, intro=None):
fname = os.path.join(os.path.expanduser('~'), '.ipdb_history')
self._pt_app.buffer.history = FileHistory(fname)
self._pt_app.buffer.reset()
self.do_alias('$ dollar %*')
cmdloop(self, intro)
TerminalPdb.precmd = precmd_prime
TerminalPdb.cmdloop = cmdloop_prime
# A better dir function.
#
# Prints names in columns and orders them by superclass.
#
def do_ls(self, arg):
try:
value = self._getval(arg)
except:
return
import fcntl, termios, struct
th, tw, hp, wp = struct.unpack('HHHH', fcntl.ioctl(
0,
termios.TIOCGWINSZ,
struct.pack('HHHH', 0, 0, 0, 0),
))
terminal_width = tw
def printable_name(each):
try:
return 'instance' if each == value and not isinstance(value, type) else each.__name__
except:
return each
def print_columns(names):
for n in range(len(names)):
num_rows = n + 1
columns = [names[i:i + num_rows] for i in range(0, len(names), num_rows)]
widths = [max(len(name) for name in column) for column in columns]
total_width = sum(w + 2 for w in widths)
if total_width < terminal_width:
for row_num in range(num_rows):
for column_num in range(len(columns)):
if row_num < len(columns[column_num]):
print columns[column_num][row_num].ljust(widths[column_num] + 1),
print ''
return
ancestors = (type.mro(value) if isinstance(value, type) else [value] + type(value).mro())[::-1]
method_resolution = {}
for each in ancestors:
if not hasattr(each, '__dict__'): continue
for name in each.__dict__.keys():
if name.startswith('__'): continue
method_resolution[name] = each
for each in ancestors:
if not hasattr(each, '__dict__'): continue
names = [name for name in each.__dict__.keys() if method_resolution.get(name) == each]
callables = [name for name in names if callable(each.__dict__[name])]
noncallables = [name for name in names if not callable(each.__dict__[name])]
if callables:
print "\033[0;34m{}#methods\033[0m".format(printable_name(each))
print_columns(sorted(callables))
if noncallables:
print "\033[0;34m{}#attributes\033[0m".format(printable_name(each))
print_columns(sorted(noncallables))
def do_dollar(self, arg):
try:
value = self._getval(arg)
except:
return
namespaces = [('Interactive', { 'name': value })]
self.shell.find_line_magic('pinfo2')('name', namespaces=namespaces)
# Copied from superclass to create correct subclass instance
def do_debug(self, arg):
sys.settrace(None)
globals = self.curframe.f_globals
locals = self.curframe_locals
p = TerminalPdb(self.completekey, self.stdin, self.stdout)
print >>self.stdout, "ENTERING RECURSIVE DEBUGGER"
sys.call_tracing(p.run, (arg, globals, locals))
print >>self.stdout, "LEAVING RECURSIVE DEBUGGER"
sys.settrace(self.trace_dispatch)
self.lastcmd = p.lastcmd
TerminalPdb.do_ls = do_ls
TerminalPdb.do_dollar = do_dollar
TerminalPdb.do_debug = do_debug
patch_ipdb()
del patch_ipdb
@gagomes
Copy link

gagomes commented Jun 9, 2024

Any plans to make a python3 version of this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment