106 lines
3.5 KiB
Python
106 lines
3.5 KiB
Python
"""
|
|
interactive debugging with the Python Debugger.
|
|
"""
|
|
import py
|
|
import pdb, sys, linecache
|
|
|
|
def pytest_addoption(parser):
|
|
group = parser.getgroup("general")
|
|
group._addoption('--pdb',
|
|
action="store_true", dest="usepdb", default=False,
|
|
help="start the interactive Python debugger on errors.")
|
|
|
|
def pytest_configure(config):
|
|
if config.getvalue("usepdb"):
|
|
config.pluginmanager.register(PdbInvoke(), 'pdb')
|
|
|
|
class PdbInvoke:
|
|
def pytest_runtest_makereport(self, item, call):
|
|
if call.excinfo and not \
|
|
call.excinfo.errisinstance(py.test.exc.Skipped):
|
|
# play well with capturing, slightly hackish
|
|
capman = item.config.pluginmanager.getplugin('capturemanager')
|
|
capman.suspendcapture()
|
|
|
|
tw = py.io.TerminalWriter()
|
|
repr = call.excinfo.getrepr()
|
|
repr.toterminal(tw)
|
|
post_mortem(call.excinfo._excinfo[2])
|
|
|
|
capman.resumecapture_item(item)
|
|
|
|
class Pdb(py.std.pdb.Pdb):
|
|
def do_list(self, arg):
|
|
self.lastcmd = 'list'
|
|
last = None
|
|
if arg:
|
|
try:
|
|
x = eval(arg, {}, {})
|
|
if type(x) == type(()):
|
|
first, last = x
|
|
first = int(first)
|
|
last = int(last)
|
|
if last < first:
|
|
# Assume it's a count
|
|
last = first + last
|
|
else:
|
|
first = max(1, int(x) - 5)
|
|
except:
|
|
print ('*** Error in argument: %s' % repr(arg))
|
|
return
|
|
elif self.lineno is None:
|
|
first = max(1, self.curframe.f_lineno - 5)
|
|
else:
|
|
first = self.lineno + 1
|
|
if last is None:
|
|
last = first + 10
|
|
filename = self.curframe.f_code.co_filename
|
|
breaklist = self.get_file_breaks(filename)
|
|
try:
|
|
for lineno in range(first, last+1):
|
|
# start difference from normal do_line
|
|
line = self._getline(filename, lineno)
|
|
# end difference from normal do_line
|
|
if not line:
|
|
print ('[EOF]')
|
|
break
|
|
else:
|
|
s = repr(lineno).rjust(3)
|
|
if len(s) < 4: s = s + ' '
|
|
if lineno in breaklist: s = s + 'B'
|
|
else: s = s + ' '
|
|
if lineno == self.curframe.f_lineno:
|
|
s = s + '->'
|
|
sys.stdout.write(s + '\t' + line)
|
|
self.lineno = lineno
|
|
except KeyboardInterrupt:
|
|
pass
|
|
do_l = do_list
|
|
|
|
def _getline(self, filename, lineno):
|
|
if hasattr(filename, "__source__"):
|
|
try:
|
|
return filename.__source__.lines[lineno - 1] + "\n"
|
|
except IndexError:
|
|
return None
|
|
return linecache.getline(filename, lineno)
|
|
|
|
def get_stack(self, f, t):
|
|
# Modified from bdb.py to be able to walk the stack beyond generators,
|
|
# which does not work in the normal pdb :-(
|
|
stack, i = pdb.Pdb.get_stack(self, f, t)
|
|
if f is None:
|
|
i = max(0, len(stack) - 1)
|
|
while i and stack[i][0].f_locals.get("__tracebackhide__", False):
|
|
i-=1
|
|
return stack, i
|
|
|
|
def post_mortem(t):
|
|
p = Pdb()
|
|
p.reset()
|
|
p.interaction(None, t)
|
|
|
|
def set_trace():
|
|
# again, a copy of the version in pdb.py
|
|
Pdb().set_trace(sys._getframe().f_back)
|