[Python-Dev] Event loops, PyOS_InputHook, and Tkinter

Noam Raphael noamraph at gmail.com
Sat Nov 12 20:06:59 CET 2005


On 11/12/05, skip at pobox.com <skip at pobox.com> wrote:
> If I have a Gtk app I have to feed other (socket, callback) pairs to it.  It
> takes care of adding it to the select() call.  Python could dictate that the
> way to play ball is for other packages (Tkinter, PyGtk, wxPython, etc) to
> feed Python the (socket, callback) pair.  Then you have a uniform way to
> control event-driven applications.  Today, a package like Michiel's has no
> idea what sort of event loop it will encounter.  If Python provided the
> event loop API it would be the same no matter what widget set happened to be
> used.
>
> The sticking point is probably that a number of such packages presume they
> will always provide the main event loop and have to way to feed their
> sockets to another event loop controller.  That might present some hurdles
> for the various package writers/Python wrappers.
>
I think that in order to solve Michiels' problem, there's no need for
something like that, since probably neither of the "loops" are
listening to sockets.

Currently, Tkinter sets PyOS_InputHook to call its "dooneevent"
repeatedly while Python code isn't being executed. It turns out to
work excellently. All that is needed to make Tkinter and Michiels'
code run together is a way to say "add this callback to the input
hook" instead of the current "replace the current input hook with this
callback". Then, when the interpreter is idle, it will call all the
registered callbacks, one at a time, and everyone would be happy.

To make this work with IDLE, or other interactive shells written in
Python, you need to expose a function which will run all the
registered callbacks. Then IDLE can call that function repeatedly when
it's idle, and you'll get the same behaviour you have in the regular
interactive shell. Specifically for IDLE, I know where that place is -
since there's no way to generally invoke the input hook, I wrote a
patch that calls _tkinter.dooneevent(_tkinter.DONT_WAIT) in the right
place, and it works fine.

Concerning threads - please don't. The "do one event at a time while
the interpreter is idle" method works fine. Most programs aren't
designed to be thread-safe, and since Tkinter does many callbacks to
Python functions, you'll get unexpected behaviour if it's on another
thread.

I hope I made myself clear. This solution is simple, and works
whenever a "do one event" function is available.

Have a good week,
Noam


More information about the Python-Dev mailing list