summaryrefslogtreecommitdiffstats
path: root/Lib/pdb.py
diff options
context:
space:
mode:
authorGeorg Brandl <georg@python.org>2010-07-30 18:46:38 (GMT)
committerGeorg Brandl <georg@python.org>2010-07-30 18:46:38 (GMT)
commit0a9c3e91dc50ce22a48ff7364a6c297ffb91c19a (patch)
treecfbc1e378c95a70e7d07167ae0c985572a524ad4 /Lib/pdb.py
parentcdf66a9a7c6fe761353058d6d8eb3695ac567722 (diff)
downloadcpython-0a9c3e91dc50ce22a48ff7364a6c297ffb91c19a.zip
cpython-0a9c3e91dc50ce22a48ff7364a6c297ffb91c19a.tar.gz
cpython-0a9c3e91dc50ce22a48ff7364a6c297ffb91c19a.tar.bz2
Show the traceback line numbers as well as the current line numbers if an exception is being debugged. Courtesy of pdb++ by Antonio Cuni. Also document -> and >> markers for "list".
Diffstat (limited to 'Lib/pdb.py')
-rwxr-xr-xLib/pdb.py68
1 files changed, 48 insertions, 20 deletions
diff --git a/Lib/pdb.py b/Lib/pdb.py
index 2531e19..83e1197 100755
--- a/Lib/pdb.py
+++ b/Lib/pdb.py
@@ -70,8 +70,10 @@ import sys
import linecache
import cmd
import bdb
+import dis
import os
import re
+import code
import pprint
import traceback
import inspect
@@ -107,14 +109,22 @@ def find_function(funcname, filename):
def getsourcelines(obj):
lines, lineno = inspect.findsource(obj)
- if inspect.isframe(obj) and lineno == 0 and \
- obj.f_globals is obj.f_locals:
+ if inspect.isframe(obj) and obj.f_globals is obj.f_locals:
# must be a module frame: do not try to cut a block out of it
- return lines, 0
+ return lines, 1
elif inspect.ismodule(obj):
- return lines, 0
+ return lines, 1
return inspect.getblock(lines[lineno:]), lineno+1
+def lasti2lineno(code, lasti):
+ linestarts = list(dis.findlinestarts(code))
+ linestarts.reverse()
+ for i, lineno in linestarts:
+ if lasti >= i:
+ return lineno
+ return 0
+
+
# Interaction prompt line will separate file and call info from code
# text using value of line_prefix string. A newline and arrow may
# be to your liking. You can set it once pdb is imported using the
@@ -133,6 +143,7 @@ class Pdb(bdb.Bdb, cmd.Cmd):
self.aliases = {}
self.mainpyfile = ''
self._wait_for_mainpyfile = 0
+ self.tb_lineno = {}
# Try to load readline if it exists
try:
import readline
@@ -179,10 +190,18 @@ class Pdb(bdb.Bdb, cmd.Cmd):
self.stack = []
self.curindex = 0
self.curframe = None
+ self.tb_lineno.clear()
- def setup(self, f, t):
+ def setup(self, f, tb):
self.forget()
- self.stack, self.curindex = self.get_stack(f, t)
+ self.stack, self.curindex = self.get_stack(f, tb)
+ while tb:
+ # when setting up post-mortem debugging with a traceback, save all
+ # the original line numbers to be displayed along the current line
+ # numbers (which can be different, e.g. due to finally clauses)
+ lineno = lasti2lineno(tb.tb_frame.f_code, tb.tb_lasti)
+ self.tb_lineno[tb.tb_frame] = lineno
+ tb = tb.tb_next
self.curframe = self.stack[self.curindex][0]
# The f_locals dictionary is updated from the actual frame
# locals whenever the .f_locals accessor is called, so we
@@ -1005,13 +1024,18 @@ class Pdb(bdb.Bdb, cmd.Cmd):
def do_list(self, arg):
"""l(ist) [first [,last] | .]
- List source code for the current file.
- Without arguments, list 11 lines around the current line
- or continue the previous listing.
- With . as argument, list 11 lines around the current line.
- With one argument, list 11 lines starting at that line.
- With two arguments, list the given range;
- if the second argument is less than the first, it is a count.
+
+ List source code for the current file. Without arguments,
+ list 11 lines around the current line or continue the previous
+ listing. With . as argument, list 11 lines around the current
+ line. With one argument, list 11 lines starting at that line.
+ With two arguments, list the given range; if the second
+ argument is less than the first, it is a count.
+
+ The current line in the current frame is indicated by "->".
+ If an exception is being debugged, the line where the
+ exception was originally raised or propagated is indicated by
+ ">>", if it differs from the current line.
"""
self.lastcmd = 'list'
last = None
@@ -1039,10 +1063,9 @@ class Pdb(bdb.Bdb, cmd.Cmd):
filename = self.curframe.f_code.co_filename
breaklist = self.get_file_breaks(filename)
try:
- # XXX add tb_lineno feature
lines = linecache.getlines(filename, self.curframe.f_globals)
self._print_lines(lines[first-1:last], first, breaklist,
- self.curframe.f_lineno, -1)
+ self.curframe)
self.lineno = min(last, len(lines))
if len(lines) < last:
self.message('[EOF]')
@@ -1061,7 +1084,7 @@ class Pdb(bdb.Bdb, cmd.Cmd):
except IOError as err:
self.error(err)
return
- self._print_lines(lines, lineno, breaklist, self.curframe.f_lineno, -1)
+ self._print_lines(lines, lineno, breaklist, self.curframe)
do_ll = do_longlist
def do_source(self, arg):
@@ -1077,10 +1100,15 @@ class Pdb(bdb.Bdb, cmd.Cmd):
except (IOError, TypeError) as err:
self.error(err)
return
- self._print_lines(lines, lineno, [], -1, -1)
+ self._print_lines(lines, lineno)
- def _print_lines(self, lines, start, breaks, current, special):
+ def _print_lines(self, lines, start, breaks=(), frame=None):
"""Print a range of lines."""
+ if frame:
+ current_lineno = frame.f_lineno
+ exc_lineno = self.tb_lineno.get(frame, -1)
+ else:
+ current_lineno = exc_lineno = -1
for lineno, line in enumerate(lines, start):
s = str(lineno).rjust(3)
if len(s) < 4:
@@ -1089,9 +1117,9 @@ class Pdb(bdb.Bdb, cmd.Cmd):
s += 'B'
else:
s += ' '
- if lineno == current:
+ if lineno == current_lineno:
s += '->'
- elif lineno == special:
+ elif lineno == exc_lineno:
s += '>>'
self.message(s + '\t' + line.rstrip())