After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 524327 - Interactive PyGTK
Interactive PyGTK
Status: RESOLVED FIXED
Product: pygtk
Classification: Bindings
Component: general
2.12.x
Other All
: Normal enhancement
: ---
Assigned To: Nobody's working on this now (help wanted and appreciated)
Python bindings maintainers
Depends on:
Blocks:
 
 
Reported: 2008-03-25 15:46 UTC by Michiel de Hoon
Modified: 2008-09-11 19:44 UTC
See Also:
GNOME target: ---
GNOME version: Unversioned Enhancement


Attachments
Patch for gtk/gtk.override, gtk/__init__.py (2.96 KB, patch)
2008-03-25 15:48 UTC, Michiel de Hoon
none Details | Review
Update patch for gtk/gtk.override, gtk/__init__.py (2.71 KB, patch)
2008-04-01 13:01 UTC, Michiel de Hoon
committed Details | Review

Description Michiel de Hoon 2008-03-25 15:46:42 UTC
The attached patch allows PyGTK to be interactively, meaning that users can use PyGTK from the command prompt and have the event loop running without having to call gtk.mainloop(). So users can do
>>> import gtk
>>> window = gtk.Window()
>>> window.show()           # The window shows up immediately
>>> window.set_title("My new title")    # The title changes immediately
and so on, without ever having to call gtk.mainloop().

I have been using this patch for scientific visualization, but I think it is also useful for  people developing a GUI, as it allows them to try things from the command line and immediately see the result, without having to close the GUI they are working on.

Tkinter is also interactive in the same way; the proposed patch uses the same approach Tkinter. Essentially, PyOS_InputHook is used to start the event loop by calling gtk_main() just before Python starts waiting for the user to type in the next command at the Python prompt. Just before gtk_main is called, g_io_add_watch is used to add a watch on stdin. As soon as input is available on stdin, this watch causes a call to gtk_main_quit. Then gtk_main exits, and returning control to Python, which then proceeds to process the command the user typed in. Effectively, GTK's event loop is running whenever Python is not busy handling a user command.

From the user perspective, this patch adds one function set_interactive to gtk.
Calling gtk.set_interactive(True) installs the event loop; calling gtk.set_interactive(False) removes it. In gtk.__init__.py, gtk.set_interactive(True) is called if stdin is connected to a console.

I tested this patch on Windows, Cygwin, Mac OS X, Linux, and SunOS, and I have used it for my job for the past two years without problems. There is one caveat though: For this patch to work on Windows, it needs Glib version 2.13.0 or higher (current version of Glib is 2.16.1). For other platforms, there is no such requirement. This patch generates a RuntimeWarning if a user calls gtk.set_interactive(True) if Glib < 2.13.0 is detected on Windows.
Comment 1 Michiel de Hoon 2008-03-25 15:48:00 UTC
Created attachment 107998 [details] [review]
Patch for gtk/gtk.override, gtk/__init__.py
Comment 2 Johan (not receiving bugmail) Dahlin 2008-03-25 16:16:16 UTC
The idea is great and very simple.

I'm all for adding this kind of integration with the command line, assuming it will not break existing code (too badly).
Comment 3 Paul Pogonyshev 2008-03-26 19:00:17 UTC
Did you test that the patch works (I assume it does) only, or did you test that various PyGTK programs run fine with it too?  I too think it is a great addition to PyGTK, but we need to be sure it is safe, because it subtly touches almost everything.

If I understand correctly, it will set_interactive (True) if a program is just run from a console, not necessarily from interpreter.  This is potentially problematic if the patch introduces some subtle changes and it probably does.  Is there a better way to find out if we have some interactive Python loop running above?
Comment 4 Michiel de Hoon 2008-03-27 15:23:18 UTC
> Did you test that the patch works (I assume it does) only, or did you test that
> various PyGTK programs run fine with it too?  I too think it is a great
> addition to PyGTK, but we need to be sure it is safe, because it subtly touches
> almost everything.

I tried this patch on the PyGTK examples that are included with the pygtk distribution. I did not notice any problems there. Also, I have been using this patch for my own work for the past two years without any problems (admittedly, my experience is biased towards my own needs).

For typical PyGTK programs, the patch actually doesn't change anything. The added function set_interactive only sets the pointer-to-a-function PyOS_InputHook. Python calls PyOS_InputHook only when it is idle, i.e. when it does not have any commands to process. If script.py is a typical PyGTK program that ends with a call to gtk.main(), then Python will first execute the commands in script.py, and stays in gtk.main() without the loop in this patch ever being called.

Note also that if PyGTK is used interactively with this patch, and the loop in the patch is running, and then the user types gtk.main(), then the first thing that happens is that the patch-loop exits. Python then proceeds to execute gtk.main() in the usual way, which is not affected in any way by this patch.

> If I understand correctly, it will set_interactive (True) if a program is just
> run from a console, not necessarily from interpreter.  This is potentially
> problematic if the patch introduces some subtle changes and it probably does. 
> Is there a better way to find out if we have some interactive Python loop
> running above?

The check for sys.stdin.isatty() in gtk/__init__.py isn't actually needed. I was trying to keep this patch minimally intrusive to existing PyGTK programs.

Python calls PyOS_InputHook only if stdin is a console. So if PyOS_InputHook is set by set_interactive(True), but stdin is a not a console, then anyway PyOS_InputHook will never be called, so it doesn't matter.

In hindsight, the check for sys.stdin.isatty() is probably not even a good idea. It works fine with
python script.py
python -i script.py
python < script.py
python -i < script.py
but it gets confused with IDLE. In IDLE, there are two pythons; one python is running IDLE and one python is executing the user commands; they each have their own stdin. Since PyOS_InputHook doesn't get called in IDLE anyway, it doesn't matter if set_interactive(True) is called or not, but the call to sys.stdin.isatty() leads to a spurious warning message on IDLE.
(This discussion is relevant only if anybody is actually running PyGTK from IDLE).

Anyway, I should get back to your question. If Python is called from the console but not interactively, it means either
python script.py
or
python < script.py
In the second case, stdin is not a console, and Python will not call PyOS_InputHook.
In the first case, the commands in script.py are executed before PyOS_InputHook is called. If script.py ends with gtk.main(), then that's the end of it; the loop in the patch is not called. If script.py does not end with gtk.main(), python will simply exit once the end of script.py is reached.

Note also that Tkinter uses to same approach to get interactivity (run the Tkinter event loop, and step out of it if there is some input on stdin).


There is one point for which I need some clarification:

On Windows, this patch works only if GLib is version 2.13 or newer. On other platforms, there is no such requirement. In the current version of the patch, I am checking the GLib version in the C-code, and essentially ignore set_interactive(True) if GLib is too old on Windows.
It may be better to simply require (on Windows platforms) GLib > 2.13.0 in gtk/__init__.py. Or is that too drastic a change?
Comment 5 Michiel de Hoon 2008-04-01 13:01:49 UTC
Created attachment 108413 [details] [review]
Update patch for gtk/gtk.override, gtk/__init__.py

Updated patch for gtk/gtk.override, gtk/__init__.py. This patch does not contain the superfluous checks for stdin, and by default checks for GLib >= 2.13.0 on Windows. This patch was tested on Windows, Cygwin, Linux, and Mac OS X.
Comment 6 Paul Pogonyshev 2008-09-11 19:44:33 UTC
I committed the patch (only removed test for GLib version --- not needed anymore, we rely on that version anyway), it gives pretty impressive improvement for quick feature testing.  Let's hope this doesn't break anything.

Sending        ChangeLog
Sending        gtk/__init__.py
Sending        gtk/gtk.override
Transmitting file data ...
Committed revision 3042.

2008-09-11  Michiel de Hoon  <mjldehoon@yahoo.com>

	Bug 524327 – Interactive PyGTK

	* gtk/gtk.override (_main_quit, _loop, _wrap_set_interactive): New
	functions.

	* gtk/__init__.py: Make PyGTK interactive.