From 604e583740928d53b449b3c266c617c37726ef55 2006-11-30 05:22:31 From: fperez Date: 2006-11-30 05:22:31 Subject: [PATCH] Add new %debug magic, activates the interactive debugger immediately on the last traceback without having to rerun any code. --- diff --git a/IPython/Magic.py b/IPython/Magic.py index 1ce864d..fa27c88 100644 --- a/IPython/Magic.py +++ b/IPython/Magic.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """Magic functions for InteractiveShell. -$Id: Magic.py 1941 2006-11-26 22:24:43Z vivainio $""" +$Id: Magic.py 1956 2006-11-30 05:22:31Z fperez $""" #***************************************************************************** # Copyright (C) 2001 Janko Hauser and @@ -1164,14 +1164,21 @@ Currently the magic system has the following functions:\n""" self.shell.logger.logstate() def magic_pdb(self, parameter_s=''): - """Control the calling of the pdb interactive debugger. + """Control the automatic calling of the pdb interactive debugger. Call as '%pdb on', '%pdb 1', '%pdb off' or '%pdb 0'. If called without argument it works as a toggle. When an exception is triggered, IPython can optionally call the interactive pdb debugger after the traceback printout. %pdb toggles - this feature on and off.""" + this feature on and off. + + The initial state of this feature is set in your ipythonrc + configuration file (the variable is called 'pdb'). + + If you want to just activate the debugger AFTER an exception has fired, + without having to type '%pdb on' and rerunning your code, you can use + the %debug magic.""" par = parameter_s.strip().lower() @@ -1184,12 +1191,27 @@ Currently the magic system has the following functions:\n""" return else: # toggle - new_pdb = not self.shell.InteractiveTB.call_pdb + new_pdb = not self.shell.call_pdb # set on the shell self.shell.call_pdb = new_pdb print 'Automatic pdb calling has been turned',on_off(new_pdb) + def magic_debug(self, parameter_s=''): + """Activate the interactive debugger in post-mortem mode. + + If an exception has just occurred, this lets you inspect its stack + frames interactively. Note that this will always work only on the last + traceback that occurred, so you must call this quickly after an + exception that you wish to inspect has fired, because if another one + occurs, it clobbers the previous one. + + If you want IPython to automatically do this on every exception, see + the %pdb magic for more details. + """ + + self.shell.debugger(force=True) + def magic_prun(self, parameter_s ='',user_mode=1, opts=None,arg_lst=None,prog_ns=None): diff --git a/IPython/iplib.py b/IPython/iplib.py index 29d1ce4..bce0905 100644 --- a/IPython/iplib.py +++ b/IPython/iplib.py @@ -6,7 +6,7 @@ Requires Python 2.3 or newer. This file contains all the classes and helper functions specific to IPython. -$Id: iplib.py 1935 2006-11-26 20:42:29Z vivainio $ +$Id: iplib.py 1956 2006-11-30 05:22:31Z fperez $ """ #***************************************************************************** @@ -1412,20 +1412,31 @@ want to merge them back into the new files.""" % locals() value = msg, (filename, lineno, offset, line) self.SyntaxTB(etype,value,[]) - def debugger(self): - """Call the pydb/pdb debugger.""" + def debugger(self,force=False): + """Call the pydb/pdb debugger. - if not self.rc.pdb: + Keywords: + + - force(False): by default, this routine checks the instance call_pdb + flag and does not actually invoke the debugger if the flag is false. + The 'force' option forces the debugger to activate even if the flag + is false. + """ + + if not (force or self.call_pdb): return + have_pydb = False if sys.version[:3] >= '2.5': + # use pydb if available try: from pydb import pm have_pydb = True except ImportError: pass if not have_pydb: - from pdb import pm + # fallback to our internal debugger + pm = lambda : self.InteractiveTB.debugger(force=True) self.history_saving_wrapper(pm)() def showtraceback(self,exc_tuple = None,filename=None,tb_offset=None): diff --git a/IPython/ultraTB.py b/IPython/ultraTB.py index 5455086..9d02773 100644 --- a/IPython/ultraTB.py +++ b/IPython/ultraTB.py @@ -60,7 +60,7 @@ You can implement other color schemes easily, the syntax is fairly self-explanatory. Please send back new schemes you develop to the author for possible inclusion in future releases. -$Id: ultraTB.py 1787 2006-09-27 06:56:29Z fperez $""" +$Id: ultraTB.py 1956 2006-11-30 05:22:31Z fperez $""" #***************************************************************************** # Copyright (C) 2001 Nathaniel Gray @@ -666,8 +666,16 @@ class VerboseTB(TBTools): # return all our info assembled as a single string return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) ) - def debugger(self): - """Call up the pdb debugger if desired, always clean up the tb reference. + def debugger(self,force=False): + """Call up the pdb debugger if desired, always clean up the tb + reference. + + Keywords: + + - force(False): by default, this routine checks the instance call_pdb + flag and does not actually invoke the debugger if the flag is false. + The 'force' option forces the debugger to activate even if the flag + is false. If the call_pdb flag is set, the pdb interactive debugger is invoked. In all cases, the self.tb reference to the current traceback @@ -678,7 +686,7 @@ class VerboseTB(TBTools): requires a special setup for the readline completers, you'll have to fix that by hand after invoking the exception handler.""" - if self.call_pdb: + if force or self.call_pdb: if self.pdb is None: self.pdb = Debugger.Pdb( self.color_scheme_table.active_scheme_name) @@ -688,7 +696,10 @@ class VerboseTB(TBTools): sys.displayhook = sys.__displayhook__ self.pdb.reset() # Find the right frame so we don't pop up inside ipython itself - etb = self.tb + if hasattr(self,'tb'): + etb = self.tb + else: + etb = self.tb = sys.last_traceback while self.tb.tb_next is not None: self.tb = self.tb.tb_next try: @@ -696,12 +707,11 @@ class VerboseTB(TBTools): etb = etb.tb_next self.pdb.botframe = etb.tb_frame self.pdb.interaction(self.tb.tb_frame, self.tb) - except: - print '*** ERROR ***' - print 'This version of pdb has a bug and crashed.' - print 'Returning to IPython...' - sys.displayhook = dhook - del self.tb + finally: + sys.displayhook = dhook + + if hasattr(self,'tb'): + del self.tb def handler(self, info=None): (etype, evalue, etb) = info or sys.exc_info() diff --git a/doc/ChangeLog b/doc/ChangeLog index 0aa3ad8..d5da663 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,4 +1,11 @@ -2006-11-2(8 Ville Vainio +2006-11-29 Fernando Perez + + * IPython/Magic.py (magic_debug): new %debug magic to activate the + interactive debugger on the last traceback, without having to call + %pdb and rerun your code. Made minor changes in various modules, + should automatically recognize pydb if available. + +2006-11-28 Ville Vainio * completer.py: If the text start with !, show file completions properly. This helps when trying to complete command name