##// END OF EJS Templates
Clarify event loop support in Term/Kernel
Jeremy Sikes -
Show More
@@ -1,103 +1,108 b''
1 ================================
1 ================================
2 Integrating with GUI event loops
2 Integrating with GUI event loops
3 ================================
3 ================================
4
4
5 When the user types ``%gui qt``, IPython integrates itself with the Qt event
5 When the user types ``%gui qt``, IPython integrates itself with the Qt event
6 loop, so you can use both a GUI and an interactive prompt together. IPython
6 loop, so you can use both a GUI and an interactive prompt together. IPython
7 supports a number of common GUI toolkits, but from IPython 3.0, it is possible
7 supports a number of common GUI toolkits, but from IPython 3.0, it is possible
8 to integrate other event loops without modifying IPython itself.
8 to integrate other event loops without modifying IPython itself.
9
9
10 Supported event loops include ``qt4``, ``qt5``, ``gtk2``, ``gtk3``, ``wx``,
10 Supported event loops include ``qt4``, ``qt5``, ``gtk2``, ``gtk3``, ``wx``,
11 ``osx`` and ``tk``. Make sure the event loop you specify matches the GUI
11 ``osx`` and ``tk``. Make sure the event loop you specify matches the GUI
12 toolkit used by your own code.
12 toolkit used by your own code.
13
13
14 To make IPython GUI event loop integration occur automatically at every
14 To make IPython GUI event loop integration occur automatically at every
15 startup, set the ``c.InteractiveShellApp.gui`` configuration key in your
15 startup, set the ``c.InteractiveShellApp.gui`` configuration key in your
16 IPython profile (see :ref:`setting_config`).
16 IPython profile (see :ref:`setting_config`).
17
17
18 Terminal IPython handles event loops very differently from the IPython kernel,
18 If the event loop you use is supported by IPython, turning on event loop
19 so different steps are needed to integrate with each.
19 integration follows the steps just described whether you use Terminal IPython
20 or an IPython kernel.
20
21
21 Event loops in the terminal
22 However, the way Terminal IPython handles event loops is very different from
22 ---------------------------
23 the way IPython kernel does, so if you need to integrate with a new kind of
24 event loop, different steps are needed to integrate with each.
25
26 Integrating with a new event loop in the terminal
27 -------------------------------------------------
23
28
24 .. versionchanged:: 5.0
29 .. versionchanged:: 5.0
25
30
26 There is a new API for event loop integration using prompt_toolkit.
31 There is a new API for event loop integration using prompt_toolkit.
27
32
28 In the terminal, IPython uses prompt_toolkit to prompt the user for input.
33 In the terminal, IPython uses prompt_toolkit to prompt the user for input.
29 prompt_toolkit provides hooks to integrate with an external event loop.
34 prompt_toolkit provides hooks to integrate with an external event loop.
30
35
31 To integrate an event loop, define a function which runs the GUI event loop
36 To integrate an event loop, define a function which runs the GUI event loop
32 until there is input waiting for prompt_toolkit to process. There are two ways
37 until there is input waiting for prompt_toolkit to process. There are two ways
33 to detect this condition::
38 to detect this condition::
34
39
35 # Polling for input.
40 # Polling for input.
36 def inputhook(context):
41 def inputhook(context):
37 while not context.input_is_ready():
42 while not context.input_is_ready():
38 # Replace this with the appropriate call for the event loop:
43 # Replace this with the appropriate call for the event loop:
39 iterate_loop_once()
44 iterate_loop_once()
40
45
41 # Using a file descriptor to notify the event loop to stop.
46 # Using a file descriptor to notify the event loop to stop.
42 def inputhook2(context):
47 def inputhook2(context):
43 fd = context.fileno()
48 fd = context.fileno()
44 # Replace the functions below with those for the event loop.
49 # Replace the functions below with those for the event loop.
45 add_file_reader(fd, callback=stop_the_loop)
50 add_file_reader(fd, callback=stop_the_loop)
46 run_the_loop()
51 run_the_loop()
47
52
48 Once you have defined this function, register it with IPython:
53 Once you have defined this function, register it with IPython:
49
54
50 .. currentmodule:: IPython.terminal.pt_inputhooks
55 .. currentmodule:: IPython.terminal.pt_inputhooks
51
56
52 .. function:: register(name, inputhook)
57 .. function:: register(name, inputhook)
53
58
54 Register the function *inputhook* as the event loop integration for the
59 Register the function *inputhook* as the event loop integration for the
55 GUI *name*. If ``name='foo'``, then the user can enable this integration
60 GUI *name*. If ``name='foo'``, then the user can enable this integration
56 by running ``%gui foo``.
61 by running ``%gui foo``.
57
62
58
63
59 Event loops in the kernel
64 Integrating with a new event loop in the kernel
60 -------------------------
65 -----------------------------------------------
61
66
62 The kernel runs its own event loop, so it's simpler to integrate with others.
67 The kernel runs its own event loop, so it's simpler to integrate with others.
63 IPython allows the other event loop to take control, but it must call
68 IPython allows the other event loop to take control, but it must call
64 :meth:`IPython.kernel.zmq.kernelbase.Kernel.do_one_iteration` periodically.
69 :meth:`IPython.kernel.zmq.kernelbase.Kernel.do_one_iteration` periodically.
65
70
66 To integrate with this, write a function that takes a single argument,
71 To integrate with this, write a function that takes a single argument,
67 the IPython kernel instance, arranges for your event loop to call
72 the IPython kernel instance, arranges for your event loop to call
68 ``kernel.do_one_iteration()`` at least every ``kernel._poll_interval`` seconds,
73 ``kernel.do_one_iteration()`` at least every ``kernel._poll_interval`` seconds,
69 and starts the event loop.
74 and starts the event loop.
70
75
71 Decorate this function with :func:`IPython.kernel.zmq.eventloops.register_integration`,
76 Decorate this function with :func:`IPython.kernel.zmq.eventloops.register_integration`,
72 passing in the names you wish to register it for. Here is a slightly simplified
77 passing in the names you wish to register it for. Here is a slightly simplified
73 version of the Tkinter integration already included in IPython::
78 version of the Tkinter integration already included in IPython::
74
79
75 @register_integration('tk')
80 @register_integration('tk')
76 def loop_tk(kernel):
81 def loop_tk(kernel):
77 """Start a kernel with the Tk event loop."""
82 """Start a kernel with the Tk event loop."""
78 from tkinter import Tk
83 from tkinter import Tk
79
84
80 # Tk uses milliseconds
85 # Tk uses milliseconds
81 poll_interval = int(1000*kernel._poll_interval)
86 poll_interval = int(1000*kernel._poll_interval)
82 # For Tkinter, we create a Tk object and call its withdraw method.
87 # For Tkinter, we create a Tk object and call its withdraw method.
83 class Timer(object):
88 class Timer(object):
84 def __init__(self, func):
89 def __init__(self, func):
85 self.app = Tk()
90 self.app = Tk()
86 self.app.withdraw()
91 self.app.withdraw()
87 self.func = func
92 self.func = func
88
93
89 def on_timer(self):
94 def on_timer(self):
90 self.func()
95 self.func()
91 self.app.after(poll_interval, self.on_timer)
96 self.app.after(poll_interval, self.on_timer)
92
97
93 def start(self):
98 def start(self):
94 self.on_timer() # Call it once to get things going.
99 self.on_timer() # Call it once to get things going.
95 self.app.mainloop()
100 self.app.mainloop()
96
101
97 kernel.timer = Timer(kernel.do_one_iteration)
102 kernel.timer = Timer(kernel.do_one_iteration)
98 kernel.timer.start()
103 kernel.timer.start()
99
104
100 Some event loops can go one better, and integrate checking for messages on the
105 Some event loops can go one better, and integrate checking for messages on the
101 kernel's ZMQ sockets, making the kernel more responsive than plain polling. How
106 kernel's ZMQ sockets, making the kernel more responsive than plain polling. How
102 to do this is outside the scope of this document; if you are interested, look at
107 to do this is outside the scope of this document; if you are interested, look at
103 the integration with Qt in :mod:`IPython.kernel.zmq.eventloops`.
108 the integration with Qt in :mod:`IPython.kernel.zmq.eventloops`.
General Comments 0
You need to be logged in to leave comments. Login now