diff --git a/IPython/Extensions/ipy_winpdb.py b/IPython/Extensions/ipy_winpdb.py new file mode 100644 index 0000000..6992013 --- /dev/null +++ b/IPython/Extensions/ipy_winpdb.py @@ -0,0 +1,73 @@ +""" Debug a script (like %run -d) in IPython process, Using WinPdb + +Usage: + +%wdb test.py + run test.py, with a winpdb breakpoint at start of the file + +%wdb pass + Change the password (e.g. if you have forgotten the old one) +""" + +import os + +import IPython.ipapi +import rpdb2 + +ip = IPython.ipapi.get() + +rpdb_started = False + +def wdb_f(self, arg): + """ Debug a script (like %run -d) in IPython process, Using WinPdb + + Usage: + + %wdb test.py + run test.py, with a winpdb breakpoint at start of the file + + %wdb pass + Change the password (e.g. if you have forgotten the old one) + + Note that after the script has been run, you need to do "Go" (f5) + in WinPdb to resume normal IPython operation. + """ + + global rpdb_started + if not arg.strip(): + print __doc__ + return + + if arg.strip() == 'pass': + passwd = raw_input('Enter new winpdb session password: ') + ip.db['winpdb_pass'] = passwd + print "Winpdb password changed" + if rpdb_started: + print "You need to restart IPython to use the new password" + return + + path = os.path.abspath(arg) + if not os.path.isfile(path): + raise IPython.ipapi.UsageError("%%wdb: file %s does not exist" % path) + if not rpdb_started: + passwd = ip.db.get('winpdb_pass', None) + if passwd is None: + import textwrap + print textwrap.dedent("""\ + Winpdb sessions need a password that you use for attaching the external + winpdb session. IPython will remember this. You can change the password later + by '%wpdb pass' + """) + passwd = raw_input('Enter new winpdb session password: ') + ip.db['winpdb_pass'] = passwd + + print "Starting rpdb2 in IPython process" + rpdb2.start_embedded_debugger(passwd, timeout = 0) + rpdb_started = True + + rpdb2.set_temp_breakpoint(path) + print 'It is time to attach with WinPdb (launch WinPdb if needed, File -> Attach)' + ip.magic('%run ' + arg) + + +ip.expose_magic('wdb', wdb_f) diff --git a/IPython/UserConfig/ipy_user_conf.py b/IPython/UserConfig/ipy_user_conf.py index e1c00fe..e77abcc 100644 --- a/IPython/UserConfig/ipy_user_conf.py +++ b/IPython/UserConfig/ipy_user_conf.py @@ -87,6 +87,8 @@ def main(): # For bzr completer, requires bzrlib (the python installation of bzr) #import ipy_bzr + + # some config helper functions you can use def import_all(modules): """ Usage: import_all("os sys") """ diff --git a/IPython/gui/wx/ipshell_nonblocking.py b/IPython/gui/wx/ipshell_nonblocking.py index f3164d9..8d34ced 100644 --- a/IPython/gui/wx/ipshell_nonblocking.py +++ b/IPython/gui/wx/ipshell_nonblocking.py @@ -92,7 +92,7 @@ class NonBlockingIPShell(object): def __init__(self,argv=[],user_ns={},user_global_ns=None, cin=None, cout=None, cerr=None, - ask_exit_handler=None): + ask_exit_handler=None, rawinput=None): ''' @param argv: Command line options for IPython @type argv: list @@ -114,7 +114,7 @@ class NonBlockingIPShell(object): #ipython0 initialisation self.initIpython0(argv, user_ns, user_global_ns, cin, cout, cerr, - ask_exit_handler) + ask_exit_handler, rawinput) #vars used by _execute self._iter_more = 0 @@ -133,7 +133,7 @@ class NonBlockingIPShell(object): def initIpython0(self, argv=[], user_ns={}, user_global_ns=None, cin=None, cout=None, cerr=None, - ask_exit_handler=None): + ask_exit_handler=None, rawinput=None): #first we redefine in/out/error functions of IPython if cin: IPython.Shell.Term.cin = cin @@ -167,7 +167,8 @@ class NonBlockingIPShell(object): self._IP.set_hook('shell_hook',self._shell) #we replace the ipython default input command caller by our method - IPython.iplib.raw_input_original = self._raw_input + IPython.iplib.raw_input_original = rawinput + #we replace the ipython default exit command by our method self._IP.exit = ask_exit_handler #we replace the help command @@ -339,12 +340,6 @@ class NonBlockingIPShell(object): ''' pass - #def _askExit(self): - # ''' - # Can be redefined to generate post event to exit the Ipython shell - # ''' - # pass - def _getHistoryMaxIndex(self): ''' returns the max length of the history buffer @@ -385,18 +380,6 @@ class NonBlockingIPShell(object): ''' self._doc_text = text - def _raw_input(self, prompt=''): - ''' - Custom raw_input() replacement. Get's current line from console buffer. - - @param prompt: Prompt to print. Here for compatability as replacement. - @type prompt: string - - @return: The current command line text. - @rtype: string - ''' - return self._line_to_execute - def _execute(self): ''' Executes the current line provided by the shell object. diff --git a/IPython/gui/wx/ipython_view.py b/IPython/gui/wx/ipython_view.py index 9b700e8..310528f 100644 --- a/IPython/gui/wx/ipython_view.py +++ b/IPython/gui/wx/ipython_view.py @@ -47,11 +47,12 @@ class WxNonBlockingIPShell(NonBlockingIPShell): def __init__(self, parent, argv=[],user_ns={},user_global_ns=None, cin=None, cout=None, cerr=None, - ask_exit_handler=None): + ask_exit_handler=None, rawinput=None): NonBlockingIPShell.__init__(self,argv,user_ns,user_global_ns, cin, cout, cerr, - ask_exit_handler) + ask_exit_handler, + rawinput) self.parent = parent @@ -302,18 +303,6 @@ class WxConsoleView(stc.StyledTextCtrl): return self.GetTextRange(self.getCurrentPromptStart(), self.getCurrentLineEnd()) - def showReturned(self, text): - ''' - Show returned text from last command and print new prompt. - - @param text: Text to show. - @type text: string - ''' - self.write('\n'+text) - if text: - self.write('\n') - self.showPrompt() - def moveCursorOnNewValidKey(self): #If cursor is at wrong position put it at last line... if self.GetCurrentPos() < self.getCurrentPromptStart(): @@ -406,7 +395,7 @@ class WxConsoleView(stc.StyledTextCtrl): elif event.GetKeyCode() == wx.WXK_BACK: self.moveCursorOnNewValidKey() if self.getCursorPos() > self.getCurrentPromptStart(): - self.removeFromTo(self.getCursorPos()-1,self.getCursorPos()) + event.Skip() return True if skip: @@ -461,6 +450,7 @@ class IPShellWidget(wx.Panel): because it seems to be more useful Any idea to make it more 'generic' welcomed. ''' + def __init__(self, parent, intro=None, background_color="BLACK", add_button_handler=None, wx_ip_shell=None, @@ -475,15 +465,15 @@ class IPShellWidget(wx.Panel): ### IPython non blocking shell instanciation ### self.cout = StringIO() - self.add_button_handler = add_button_handler if wx_ip_shell is not None: self.IP = wx_ip_shell else: self.IP = WxNonBlockingIPShell(self, - cout = self.cout,cerr = self.cout, - ask_exit_handler = self.askExitCallback) + cout = self.cout, cerr = self.cout, + ask_exit_handler = self.askExitCallback, + rawinput = self.rawInput) ### IPython wx console view instanciation ### #If user didn't defined an intro text, we create one for him @@ -501,9 +491,11 @@ class IPShellWidget(wx.Panel): self.IP.getPrompt(), intro=welcome_text, background_color=background_color) + + self.cout.write = self.text_ctrl.write self.text_ctrl.Bind(wx.EVT_KEY_DOWN, self.keyPress, self.text_ctrl) - + ### making the layout of the panel ### sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.text_ctrl, 1, wx.EXPAND) @@ -525,6 +517,7 @@ class IPShellWidget(wx.Panel): def stateDoExecuteLine(self): #print >>sys.__stdout__,"command:",self.getCurrentLine() line=self.text_ctrl.getCurrentLine() + self.text_ctrl.write('\n') self.IP.doExecute((line.replace('\t',' '*4)).encode('cp1252')) self.updateHistoryTracker(self.text_ctrl.getCurrentLine()) self.setCurrentState('WAIT_END_OF_EXECUTION') @@ -550,19 +543,24 @@ class IPShellWidget(wx.Panel): self.text_ctrl.setPrompt(self.IP.getPrompt()) self.text_ctrl.setIndentation(self.IP.getIndentation()) self.text_ctrl.setPromptCount(self.IP.getPromptCount()) - rv = self.cout.getvalue() - if rv: rv = rv.strip('\n') - self.text_ctrl.showReturned(rv) - self.cout.truncate(0) + self.text_ctrl.showPrompt() self.IP.initHistoryIndex() self.setCurrentState('IDLE') def setCurrentState(self, state): self.cur_state = state self.updateStatusTracker(self.cur_state) - + #---------------------------- Ipython raw_input ----------------------------------- + def rawInput(self, prompt=''): + self.setCurrentState('WAITING_USER_INPUT') + while self.cur_state != 'WAIT_END_OF_EXECUTION': + pass + line = self.text_ctrl.getCurrentLine() + line = line.split('\n') + return line[-2] + #---------------------------- IPython pager --------------------------------------- - def pager(self,text):#,start=0,screen_lines=0,pager_cmd = None): + def pager(self,text): if self.pager_state == 'INIT': #print >>sys.__stdout__,"PAGER state:",self.pager_state @@ -635,13 +633,21 @@ class IPShellWidget(wx.Panel): self.pager(self.doc) return + if self.cur_state == 'WAITING_USER_INPUT': + line=self.text_ctrl.getCurrentLine() + self.text_ctrl.write('\n') + self.setCurrentState('WAIT_END_OF_EXECUTION') + return + if event.GetKeyCode() in [ord('q'),ord('Q')]: if self.pager_state == 'WAITING': self.pager_state = 'DONE' self.stateShowPrompt() return - - #scroll_position = self.text_ctrl.GetScrollPos(wx.VERTICAL) + + if self.cur_state == 'WAITING_USER_INPUT': + event.Skip() + if self.cur_state == 'IDLE': if event.KeyCode == wx.WXK_UP: history = self.IP.historyBack() @@ -669,7 +675,7 @@ class IPShellWidget(wx.Panel): return event.Skip() - + #------------------------ Hook Section ----------------------------------- def updateHistoryTracker(self,command_line): ''' diff --git a/IPython/gui/wx/wxIPython.py b/IPython/gui/wx/wxIPython.py index 2916875..a7c5e8e 100644 --- a/IPython/gui/wx/wxIPython.py +++ b/IPython/gui/wx/wxIPython.py @@ -36,8 +36,7 @@ class MyFrame(wx.Frame): self.ipython_panel = IPShellWidget(self,background_color = "BLACK") - #self.ipython_panel = WxIPythonViewPanel(self, - # background_color = "WHITE") + #self.ipython_panel = IPShellWidget(self,background_color = "WHITE") self.ipython_panel.setHistoryTrackerHook(self.history_panel.write) self.ipython_panel.setStatusTrackerHook(self.updateStatus) @@ -122,6 +121,7 @@ class MyFrame(wx.Frame): states = {'IDLE':'Idle', 'DO_EXECUTE_LINE':'Send command', 'WAIT_END_OF_EXECUTION':'Running command', + 'WAITING_USER_INPUT':'Waiting user input', 'SHOW_DOC':'Showing doc', 'SHOW_PROMPT':'Showing prompt'} self.statusbar.SetStatusText(states[text], 0)