From db8fdb5260bc778c2cc103cd48c991e212d9fe14 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sun, 27 Oct 2019 03:36:04 +0100 Subject: [PATCH] [WIP] doctest: lazily instantiate debugger --- Lib/doctest.py | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/Lib/doctest.py b/Lib/doctest.py index baa503c83f8..9d51797166d 100644 --- a/Lib/doctest.py +++ b/Lib/doctest.py @@ -94,6 +94,7 @@ __all__ = [ import __future__ import difflib +import functools import inspect import linecache import os @@ -358,24 +359,16 @@ class _OutputRedirectingPdb(pdb.Pdb): """ def __init__(self, out): self.__out = out - self.__debugger_used = False # do not play signal games in the pdb pdb.Pdb.__init__(self, stdout=out, nosigint=True) # still use input() to get user input self.use_rawinput = 1 def set_trace(self, frame=None): - self.__debugger_used = True if frame is None: frame = sys._getframe().f_back 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): # Redirect stdout to the given stream. save_stdout = sys.stdout @@ -1217,6 +1210,8 @@ class DocTestRunner: # Create a fake output target for capturing doctest output. self._fakeout = _SpoofOut() + self.debugger = None + #///////////////////////////////////////////////////////////////// # Reporting methods #///////////////////////////////////////////////////////////////// @@ -1335,13 +1330,15 @@ class DocTestRunner: # Don't blink! This is where the user's code gets run. exec(compile(example.source, filename, "single", compileflags, True), test.globs) - self.debugger.set_continue() # ==== Example Finished ==== + if self.debugger: + self.debugger.set_continue() # ==== Example Finished ==== exception = None except KeyboardInterrupt: raise except: 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 self._fakeout.truncate(0) @@ -1422,6 +1419,12 @@ class DocTestRunner: else: 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): """ 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. save_trace = sys.gettrace() save_set_trace = pdb.set_trace - self.debugger = _OutputRedirectingPdb(save_stdout) - self.debugger.reset() - pdb.set_trace = self.debugger.set_trace + pdb.set_trace = functools.partial(self._pdb_set_trace, save_stdout) # Patch linecache.getlines, so we can see the example's source # when we're inside the debugger.