diff --git a/Lib/doctest.py b/Lib/doctest.py index 5dd0bae40be..724a3ad616c 100644 --- a/Lib/doctest.py +++ b/Lib/doctest.py @@ -1254,27 +1254,30 @@ class DocTestRunner: if compileflags is None: compileflags = _extract_future_flags(test.globs) + save_stdout = sys.stdout if out is None: - out = sys.stdout.write - saveout = sys.stdout + out = save_stdout.write + sys.stdout = self._fakeout - # Note that don't save away the previous pdb.set_trace. Rather, - # we safe pdb.set_trace on import (see import section above). - # We then call and restore that original cersion. We do it this - # way to make this feature testable. If we kept and called the - # previous version, we'd end up restoring the original stdout, - # which is not what we want. + # Patch pdb.set_trace to restore sys.stdout, so that interactive + # debugging output is visible (not still redirected to self._fakeout). + # Note that we run "the real" pdb.set_trace (captured at doctest + # import time) in our replacement. Because the current run() may + # run another doctest (and so on), the current pdb.set_trace may be + # our set_trace function, which changes sys.stdout. If we called + # a chain of those, we wouldn't be left with the save_stdout + # *this* run() invocation wants. def set_trace(): - sys.stdout = saveout + sys.stdout = save_stdout real_pdb_set_trace() + save_set_trace = pdb.set_trace + pdb.set_trace = set_trace try: - sys.stdout = self._fakeout - pdb.set_trace = set_trace return self.__run(test, compileflags, out) finally: - sys.stdout = saveout - pdb.set_trace = real_pdb_set_trace + sys.stdout = save_stdout + pdb.set_trace = save_set_trace if clear_globs: test.globs.clear() diff --git a/Lib/test/test_doctest.py b/Lib/test/test_doctest.py index 130cf048a1d..28b72cb5bcf 100644 --- a/Lib/test/test_doctest.py +++ b/Lib/test/test_doctest.py @@ -987,11 +987,11 @@ Run the debugger on the docstring, and then restore sys.stdin. def test_pdb_set_trace(): r"""Using pdb.set_trace from a doctest - You can use pdb.set_trace from a doctest. To do so, you must + You can use pdb.set_trace from a doctest. To do so, you must retrieve the set_trace function from the pdb module at the time - you use it. The doctest module changes sys,stdout so that it can - capture program output. It also temporarily replaces pdb.set_trace - with a version that restores stdout. This is necessary for you to + you use it. The doctest module changes sys.stdout so that it can + capture program output. It also temporarily replaces pdb.set_trace + with a version that restores stdout. This is necessary for you to see debugger output. >>> doc = ''' @@ -1041,8 +1041,7 @@ def test_pdb_set_trace(): ... >>> calls_set_trace() ... ''' >>> test = doctest.DocTest(doc, globals(), "foo", "foo.py", 0) - - >>> import tempfile + >>> fake_stdin = tempfile.TemporaryFile(mode='w+') >>> fake_stdin.write('\n'.join([ ... 'up', # up out of pdb.set_trace