[IPython-dev] Detecting GUI mainloop running in IPython

Eric Firing efiring@hawaii....
Sun Jul 25 15:35:02 CDT 2010


On 07/25/2010 09:10 AM, Brian Granger wrote:
> Gael,
>
> Great questions.  The short answer is that the traditional methods of
> discovering if the event loop is running won't work.  This issue will
> become even more complicated with we implement GUI integration in the
> new 2 process frontend/kernel.  We still need to decide how we are going
> to handle this.  Here was the last email we sent out a long time ago
> that didn't really get any response:

Brian,

I've been looking at that old message for a couple of weeks, trying to 
figure out how to respond from the mpl perspective.  I'm still quite 
uncertain, and I would be pleased to see people with a better 
understanding of gui toolkits, event loops, and ipython step in.

Preliminary thoughts:

Although ipython has provided invaluable service to mpl by enabling 
interactive plotting for all gui backends, I am not at all sure that 
this functionality should be left to ipython in the long run.  The 
problem is that mpl is used in a variety of ways and environments.  Gui 
functionality is central to mpl; it seems odd, and unnecessarily 
complicated, to have to delegate part of that to an environment, or 
shell, like ipython.

At present, for most backends, interactive mpl plotting is possible in 
ipython without any of ipython's gui logic.  That is, running vanilla 
ipython one can:

In [1]: from pylab import *

In [2]: ion()

In [3]: plot([1,2,3])
Out[3]: [<matplotlib.lines.Line2D object at 0x3f3c350>]

and the plot appears with full interaction, courtesy of the 
PyOS_InputHook mechanism used by default in tk, gtk, and qt4.  If mpl 
simply adopted the new ipython code to add this capability to wx, then 
wx* backends would be included.  The advantage over leaving this in 
ipython is that it would give mpl more uniform behavior regardless of 
whether it is run in ipython or elsewhere.

Sometimes one wants mpl's show() to have blocking behavior.  At present 
it blocks when mpl is not in interactive mode.  The blocking is 
implemented by starting the gui event loop.

One very useful service ipython provides is enabling mpl scripts with 
show() to be run in non-blocking mode.  I think this would be even 
better if one could easily choose whether to respect the interactive 
setting.  Then, one could either run a script in ipython exactly as it 
would be run from the command line--that is, blocking at each show() if 
not in interactive mode--or one could run it as at present in pylab 
mode.  I think this could be done with simple modifications of the pylab 
mode code.

I have no idea how all this will be affected by the proposed two-process 
model for ipython.

>
> Current situation
> =============
>
> Both matplotlib and ets have code that tries to:
>
> * See what GUI toolkit is being used
> * Get the global App object if it already exists, if not create it.
> * See if the main loop is running, if not possibly start it.
>
> All of this logic makes many assumptions about how IPython affects the
> answers to these questions.  Because IPython's GUI support has changed
> in significant
> ways, current matplotlib and ets make incorrect decisions about these
> issues (such as trying to
> start the event loop a second time, creating a second main App ojbect,
> etc.) under IPython
> 0.11.  This leads to crashes...

This complexity is the reason why I would like to delegate all gui 
control back to mpl.

>
> Description of GUI support in 0.11
> ==========================
>
> IPython allows GUI event loops to be run in an interactive IPython session.
> This is done using Python's PyOS_InputHook hook which Python calls
> when the :func:`raw_input` function is called and is waiting for user input.
> IPython has versions of this hook for wx, pyqt4 and pygtk.  When the
> inputhook
> is called, it iterates the GUI event loop until a user starts to type
> again.  When the user stops typing, the event loop iterates again.  This
> is how tk works.
>
> When a GUI program is used interactively within IPython, the event loop of
> the GUI should *not* be started. This is because, the PyOS_Inputhook itself
> is responsible for iterating the GUI event loop.
>
> IPython has facilities for installing the needed input hook for each GUI
> toolkit and for creating the needed main GUI application object. Usually,
> these main application objects should be created only once and for some
> GUI toolkits, special options have to be passed to the application object
> to enable it to function properly in IPython.

I don't know anything about these options.  I think that presently, mpl 
is always making the app object--but it is hard to keep all this 
straight in my head.

>
> What we need to decide
> ===================
>
> We need to answer the following questions:
>
> * Who is responsible for creating the main GUI application object, IPython
>   or third parties (matplotlib, enthought.traits, etc.)?
>

At least for mpl, mpl always needs to be *able* to make it, since it 
can't depend on being run in ipython.  Therefore it seems simpler if mpl 
always *does* make it.

> * What is the proper way for third party code to detect if a GUI application
>   object has already been created?  If one has been created, how should
>   the existing instance be retrieved?
>

It would be simpler if third party code (mpl) did not *have* to do all 
this--if it could simply assume that it was responsible for creating and 
destroying the app object.  But maybe this is naive.


> * In a GUI application object has been created, how should third party code
>   detect if the GUI event loop is running. It is not sufficient to call the
>   relevant function methods in the GUI toolkits (like ``IsMainLoopRunning``)
>   because those don't know if the GUI event loop is running through the
>   input hook.
>

Again, it seems so much simpler if the third party code can be left in 
control of all this, so the question does not even arise.

> * We might need a way for third party code to determine if it is running
>   in IPython or not.  Currently, the only way of running GUI code in IPython
>   is by using the input hook, but eventually, GUI based versions of IPython
>   will allow the GUI event loop in the more traditional manner. We will need
>   a way for third party code to distinguish between these two cases.
>

What are the non-hook methods you have in mind?  Maybe this option makes 
my proposed, or hoped-for, simplification impossible.

> While we are focused on other things right now (the kernel/frontend) we
> would love to hear your thoughts on these issues.  Implementing a
> solution shouldn't be too difficult.

Another vague thought:  If we really need a more flexible environment, 
then maybe the way to achieve it is with a separate package or module 
that provides the API for collaboration between, e.g., ipython and mpl. 
  Perhaps all the toolkit-specific event loop code could be factored out 
and wrapped in a toolkit-neutral API.  Then, an mpl interactive backend 
would use this API regardless of whether mpl is running in a script, or 
inside ipython.  In the latter case, ipython would be using the same 
API, providing centralized knowledge of, and control over, the app 
object and the loop.  I think that such a refactoring, largely combining 
existing functionality in ipython and mpl, might not be terribly 
difficult, and might make future improvements in functionality much 
easier.  It would also make it easier for other libraries to plug into 
ipython, collaborate with mpl, etc.

Even if the idea above is sound--and it may be completely 
impractical--the devil is undoubtedly in the details.

Eric

>
> Cheers,
>
> Brian
>
>
>
> On Sun, Jul 25, 2010 at 11:10 AM, Gael Varoquaux
> <gael.varoquaux@normalesup.org <mailto:gael.varoquaux@normalesup.org>>
> wrote:
>
>     With the 0.11 series of IPython, I no longer understand how the
>     interaction with the GUI mainloop occurs:
>
>     ----------------------------------------------------------------------
>     $ ipython -wthread
>
>     In [1]: import wx
>
>     In [2]: wx.App.IsMainLoopRunning()
>     Out[2]: False
>     ----------------------------------------------------------------------
>
>     ----------------------------------------------------------------------
>     $ ipython -q4thread
>     In [1]: from PyQt4 import QtGui
>
>     In [2]: type(QtGui.QApplication.instance())
>     Out[2]: <type 'NoneType'>
>     ----------------------------------------------------------------------
>
>     Is there a mainloop running or not? If not, I really don't
>     understand how
>     I get interactivity with GUI windows and I'd love an explaination or a
>     pointer.
>
>     The problem with this behavior is that there is a lot of code that
>     checks
>     if a mainloop is running, and if not starts one. This code thus blocks
>     IPython and more or less defeats the purpose of the GUI options.
>
>     Cheers,
>
>     Gaël
>     _______________________________________________
>     IPython-dev mailing list
>     IPython-dev@scipy.org <mailto:IPython-dev@scipy.org>
>     http://mail.scipy.org/mailman/listinfo/ipython-dev
>
>
>
>
> --
> Brian E. Granger, Ph.D.
> Assistant Professor of Physics
> Cal Poly State University, San Luis Obispo
> bgranger@calpoly.edu <mailto:bgranger@calpoly.edu>
> ellisonbg@gmail.com <mailto:ellisonbg@gmail.com>
>
>
>
> _______________________________________________
> IPython-dev mailing list
> IPython-dev@scipy.org
> http://mail.scipy.org/mailman/listinfo/ipython-dev



More information about the IPython-dev mailing list