diff --git a/IPython/gui/wx/ipython_view.py b/IPython/gui/wx/ipython_view.py index 599d7d6..6f0f42a 100644 --- a/IPython/gui/wx/ipython_view.py +++ b/IPython/gui/wx/ipython_view.py @@ -50,30 +50,34 @@ class WxNonBlockingIPShell(NonBlockingIPShell): def __init__(self,wx_instance, argv=[],user_ns={},user_global_ns=None, cin=None, cout=None, cerr=None, - exit_handler=None,time_loop = 0.1): + ask_exit_handler=None): - user_ns['addGUIShortcut'] = self.addGUIShortcut + #user_ns['addGUIShortcut'] = self.addGUIShortcut NonBlockingIPShell.__init__(self,argv,user_ns,user_global_ns, cin, cout, cerr, - exit_handler,time_loop) + ask_exit_handler) # This creates a new Event class and a EVT binder function (self.IPythonAskExitEvent, EVT_IP_ASK_EXIT) = wx.lib.newevent.NewEvent() - (self.IPythonAddButtonEvent, EVT_IP_ADD_BUTTON_EXIT) = wx.lib.newevent.NewEvent() - (self.IPythonExecuteDoneEvent, EVT_IP_EXECUTE_DONE) = wx.lib.newevent.NewEvent() + (self.IPythonAddButtonEvent, EVT_IP_ADD_BUTTON_EXIT) = \ + wx.lib.newevent.NewEvent() + (self.IPythonExecuteDoneEvent, EVT_IP_EXECUTE_DONE) = \ + wx.lib.newevent.NewEvent() - wx_instance.Bind(EVT_IP_ASK_EXIT, wx_instance.exit_handler) + wx_instance.Bind(EVT_IP_ASK_EXIT, wx_instance.ask_exit_handler) wx_instance.Bind(EVT_IP_ADD_BUTTON_EXIT, wx_instance.add_button_handler) wx_instance.Bind(EVT_IP_EXECUTE_DONE, wx_instance.evtStateExecuteDone) self.wx_instance = wx_instance - self._IP.exit = self._AskExit + self._IP.ask_exit = self._askExit def addGUIShortcut(self,text,func): - evt = self.IPythonAddButtonEvent(button_info={'text':text,'func':self.wx_instance.doExecuteLine(func)}) + evt = self.IPythonAddButtonEvent( + button_info={ 'text':text, + 'func':self.wx_instance.doExecuteLine(func)}) wx.PostEvent(self.wx_instance, evt) - def _AskExit(self): + def _askExit(self): evt = self.IPythonAskExitEvent() wx.PostEvent(self.wx_instance, evt) @@ -463,7 +467,8 @@ class WxIPythonViewPanel(wx.Panel): I've choosed to derivate from a wx.Panel because it seems to be ore usefull Any idea to make it more 'genric' welcomed. ''' - def __init__(self, parent, exit_handler=None, intro=None, + + def __init__(self, parent, ask_exit_handler=None, intro=None, background_color="BLACK", add_button_handler=None, wx_ip_shell=None, ): @@ -479,17 +484,14 @@ class WxIPythonViewPanel(wx.Panel): self.cout = StringIO() self.add_button_handler = add_button_handler - self.exit_handler = exit_handler + self.ask_exit_handler = ask_exit_handler if wx_ip_shell is not None: self.IP = wx_ip_shell else: self.IP = WxNonBlockingIPShell(self, cout=self.cout,cerr=self.cout, - exit_handler = exit_handler, - time_loop = 0.1) - self.IP.start() - + ask_exit_handler = ask_exit_handler) ### IPython wx console view instanciation ### #If user didn't defined an intro text, we create one for him #If you really wnat an empty intrp just call wxIPythonViewPanel with intro='' @@ -541,8 +543,6 @@ class WxIPythonViewPanel(wx.Panel): #self.Bind(wx.EVT_IDLE, self.runStateMachine) def __del__(self): - self.IP.shutdown() - self.IP.join() WxConsoleView.__del__() #---------------------------- IPython Thread Management --------------------------------------- @@ -705,7 +705,7 @@ class WxIPythonViewPanel(wx.Panel): if event.Modifiers == wx.MOD_CONTROL: if self.cur_state == 'WAIT_END_OF_EXECUTION': #we raise an exception inside the IPython thread container - self.IP.raise_exc(KeyboardInterrupt) + self.IP.ce.raise_exc(KeyboardInterrupt) return if event.KeyCode == wx.WXK_RETURN: diff --git a/IPython/gui/wx/non_blocking_ip_shell.py b/IPython/gui/wx/non_blocking_ip_shell.py index 9336465..c973fb5 100644 --- a/IPython/gui/wx/non_blocking_ip_shell.py +++ b/IPython/gui/wx/non_blocking_ip_shell.py @@ -31,16 +31,19 @@ try: except Exception,e: raise "Error importing IPython (%s)" % str(e) +############################################################################## class _Helper(object): """Redefine the built-in 'help'. This is a wrapper around pydoc.help (with a twist). """ + def __init__(self,pager): self._pager = pager def __repr__(self): return "Type help() for interactive help, " \ "or help(object) for help about object." + def __call__(self, *args, **kwds): class DummyWriter(object): def __init__(self,pager): @@ -57,20 +60,41 @@ class _Helper(object): return pydoc.help(*args, **kwds) -class NonBlockingIPShell(ThreadEx): +############################################################################## +class _CodeExecutor(ThreadEx): + + def __init__(self, instance, after): + ThreadEx.__init__(self) + self.instance = instance + self._afterExecute=after + + def run(self): + try: + self.instance._doc_text = None + self.instance._help_text = None + self.instance._execute() + # used for uper class to generate event after execution + self._afterExecute() + + except KeyboardInterrupt: + pass + + +############################################################################## +class NonBlockingIPShell(object): ''' - Create an IPython instance inside a dedicated thread. - Does not start a blocking event loop, instead allow single iterations. + Create an IPython instance, running the commands in a separate, + non-blocking thread. This allows embedding in any GUI without blockage. - The thread is a slave one, in that it doesn't interact directly with the GUI. - Note ThreadEx class supports asynchroneous function call - via raise_exc() + + Note: The ThreadEx class supports asynchroneous function call + via raise_exc() ''' def __init__(self,argv =[],user_ns={},user_global_ns=None, cin=None, cout=None, cerr=None, - exit_handler=None,time_loop = 0.1): + ask_exit_handler=None): ''' @param argv: Command line options for IPython @type argv: list @@ -89,8 +113,6 @@ class NonBlockingIPShell(ThreadEx): @param time_loop: Define the sleep time between two thread's loop @type int ''' - ThreadEx.__init__(self) - #first we redefine in/out/error functions of IPython if cin: IPython.Shell.Term.cin = cin @@ -127,7 +149,11 @@ class NonBlockingIPShell(ThreadEx): IPython.iplib.raw_input_original = self._raw_input #we replace the ipython default exit command by our method self._IP.exit = self._setAskExit - + #we modify Exit and Quit Magic + ip = IPython.ipapi.get() + ip.expose_magic('Exit', self._setDoExit) + ip.expose_magic('Quit', self._setDoExit) + sys.excepthook = excepthook self._iter_more = 0 @@ -136,9 +162,6 @@ class NonBlockingIPShell(ThreadEx): self._prompt = str(self._IP.outputcache.prompt1).strip() #thread working vars - self._terminate = False - self._time_loop = time_loop - self._do_execute = False self._line_to_execute = '' #vars that will be checked by GUI loop to handle thread states... @@ -152,46 +175,16 @@ class NonBlockingIPShell(ThreadEx): self._IP.user_ns['help'] = _Helper(self._pager_help) #----------------------- Thread management section ---------------------- - def run (self): - """ - Thread main loop - The thread will run until self._terminate will be set to True via shutdown() function - Command processing can be interrupted with Instance.raise_exc(KeyboardInterrupt) call in the - GUI thread. - """ - while(not self._terminate): - try: - if self._do_execute: - self._doc_text = None - self._help_text = None - self._execute() - self._do_execute = False - self._afterExecute() #used for uper class to generate event after execution - - except KeyboardInterrupt: - pass - - time.sleep(self._time_loop) - - def shutdown(self): - """ - Shutdown the tread - """ - self._terminate = True - def doExecute(self,line): """ Tell the thread to process the 'line' command """ - self._do_execute = True + self._line_to_execute = line + + self.ce = _CodeExecutor(self,self._afterExecute) + self.ce.start() - def isExecuteDone(self): - """ - Returns the processing state - """ - return not self._do_execute - #----------------------- IPython management section ---------------------- def getAskExit(self): ''' @@ -351,7 +344,7 @@ class NonBlockingIPShell(ThreadEx): ''' self._history_level = self._getHistoryMaxIndex()+1 - #----------------------- IPython PRIVATE management section ---------------------- + #----------------------- IPython PRIVATE management section -------------- def _afterExecute(self): ''' Can be redefined to generate post event after excution is done @@ -360,10 +353,17 @@ class NonBlockingIPShell(ThreadEx): def _setAskExit(self): ''' - set the _ask_exit variable that can be cjhecked by GUI to see if + set the _ask_exit variable that can be checked by GUI to see if IPython request an exit handling ''' self._ask_exit = True + + def _setDoExit(self, toto, arg): + ''' + set the _do_exit variable that can be checked by GUI to see if + IPython do a direct exit of the app + ''' + self._do_exit = True def _getHistoryMaxIndex(self): ''' @@ -378,7 +378,7 @@ class NonBlockingIPShell(ThreadEx): ''' Get's the command string of the current history level. - @return: Historic command string. + @return: Historic command stri @rtype: string ''' rv = self._IP.input_hist_raw[self._history_level].strip('\n')