[WIP] doctest: lazily instantiate debugger

This commit is contained in:
Daniel Hahler 2019-10-27 03:36:04 +01:00
parent c4862e333a
commit db8fdb5260
1 changed files with 14 additions and 13 deletions

View File

@ -94,6 +94,7 @@ __all__ = [
import __future__ import __future__
import difflib import difflib
import functools
import inspect import inspect
import linecache import linecache
import os import os
@ -358,24 +359,16 @@ class _OutputRedirectingPdb(pdb.Pdb):
""" """
def __init__(self, out): def __init__(self, out):
self.__out = out self.__out = out
self.__debugger_used = False
# do not play signal games in the pdb # do not play signal games in the pdb
pdb.Pdb.__init__(self, stdout=out, nosigint=True) pdb.Pdb.__init__(self, stdout=out, nosigint=True)
# still use input() to get user input # still use input() to get user input
self.use_rawinput = 1 self.use_rawinput = 1
def set_trace(self, frame=None): def set_trace(self, frame=None):
self.__debugger_used = True
if frame is None: if frame is None:
frame = sys._getframe().f_back frame = sys._getframe().f_back
pdb.Pdb.set_trace(self, frame) pdb.Pdb.set_trace(self, frame)
def set_continue(self):
# Calling set_continue unconditionally would break unit test
# coverage reporting, as Bdb.set_continue calls sys.settrace(None).
if self.__debugger_used:
pdb.Pdb.set_continue(self)
def trace_dispatch(self, *args): def trace_dispatch(self, *args):
# Redirect stdout to the given stream. # Redirect stdout to the given stream.
save_stdout = sys.stdout save_stdout = sys.stdout
@ -1217,6 +1210,8 @@ class DocTestRunner:
# Create a fake output target for capturing doctest output. # Create a fake output target for capturing doctest output.
self._fakeout = _SpoofOut() self._fakeout = _SpoofOut()
self.debugger = None
#///////////////////////////////////////////////////////////////// #/////////////////////////////////////////////////////////////////
# Reporting methods # Reporting methods
#///////////////////////////////////////////////////////////////// #/////////////////////////////////////////////////////////////////
@ -1335,13 +1330,15 @@ class DocTestRunner:
# Don't blink! This is where the user's code gets run. # Don't blink! This is where the user's code gets run.
exec(compile(example.source, filename, "single", exec(compile(example.source, filename, "single",
compileflags, True), test.globs) compileflags, True), test.globs)
self.debugger.set_continue() # ==== Example Finished ==== if self.debugger:
self.debugger.set_continue() # ==== Example Finished ====
exception = None exception = None
except KeyboardInterrupt: except KeyboardInterrupt:
raise raise
except: except:
exception = sys.exc_info() exception = sys.exc_info()
self.debugger.set_continue() # ==== Example Finished ==== if self.debugger:
self.debugger.set_continue() # ==== Example Finished ====
got = self._fakeout.getvalue() # the actual output got = self._fakeout.getvalue() # the actual output
self._fakeout.truncate(0) self._fakeout.truncate(0)
@ -1422,6 +1419,12 @@ class DocTestRunner:
else: else:
return self.save_linecache_getlines(filename, module_globals) return self.save_linecache_getlines(filename, module_globals)
def _pdb_set_trace(self, stdout):
if not self.debugger:
self.debugger = _OutputRedirectingPdb(stdout)
self.debugger.reset()
self.debugger.set_trace(frame=sys._getframe().f_back)
def run(self, test, compileflags=None, out=None, clear_globs=True): def run(self, test, compileflags=None, out=None, clear_globs=True):
""" """
Run the examples in `test`, and display the results using the Run the examples in `test`, and display the results using the
@ -1466,9 +1469,7 @@ class DocTestRunner:
# allows us to write test cases for the set_trace behavior. # allows us to write test cases for the set_trace behavior.
save_trace = sys.gettrace() save_trace = sys.gettrace()
save_set_trace = pdb.set_trace save_set_trace = pdb.set_trace
self.debugger = _OutputRedirectingPdb(save_stdout) pdb.set_trace = functools.partial(self._pdb_set_trace, save_stdout)
self.debugger.reset()
pdb.set_trace = self.debugger.set_trace
# Patch linecache.getlines, so we can see the example's source # Patch linecache.getlines, so we can see the example's source
# when we're inside the debugger. # when we're inside the debugger.