From 46b9afc862974e5855f0ca8a181096945483c86e Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Fri, 30 Jul 2010 09:14:20 +0000 Subject: [PATCH] #1472251: remove addition of "\n" to code given to pdb.run[eval](), the bug in exec() that made this necessary has been fixed. Also document that you can give code objects to run() and runeval(), and add some tests to test_pdb. --- Doc/library/pdb.rst | 22 ++++++++++----------- Lib/bdb.py | 9 +++------ Lib/test/test_pdb.py | 47 ++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 59 insertions(+), 19 deletions(-) diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index 4e79badd3c0..6da5332f532 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -85,21 +85,21 @@ slightly different way: .. function:: run(statement, globals=None, locals=None) - Execute the *statement* (given as a string) under debugger control. The - debugger prompt appears before any code is executed; you can set breakpoints - and type :pdbcmd:`continue`, or you can step through the statement using - :pdbcmd:`step` or :pdbcmd:`next` (all these commands are explained below). - The optional *globals* and *locals* arguments specify the environment in - which the code is executed; by default the dictionary of the module - :mod:`__main__` is used. (See the explanation of the built-in :func:`exec` - or :func:`eval` functions.) + Execute the *statement* (given as a string or a code object) under debugger + control. The debugger prompt appears before any code is executed; you can + set breakpoints and type :pdbcmd:`continue`, or you can step through the + statement using :pdbcmd:`step` or :pdbcmd:`next` (all these commands are + explained below). The optional *globals* and *locals* arguments specify the + environment in which the code is executed; by default the dictionary of the + module :mod:`__main__` is used. (See the explanation of the built-in + :func:`exec` or :func:`eval` functions.) .. function:: runeval(expression, globals=None, locals=None) - Evaluate the *expression* (given as a string) under debugger control. When - :func:`runeval` returns, it returns the value of the expression. Otherwise - this function is similar to :func:`run`. + Evaluate the *expression* (given as a string or a code object) under debugger + control. When :func:`runeval` returns, it returns the value of the + expression. Otherwise this function is similar to :func:`run`. .. function:: runcall(function, *args, **kwds) diff --git a/Lib/bdb.py b/Lib/bdb.py index cee71a41bd8..572e5913d43 100644 --- a/Lib/bdb.py +++ b/Lib/bdb.py @@ -364,8 +364,9 @@ def format_stack_entry(self, frame_lineno, lprefix=': '): if line: s = s + lprefix + line.strip() return s - # The following two methods can be called by clients to use - # a debugger to debug a statement, given as a string. + # The following methods can be called by clients to use + # a debugger to debug a statement or an expression. + # Both can be given as a string, or a code object. def run(self, cmd, globals=None, locals=None): if globals is None: @@ -375,8 +376,6 @@ def run(self, cmd, globals=None, locals=None): locals = globals self.reset() sys.settrace(self.trace_dispatch) - if not isinstance(cmd, types.CodeType): - cmd = cmd+'\n' try: exec(cmd, globals, locals) except BdbQuit: @@ -393,8 +392,6 @@ def runeval(self, expr, globals=None, locals=None): locals = globals self.reset() sys.settrace(self.trace_dispatch) - if not isinstance(expr, types.CodeType): - expr = expr+'\n' try: return eval(expr, globals, locals) except BdbQuit: diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 7af903d210d..4af8516bd98 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -1,5 +1,4 @@ -# A test suite for pdb; at the moment, this only validates skipping of -# specified test modules (RFE #5142). +# A test suite for pdb; not very comprehensive at the moment. import imp import sys @@ -123,6 +122,50 @@ def test_pdb_skip_modules_with_callback(): """ +def pdb_invoke(method, arg): + """Run pdb.method(arg).""" + import pdb; getattr(pdb, method)(arg) + + +def test_pdb_run_with_incorrect_argument(): + """Testing run and runeval with incorrect first argument. + + >>> pti = PdbTestInput(['continue',]) + >>> with pti: + ... pdb_invoke('run', lambda x: x) + Traceback (most recent call last): + TypeError: exec() arg 1 must be a string, bytes or code object + + >>> with pti: + ... pdb_invoke('runeval', lambda x: x) + Traceback (most recent call last): + TypeError: eval() arg 1 must be a string, bytes or code object + """ + + +def test_pdb_run_with_code_object(): + """Testing run and runeval with code object as a first argument. + + >>> with PdbTestInput(['step','x', 'continue']): + ... pdb_invoke('run', compile('x=1', '', 'exec')) + > (1)() + (Pdb) step + --Return-- + > (1)()->None + (Pdb) x + 1 + (Pdb) continue + + >>> with PdbTestInput(['x', 'continue']): + ... x=0 + ... pdb_invoke('runeval', compile('x+1', '', 'eval')) + > (1)()->None + (Pdb) x + 1 + (Pdb) continue + """ + + def test_main(): from test import test_pdb support.run_doctest(test_pdb, verbosity=True)