Repository: ipython/ipython

Issue:
ipython console freezes for increasing no of seconds in %pylab mode
launching ipython just in console with `ipython`.
Am trying to reproduce bad editing (readline?) behavior now, looking at some functions, their help text etc. but it's all ok.
Then launching `%pylab`.
Typing in rubbish (like 'aoeuaoeaoeu') and can keep editing it without freezes.
But from the moment I type in a function name that exists, like `dir()` it even gets stuck before printing the `()`. From now on the cursor gets stuck every 5 seconds or so and keeps stuck for 2-3 seconds at a time, but that number is increasing.

Version abffd96eaa9c7
inside iTerm2 on Mac OSX.
Python 2.7.8 from conda



Discussion:
Forgot to say, I'm driving Qt4Agg usually:

``` python
n [1]: %pylab
Using matplotlib backend: Qt4Agg
Populating the interactive namespace from numpy and matplotlib
```

Interestingly, going back to rel-2.1.0 does not solve this.

I went back as far as 1.2 and it still happens in the terminal ipython.
Then went back to master, tried out `ipython qtconsole` and it's all fine there. I'm amazed I did not find this problem before, but I'm a heavy notebook user, so maybe that explains that. :)

We've had some issues with the Qt backend readline interacting before, though I can't find the issue number just at the moment.

This is a severe problem, and I have reproduced it with nothing more than

```
ipython
%gui qt
```

so it is not matplotlib-specific.  To see it on Mavericks, with either Homebrew or Anaconda python 3.4.1 and PyQt4, just start a console as above, then go away and do something elsewhere for a few minutes.  When you come back, chances are the session will be unusable because of delayed response to attempts to type or scroll through history.  It's somewhat erratic, but qualitatively repeatable.  In my case, testing is with a plain Apple terminal window (with focus follows mouse), not with ITerm2.

@takluyver, The earlier issue involving qt and readline is #481.  Despite the issue title, it involved more than just XP.  More than one distinct problem was discussed in that issue, but the primary one involved the input hook for qt.

A workaround is to use the qtconsole; at least in a little bit of testing, it seems to maintain full responsiveness.


Resolving patch:
diff --git a/IPython/lib/inputhook.py b/IPython/lib/inputhook.py
--- a/IPython/lib/inputhook.py
+++ b/IPython/lib/inputhook.py
@@ -104,7 +104,7 @@ class InputHookManager(object):
     This class installs various hooks under ``PyOSInputHook`` to handle
     GUI event loop integration.
     """
-    
+
     def __init__(self):
         if ctypes is None:
             warn("IPython GUI event loop requires ctypes, %gui will not be available")
@@ -204,14 +204,16 @@ def enable_wx(self, app=None):
             app = wx.App(redirect=False, clearSigInt=False)
         """
         import wx
-        
+
         wx_version = V(wx.__version__).version
-        
+
         if wx_version < [2, 8]:
             raise ValueError("requires wxPython >= 2.8, but you have %s" % wx.__version__)
-        
+
         from IPython.lib.inputhookwx import inputhook_wx
+        from IPython.external.appnope import nope
         self.set_inputhook(inputhook_wx)
+        nope()
         self._current_gui = GUI_WX
         import wx
         if app is None:
@@ -227,13 +229,15 @@ def disable_wx(self):
 
         This merely sets PyOS_InputHook to NULL.
         """
+        from IPython.external.appnope import nap
         if GUI_WX in self._apps:
             self._apps[GUI_WX]._in_event_loop = False
         self.clear_inputhook()
+        nap()
 
     def enable_qt4(self, app=None):
         """Enable event loop integration with PyQt4.
-        
+
         Parameters
         ----------
         app : Qt Application, optional.
@@ -254,8 +258,10 @@ def enable_qt4(self, app=None):
             app = QtGui.QApplication(sys.argv)
         """
         from IPython.lib.inputhookqt4 import create_inputhook_qt4
+        from IPython.external.appnope import nope
         app, inputhook_qt4 = create_inputhook_qt4(self, app)
         self.set_inputhook(inputhook_qt4)
+        nope()
 
         self._current_gui = GUI_QT4
         app._in_event_loop = True
@@ -267,9 +273,11 @@ def disable_qt4(self):
 
         This merely sets PyOS_InputHook to NULL.
         """
+        from IPython.external.appnope import nap
         if GUI_QT4 in self._apps:
             self._apps[GUI_QT4]._in_event_loop = False
         self.clear_inputhook()
+        nap()
 
     def enable_gtk(self, app=None):
         """Enable event loop integration with PyGTK.
@@ -299,7 +307,7 @@ def enable_gtk(self, app=None):
 
     def disable_gtk(self):
         """Disable event loop integration with PyGTK.
-        
+
         This merely sets PyOS_InputHook to NULL.
         """
         self.clear_inputhook()
@@ -333,7 +341,7 @@ def enable_tk(self, app=None):
 
     def disable_tk(self):
         """Disable event loop integration with Tkinter.
-        
+
         This merely sets PyOS_InputHook to NULL.
         """
         self.clear_inputhook()
@@ -359,7 +367,7 @@ def enable_glut(self, app=None):
         without first creating a window. You should thus not create another
         window but use instead the created one. See 'gui-glut.py' in the
         docs/examples/lib directory.
-        
+
         The default screen mode is set to:
         glut.GLUT_DOUBLE | glut.GLUT_RGBA | glut.GLUT_DEPTH
         """
@@ -393,7 +401,7 @@ def enable_glut(self, app=None):
 
     def disable_glut(self):
         """Disable event loop integration with glut.
-        
+
         This sets PyOS_InputHook to NULL and set the display function to a
         dummy one and set the timer to a dummy timer that will be triggered
         very far in the future.


Test patch: