diff options
-rw-r--r-- | Doc/library/ftplib.rst | 6 | ||||
-rw-r--r-- | Lib/bdb.py | 10 | ||||
-rw-r--r-- | Lib/doctest.py | 7 | ||||
-rwxr-xr-x | Lib/pdb.py | 27 | ||||
-rw-r--r-- | Lib/test/test_doctest.py | 29 | ||||
-rw-r--r-- | Lib/test/test_pdb.py | 42 | ||||
-rw-r--r-- | Misc/NEWS | 15 | ||||
-rw-r--r-- | Misc/maintainers.rst | 2 |
8 files changed, 123 insertions, 15 deletions
diff --git a/Doc/library/ftplib.rst b/Doc/library/ftplib.rst index 27cc444..4b25d85 100644 --- a/Doc/library/ftplib.rst +++ b/Doc/library/ftplib.rst @@ -220,9 +220,9 @@ followed by ``lines`` for the text version or ``binary`` for the binary version. Retrieve a file or directory listing in ASCII transfer mode. *command* should be an appropriate ``RETR`` command (see :meth:`retrbinary`) or a command such as ``LIST``, ``NLST`` or ``MLSD`` (usually just the string - ``'LIST'``). The *callback* function is called for each line, with the - trailing CRLF stripped. The default *callback* prints the line to - ``sys.stdout``. + ``'LIST'``). The *callback* function is called for each line with a + string argument containing the line with the trailing CRLF stripped. + The default *callback* prints the line to ``sys.stdout``. .. method:: FTP.set_pasv(boolean) @@ -109,6 +109,8 @@ class Bdb: self.is_skipped_module(frame.f_globals.get('__name__')): return False if frame is self.stopframe: + if self.stoplineno == -1: + return False return frame.f_lineno >= self.stoplineno while frame is not None and frame is not self.stopframe: if frame is self.botframe: @@ -166,10 +168,12 @@ class Bdb: but only if we are to stop at or just below this level.""" pass - def _set_stopinfo(self, stopframe, returnframe, stoplineno=-1): + def _set_stopinfo(self, stopframe, returnframe, stoplineno=0): self.stopframe = stopframe self.returnframe = returnframe self.quitting = 0 + # stoplineno >= 0 means: stop at line >= the stoplineno + # stoplineno -1 means: don't stop at all self.stoplineno = stoplineno # Derived classes and clients can call the following methods @@ -182,7 +186,7 @@ class Bdb: def set_step(self): """Stop after one line of code.""" - self._set_stopinfo(None,None) + self._set_stopinfo(None, None) def set_next(self, frame): """Stop on the next line in or below the given frame.""" @@ -209,7 +213,7 @@ class Bdb: def set_continue(self): # Don't stop except at breakpoints or when finished - self._set_stopinfo(self.botframe, None) + self._set_stopinfo(self.botframe, None, -1) if not self.breaks: # no breakpoints; run without debugger overhead sys.settrace(None) diff --git a/Lib/doctest.py b/Lib/doctest.py index 917684c..8bca63d 100644 --- a/Lib/doctest.py +++ b/Lib/doctest.py @@ -335,6 +335,8 @@ class _OutputRedirectingPdb(pdb.Pdb): self.__out = out self.__debugger_used = False pdb.Pdb.__init__(self, stdout=out) + # still use input() to get user input + self.use_rawinput = 1 def set_trace(self, frame=None): self.__debugger_used = True @@ -1381,12 +1383,17 @@ class DocTestRunner: self.save_linecache_getlines = linecache.getlines linecache.getlines = self.__patched_linecache_getlines + # Make sure sys.displayhook just prints the value to stdout + save_displayhook = sys.displayhook + sys.displayhook = sys.__displayhook__ + try: return self.__run(test, compileflags, out) finally: sys.stdout = save_stdout pdb.set_trace = save_set_trace linecache.getlines = self.save_linecache_getlines + sys.displayhook = save_displayhook if clear_globs: test.globs.clear() @@ -183,14 +183,18 @@ class Pdb(bdb.Bdb, cmd.Cmd): def user_return(self, frame, return_value): """This function is called when a return trap is set here.""" + if self._wait_for_mainpyfile: + return frame.f_locals['__return__'] = return_value print >>self.stdout, '--Return--' self.interaction(frame, None) def user_exception(self, frame, exc_info): - exc_type, exc_value, exc_traceback = exc_info """This function is called if an exception occurs, but only if we are to stop at or just below this level.""" + if self._wait_for_mainpyfile: + return + exc_type, exc_value, exc_traceback = exc_info frame.f_locals['__exception__'] = exc_type, exc_value if type(exc_type) == type(''): exc_type_name = exc_type @@ -277,8 +281,10 @@ class Pdb(bdb.Bdb, cmd.Cmd): return self.handle_command_def(line) def handle_command_def(self,line): - """ Handles one command line during command list definition. """ + """Handles one command line during command list definition.""" cmd, arg, line = self.parseline(line) + if not cmd: + return if cmd == 'silent': self.commands_silent[self.commands_bnum] = True return # continue to handle other cmd def in the cmd list @@ -286,7 +292,7 @@ class Pdb(bdb.Bdb, cmd.Cmd): self.cmdqueue = [] return 1 # end of cmd list cmdlist = self.commands[self.commands_bnum] - if (arg): + if arg: cmdlist.append(cmd+' '+arg) else: cmdlist.append(cmd) @@ -329,9 +335,11 @@ class Pdb(bdb.Bdb, cmd.Cmd): prompt_back = self.prompt self.prompt = '(com) ' self.commands_defining = True - self.cmdloop() - self.commands_defining = False - self.prompt = prompt_back + try: + self.cmdloop() + finally: + self.commands_defining = False + self.prompt = prompt_back def do_break(self, arg, temporary = 0): # break [ ([filename:]lineno | function) [, "condition"] ] @@ -467,7 +475,10 @@ class Pdb(bdb.Bdb, cmd.Cmd): Return `lineno` if it is, 0 if not (e.g. a docstring, comment, blank line or EOF). Warning: testing is not comprehensive. """ - line = linecache.getline(filename, lineno, self.curframe.f_globals) + # this method should be callable before starting debugging, so default + # to "no globals" if there is no current frame + globs = self.curframe.f_globals if hasattr(self, 'curframe') else None + line = linecache.getline(filename, lineno, globs) if not line: print >>self.stdout, 'End of file' return 0 @@ -1298,7 +1309,7 @@ def main(): # changed by the user from the command line. There is a "restart" command # which allows explicit specification of command line arguments. pdb = Pdb() - while 1: + while True: try: pdb._runscript(mainpyfile) if pdb._user_requested_quit: diff --git a/Lib/test/test_doctest.py b/Lib/test/test_doctest.py index e51bacc..b30bcab 100644 --- a/Lib/test/test_doctest.py +++ b/Lib/test/test_doctest.py @@ -981,6 +981,35 @@ unexpected exception: ZeroDivisionError: integer division or modulo by zero TestResults(failed=1, attempted=1) """ + def displayhook(): r""" +Test that changing sys.displayhook doesn't matter for doctest. + + >>> import sys + >>> orig_displayhook = sys.displayhook + >>> def my_displayhook(x): + ... print('hi!') + >>> sys.displayhook = my_displayhook + >>> def f(): + ... ''' + ... >>> 3 + ... 3 + ... ''' + >>> test = doctest.DocTestFinder().find(f)[0] + >>> r = doctest.DocTestRunner(verbose=False).run(test) + >>> post_displayhook = sys.displayhook + + We need to restore sys.displayhook now, so that we'll be able to test + results. + + >>> sys.displayhook = orig_displayhook + + Ok, now we can check that everything is ok. + + >>> r + TestResults(failed=0, attempted=1) + >>> post_displayhook is my_displayhook + True +""" def optionflags(): r""" Tests of `DocTestRunner`'s option flag handling. diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index ce64d17..8aca812 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -126,6 +126,48 @@ def test_pdb_skip_modules_with_callback(): """ +def test_pdb_continue_in_bottomframe(): + """Test that "continue" and "next" work properly in bottom frame (issue #5294). + + >>> def test_function(): + ... import pdb, sys; inst = pdb.Pdb() + ... inst.set_trace() + ... inst.botframe = sys._getframe() # hackery to get the right botframe + ... print(1) + ... print(2) + ... print(3) + ... print(4) + + >>> with PdbTestInput([ + ... 'next', + ... 'break 7', + ... 'continue', + ... 'next', + ... 'continue', + ... 'continue', + ... ]): + ... test_function() + > <doctest test.test_pdb.test_pdb_continue_in_bottomframe[0]>(4)test_function() + -> inst.botframe = sys._getframe() # hackery to get the right botframe + (Pdb) next + > <doctest test.test_pdb.test_pdb_continue_in_bottomframe[0]>(5)test_function() + -> print(1) + (Pdb) break 7 + Breakpoint 1 at <doctest test.test_pdb.test_pdb_continue_in_bottomframe[0]>:7 + (Pdb) continue + 1 + 2 + > <doctest test.test_pdb.test_pdb_continue_in_bottomframe[0]>(7)test_function() + -> print(3) + (Pdb) next + 3 + > <doctest test.test_pdb.test_pdb_continue_in_bottomframe[0]>(8)test_function() + -> print(4) + (Pdb) continue + 4 + """ + + def test_main(): from test import test_pdb test_support.run_doctest(test_pdb, verbosity=True) @@ -24,6 +24,21 @@ Core and Builtins Library ------- +- Issue #5294: Fix the behavior of pdb's "continue" command when called + in the top-level debugged frame. + +- Issue #5727: Restore the ability to use readline when calling into pdb + in doctests. + +- Issue #6719: In pdb, do not stop somewhere in the encodings machinery + if the source file to be debugged is in a non-builtin encoding. + +- Issue #8048: Prevent doctests from failing when sys.displayhook has + been reassigned. + +- Issue #8015: In pdb, do not crash when an empty line is entered as + a breakpoint command. + - Issue #9448: Fix a leak of OS resources (mutexes or semaphores) when re-initializing a buffered IO object by calling its ``__init__`` method. diff --git a/Misc/maintainers.rst b/Misc/maintainers.rst index a80d8f2..825242f 100644 --- a/Misc/maintainers.rst +++ b/Misc/maintainers.rst @@ -151,7 +151,7 @@ optparse aronacher os loewis ossaudiodev parser -pdb +pdb georg.brandl pickle alexandre.vassalotti, pitrou pickletools alexandre.vassalotti pipes |