diff --git a/Lib/bdb.py b/Lib/bdb.py index c6a10359ac..6872186683 100644 --- a/Lib/bdb.py +++ b/Lib/bdb.py @@ -3,6 +3,8 @@ import fnmatch import sys import os +import linecache +import reprlib from inspect import CO_GENERATOR, CO_COROUTINE, CO_ASYNC_GENERATOR __all__ = ["BdbQuit", "Bdb", "Breakpoint"] @@ -53,7 +55,6 @@ class Bdb: def reset(self): """Set values of attributes as ready to start debugging.""" - import linecache linecache.checkcache() self.botframe = None self._set_stopinfo(None, None) @@ -89,7 +90,11 @@ class Bdb: if event == 'call': return self.dispatch_call(frame, arg) if event == 'return': - return self.dispatch_return(frame, arg) + try: + return self.dispatch_return(frame, arg) + finally: + if frame == self.botframe: + self.botframe = None if event == 'exception': return self.dispatch_exception(frame, arg) if event == 'c_call': @@ -123,8 +128,11 @@ class Bdb: # XXX 'arg' is no longer used if self.botframe is None: # First call of dispatch since reset() - self.botframe = frame.f_back # (CT) Note that this may also be None! - return self.trace_dispatch + self.botframe = frame.f_back + # When tracing a destructor, frame.f_back is None and the 'call' + # trace event is not ignored. + if frame.f_back is not None: + return self.trace_dispatch if not (self.stop_here(frame) or self.break_anywhere(frame)): # No need to trace this function return # None @@ -371,7 +379,6 @@ class Bdb: The filename should be in canonical form. """ filename = self.canonic(filename) - import linecache # Import as late as possible line = linecache.getline(filename, lineno) if not line: return 'Line %s:%d does not exist' % (filename, lineno) @@ -538,7 +545,6 @@ class Bdb: line of code (if it exists). """ - import linecache, reprlib frame, lineno = frame_lineno filename = self.canonic(frame.f_code.co_filename) s = '%s(%r)' % (filename, lineno) @@ -843,7 +849,6 @@ class Tdb(Bdb): if not name: name = '???' print('+++ call', name, args) def user_line(self, frame): - import linecache name = frame.f_code.co_name if not name: name = '???' fn = self.canonic(frame.f_code.co_filename) diff --git a/Lib/pdb.py b/Lib/pdb.py index fb23ae3e6a..ed28a90efa 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -80,6 +80,7 @@ import signal import inspect import traceback import linecache +import shlex class Restart(Exception): @@ -609,6 +610,10 @@ class Pdb(bdb.Bdb, cmd.Cmd): hasn't been loaded yet). The file is searched for on sys.path; the .py suffix may be omitted. """ + if sys.path is None: + self.error('Cannot set a breakpoint, sys.path is None') + return + if not arg: if self.breaks: # There's at least one self.message("Num Type Disp Enb Where") @@ -1021,7 +1026,6 @@ class Pdb(bdb.Bdb, cmd.Cmd): are preserved. "restart" is an alias for "run". """ if arg: - import shlex argv0 = sys.argv[0:1] sys.argv = shlex.split(arg) sys.argv[:0] = argv0 @@ -1635,7 +1639,11 @@ def test(): # print help def help(): - import pydoc + try: + import pydoc + except ImportError: + print('***', 'Cannot print pdb main help on Python finalization') + return pydoc.pager(__doc__) _usage = """\ diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index 343c5a4440..457dd88804 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -2469,6 +2469,7 @@ class StatefulIncrementalDecoderTest(unittest.TestCase): self.assertEqual(d.decode(b'', 1), 'abcd.') class TextIOWrapperTest(unittest.TestCase): + shutdown_error = "LookupError: unknown encoding: ascii" def setUp(self): self.testdata = b"AAA\r\nBBB\rCCC\r\nDDD\nEEE\r\n" @@ -3567,7 +3568,6 @@ def _to_memoryview(buf): class CTextIOWrapperTest(TextIOWrapperTest): io = io - shutdown_error = "RuntimeError: could not find io module state" def test_initialization(self): r = self.BytesIO(b"\xc3\xa9\n\n") @@ -3613,7 +3613,6 @@ class CTextIOWrapperTest(TextIOWrapperTest): class PyTextIOWrapperTest(TextIOWrapperTest): io = pyio - shutdown_error = "LookupError: unknown encoding: ascii" class IncrementalNewlineDecoderTest(unittest.TestCase): diff --git a/Python/import.c b/Python/import.c index bb1d69e168..80f96347f5 100644 --- a/Python/import.c +++ b/Python/import.c @@ -503,6 +503,15 @@ PyImport_Cleanup(void) } } + /* Modules whose only referrer was sys.modules are now cleared by this + * garbage collection. This is the last chance to trace destructors as + * tracing in the next garbage collection made after the call to + * _PyState_ClearModules() may fail because PyState_FindModule() for + * extension modules returns NULL at that time (pdb calls into the + * readline extension module). */ + _PyGC_CollectNoFail(); + PyEval_SetTrace(NULL, NULL); + /* Clear the modules dict. */ if (PyDict_CheckExact(modules)) { PyDict_Clear(modules);