##// END OF EJS Templates
Renamed 'payload-svg' matplotlib backend to 'inline'.
Fernando Perez -
Show More
@@ -1,144 +1,144
1 1 """ A minimal application using the Qt console-style IPython frontend.
2 2 """
3 3
4 4 #-----------------------------------------------------------------------------
5 5 # Imports
6 6 #-----------------------------------------------------------------------------
7 7
8 8 # Systemm library imports
9 9 from PyQt4 import QtGui
10 10
11 11 # Local imports
12 12 from IPython.external.argparse import ArgumentParser
13 13 from IPython.frontend.qt.console.frontend_widget import FrontendWidget
14 14 from IPython.frontend.qt.console.ipython_widget import IPythonWidget
15 15 from IPython.frontend.qt.console.rich_ipython_widget import RichIPythonWidget
16 16 from IPython.frontend.qt.kernelmanager import QtKernelManager
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Constants
20 20 #-----------------------------------------------------------------------------
21 21
22 22 LOCALHOST = '127.0.0.1'
23 23
24 24 #-----------------------------------------------------------------------------
25 25 # Classes
26 26 #-----------------------------------------------------------------------------
27 27
28 28 class MainWindow(QtGui.QMainWindow):
29 29
30 30 #---------------------------------------------------------------------------
31 31 # 'object' interface
32 32 #---------------------------------------------------------------------------
33 33
34 34 def __init__(self, frontend):
35 35 """ Create a MainWindow for the specified FrontendWidget.
36 36 """
37 37 super(MainWindow, self).__init__()
38 38 self._frontend = frontend
39 39 self._frontend.exit_requested.connect(self.close)
40 40 self.setCentralWidget(frontend)
41 41
42 42 #---------------------------------------------------------------------------
43 43 # QWidget interface
44 44 #---------------------------------------------------------------------------
45 45
46 46 def closeEvent(self, event):
47 47 """ Reimplemented to prompt the user and close the kernel cleanly.
48 48 """
49 49 kernel_manager = self._frontend.kernel_manager
50 50 if kernel_manager and kernel_manager.channels_running:
51 51 title = self.window().windowTitle()
52 52 reply = QtGui.QMessageBox.question(self, title,
53 53 'Close console?', QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
54 54 if reply == QtGui.QMessageBox.Yes:
55 55 kernel_manager.shutdown_kernel()
56 56 #kernel_manager.stop_channels()
57 57 event.accept()
58 58 else:
59 59 event.ignore()
60 60
61 61 #-----------------------------------------------------------------------------
62 62 # Main entry point
63 63 #-----------------------------------------------------------------------------
64 64
65 65 def main():
66 66 """ Entry point for application.
67 67 """
68 68 # Parse command line arguments.
69 69 parser = ArgumentParser()
70 70 kgroup = parser.add_argument_group('kernel options')
71 71 kgroup.add_argument('-e', '--existing', action='store_true',
72 72 help='connect to an existing kernel')
73 73 kgroup.add_argument('--ip', type=str, default=LOCALHOST,
74 74 help='set the kernel\'s IP address [default localhost]')
75 75 kgroup.add_argument('--xreq', type=int, metavar='PORT', default=0,
76 76 help='set the XREQ channel port [default random]')
77 77 kgroup.add_argument('--sub', type=int, metavar='PORT', default=0,
78 78 help='set the SUB channel port [default random]')
79 79 kgroup.add_argument('--rep', type=int, metavar='PORT', default=0,
80 80 help='set the REP channel port [default random]')
81 81 kgroup.add_argument('--hb', type=int, metavar='PORT', default=0,
82 82 help='set the heartbeat port [default: random]')
83 83
84 84 egroup = kgroup.add_mutually_exclusive_group()
85 85 egroup.add_argument('--pure', action='store_true', help = \
86 86 'use a pure Python kernel instead of an IPython kernel')
87 87 egroup.add_argument('--pylab', type=str, metavar='GUI', nargs='?',
88 88 const='auto', help = \
89 89 "Pre-load matplotlib and numpy for interactive use. If GUI is not \
90 90 given, the GUI backend is matplotlib's, otherwise use one of: \
91 ['tk', 'gtk', 'qt', 'wx', 'payload-svg'].")
91 ['tk', 'gtk', 'qt', 'wx', 'inline'].")
92 92
93 93 wgroup = parser.add_argument_group('widget options')
94 94 wgroup.add_argument('--paging', type=str, default='inside',
95 95 choices = ['inside', 'hsplit', 'vsplit', 'none'],
96 96 help='set the paging style [default inside]')
97 97 wgroup.add_argument('--rich', action='store_true',
98 98 help='enable rich text support')
99 99 wgroup.add_argument('--gui-completion', action='store_true',
100 100 help='use a GUI widget for tab completion')
101 101
102 102 args = parser.parse_args()
103 103
104 104 # Don't let Qt or ZMQ swallow KeyboardInterupts.
105 105 import signal
106 106 signal.signal(signal.SIGINT, signal.SIG_DFL)
107 107
108 108 # Create a KernelManager and start a kernel.
109 109 kernel_manager = QtKernelManager(xreq_address=(args.ip, args.xreq),
110 110 sub_address=(args.ip, args.sub),
111 111 rep_address=(args.ip, args.rep),
112 112 hb_address=(args.ip, args.hb))
113 113 if args.ip == LOCALHOST and not args.existing:
114 114 if args.pure:
115 115 kernel_manager.start_kernel(ipython=False)
116 116 elif args.pylab:
117 117 kernel_manager.start_kernel(pylab=args.pylab)
118 118 else:
119 119 kernel_manager.start_kernel()
120 120 kernel_manager.start_channels()
121 121
122 122 # Create the widget.
123 123 app = QtGui.QApplication([])
124 124 if args.pure:
125 125 kind = 'rich' if args.rich else 'plain'
126 126 widget = FrontendWidget(kind=kind, paging=args.paging)
127 127 elif args.rich or args.pylab:
128 128 widget = RichIPythonWidget(paging=args.paging)
129 129 else:
130 130 widget = IPythonWidget(paging=args.paging)
131 131 widget.gui_completion = args.gui_completion
132 132 widget.kernel_manager = kernel_manager
133 133
134 134 # Create the main window.
135 135 window = MainWindow(widget)
136 136 window.setWindowTitle('Python' if args.pure else 'IPython')
137 137 window.show()
138 138
139 139 # Start the application main loop.
140 140 app.exec_()
141 141
142 142
143 143 if __name__ == '__main__':
144 144 main()
@@ -1,196 +1,196
1 1 # -*- coding: utf-8 -*-
2 2 """Pylab (matplotlib) support utilities.
3 3
4 4 Authors
5 5 -------
6 6
7 7 * Fernando Perez.
8 8 * Brian Granger
9 9 """
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Copyright (C) 2009 The IPython Development Team
13 13 #
14 14 # Distributed under the terms of the BSD License. The full license is in
15 15 # the file COPYING, distributed as part of this software.
16 16 #-----------------------------------------------------------------------------
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Imports
20 20 #-----------------------------------------------------------------------------
21 21
22 22 from IPython.utils.decorators import flag_calls
23 23
24 24 # If user specifies a GUI, that dictates the backend, otherwise we read the
25 25 # user's mpl default from the mpl rc structure
26 26 backends = {'tk': 'TkAgg',
27 27 'gtk': 'GTKAgg',
28 28 'wx': 'WXAgg',
29 29 'qt': 'Qt4Agg', # qt3 not supported
30 30 'qt4': 'Qt4Agg',
31 'payload-svg' : 'module://IPython.zmq.pylab.backend_payload_svg'}
31 'inline' : 'module://IPython.zmq.pylab.backend_inline'}
32 32
33 33 #-----------------------------------------------------------------------------
34 34 # Main classes and functions
35 35 #-----------------------------------------------------------------------------
36 36
37 37
38 38 def find_gui_and_backend(gui=None):
39 39 """Given a gui string return the gui and mpl backend.
40 40
41 41 Parameters
42 42 ----------
43 43 gui : str
44 Can be one of ('tk','gtk','wx','qt','qt4','payload-svg').
44 Can be one of ('tk','gtk','wx','qt','qt4','inline').
45 45
46 46 Returns
47 47 -------
48 48 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
49 'WXAgg','Qt4Agg','module://IPython.zmq.pylab.backend_payload_svg').
49 'WXAgg','Qt4Agg','module://IPython.zmq.pylab.backend_inline').
50 50 """
51 51
52 52 import matplotlib
53 53
54 54 if gui:
55 55 # select backend based on requested gui
56 56 backend = backends[gui]
57 57 else:
58 58 backend = matplotlib.rcParams['backend']
59 59 # In this case, we need to find what the appropriate gui selection call
60 60 # should be for IPython, so we can activate inputhook accordingly
61 61 g2b = backends # maps gui names to mpl backend names
62 62 b2g = dict(zip(g2b.values(), g2b.keys())) # reverse dict
63 63 gui = b2g.get(backend, None)
64 64 return gui, backend
65 65
66 66
67 67 def activate_matplotlib(backend):
68 68 """Activate the given backend and set interactive to True."""
69 69
70 70 import matplotlib
71 71 if backend.startswith('module://'):
72 72 # Work around bug in matplotlib: matplotlib.use converts the
73 73 # backend_id to lowercase even if a module name is specified!
74 74 matplotlib.rcParams['backend'] = backend
75 75 else:
76 76 matplotlib.use(backend)
77 77 matplotlib.interactive(True)
78 78
79 79 # This must be imported last in the matplotlib series, after
80 80 # backend/interactivity choices have been made
81 81 import matplotlib.pylab as pylab
82 82
83 83 # XXX For now leave this commented out, but depending on discussions with
84 84 # mpl-dev, we may be able to allow interactive switching...
85 85 #import matplotlib.pyplot
86 86 #matplotlib.pyplot.switch_backend(backend)
87 87
88 88 pylab.show._needmain = False
89 89 # We need to detect at runtime whether show() is called by the user.
90 90 # For this, we wrap it into a decorator which adds a 'called' flag.
91 91 pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
92 92
93 93
94 94 def import_pylab(user_ns, backend, import_all=True, shell=None):
95 95 """Import the standard pylab symbols into user_ns."""
96 96
97 97 # Import numpy as np/pyplot as plt are conventions we're trying to
98 98 # somewhat standardize on. Making them available to users by default
99 99 # will greatly help this.
100 100 exec ("import numpy\n"
101 101 "import matplotlib\n"
102 102 "from matplotlib import pylab, mlab, pyplot\n"
103 103 "np = numpy\n"
104 104 "plt = pyplot\n"
105 105 ) in user_ns
106 106
107 107 if shell is not None:
108 108 # If using our svg payload backend, register the post-execution
109 109 # function that will pick up the results for display. This can only be
110 110 # done with access to the real shell object.
111 if backend == backends['payload-svg']:
112 from IPython.zmq.pylab.backend_payload_svg import flush_svg
111 if backend == backends['inline']:
112 from IPython.zmq.pylab.backend_inline import flush_svg
113 113 shell.register_post_execute(flush_svg)
114 114 else:
115 from IPython.zmq.pylab.backend_payload_svg import paste
115 from IPython.zmq.pylab.backend_inline import paste
116 116 from matplotlib import pyplot
117 117 # Add 'paste' to pyplot and to the user's namespace
118 118 user_ns['paste'] = pyplot.paste = paste
119 119
120 120 if import_all:
121 121 exec("from matplotlib.pylab import *\n"
122 122 "from numpy import *\n") in user_ns
123 123
124 124
125 125 def pylab_activate(user_ns, gui=None, import_all=True):
126 126 """Activate pylab mode in the user's namespace.
127 127
128 128 Loads and initializes numpy, matplotlib and friends for interactive use.
129 129
130 130 Parameters
131 131 ----------
132 132 user_ns : dict
133 133 Namespace where the imports will occur.
134 134
135 135 gui : optional, string
136 136 A valid gui name following the conventions of the %gui magic.
137 137
138 138 import_all : optional, boolean
139 139 If true, an 'import *' is done from numpy and pylab.
140 140
141 141 Returns
142 142 -------
143 143 The actual gui used (if not given as input, it was obtained from matplotlib
144 144 itself, and will be needed next to configure IPython's gui integration.
145 145 """
146 146 gui, backend = find_gui_and_backend(gui)
147 147 activate_matplotlib(backend)
148 148 import_pylab(user_ns, backend)
149 149
150 150 print """
151 151 Welcome to pylab, a matplotlib-based Python environment [backend: %s].
152 152 For more information, type 'help(pylab)'.""" % backend
153 153
154 154 return gui
155 155
156 156 # We need a little factory function here to create the closure where
157 157 # safe_execfile can live.
158 158 def mpl_runner(safe_execfile):
159 159 """Factory to return a matplotlib-enabled runner for %run.
160 160
161 161 Parameters
162 162 ----------
163 163 safe_execfile : function
164 164 This must be a function with the same interface as the
165 165 :meth:`safe_execfile` method of IPython.
166 166
167 167 Returns
168 168 -------
169 169 A function suitable for use as the ``runner`` argument of the %run magic
170 170 function.
171 171 """
172 172
173 173 def mpl_execfile(fname,*where,**kw):
174 174 """matplotlib-aware wrapper around safe_execfile.
175 175
176 176 Its interface is identical to that of the :func:`execfile` builtin.
177 177
178 178 This is ultimately a call to execfile(), but wrapped in safeties to
179 179 properly handle interactive rendering."""
180 180
181 181 import matplotlib
182 182 import matplotlib.pylab as pylab
183 183
184 184 #print '*** Matplotlib runner ***' # dbg
185 185 # turn off rendering until end of script
186 186 is_interactive = matplotlib.rcParams['interactive']
187 187 matplotlib.interactive(False)
188 188 safe_execfile(fname,*where,**kw)
189 189 matplotlib.interactive(is_interactive)
190 190 # make rendering call now, if the user tried to do it
191 191 if pylab.draw_if_interactive.called:
192 192 pylab.draw()
193 193 pylab.draw_if_interactive.called = False
194 194
195 195 return mpl_execfile
196 196
@@ -1,586 +1,586
1 1 #!/usr/bin/env python
2 2 """A simple interactive kernel that talks to a frontend over 0MQ.
3 3
4 4 Things to do:
5 5
6 6 * Implement `set_parent` logic. Right before doing exec, the Kernel should
7 7 call set_parent on all the PUB objects with the message about to be executed.
8 8 * Implement random port and security key logic.
9 9 * Implement control messages.
10 10 * Implement event loop and poll version.
11 11 """
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16 from __future__ import print_function
17 17
18 18 # Standard library imports.
19 19 import __builtin__
20 20 import atexit
21 21 import sys
22 22 import time
23 23 import traceback
24 24
25 25 # System library imports.
26 26 import zmq
27 27
28 28 # Local imports.
29 29 from IPython.config.configurable import Configurable
30 30 from IPython.utils import io
31 31 from IPython.utils.jsonutil import json_clean
32 32 from IPython.lib import pylabtools
33 33 from IPython.utils.traitlets import Instance, Float
34 34 from entry_point import (base_launch_kernel, make_argument_parser, make_kernel,
35 35 start_kernel)
36 36 from iostream import OutStream
37 37 from session import Session, Message
38 38 from zmqshell import ZMQInteractiveShell
39 39
40 40 #-----------------------------------------------------------------------------
41 41 # Main kernel class
42 42 #-----------------------------------------------------------------------------
43 43
44 44 class Kernel(Configurable):
45 45
46 46 #---------------------------------------------------------------------------
47 47 # Kernel interface
48 48 #---------------------------------------------------------------------------
49 49
50 50 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
51 51 session = Instance(Session)
52 52 reply_socket = Instance('zmq.Socket')
53 53 pub_socket = Instance('zmq.Socket')
54 54 req_socket = Instance('zmq.Socket')
55 55
56 56 # Private interface
57 57
58 58 # Time to sleep after flushing the stdout/err buffers in each execute
59 59 # cycle. While this introduces a hard limit on the minimal latency of the
60 60 # execute cycle, it helps prevent output synchronization problems for
61 61 # clients.
62 62 # Units are in seconds. The minimum zmq latency on local host is probably
63 63 # ~150 microseconds, set this to 500us for now. We may need to increase it
64 64 # a little if it's not enough after more interactive testing.
65 65 _execute_sleep = Float(0.0005, config=True)
66 66
67 67 # Frequency of the kernel's event loop.
68 68 # Units are in seconds, kernel subclasses for GUI toolkits may need to
69 69 # adapt to milliseconds.
70 70 _poll_interval = Float(0.05, config=True)
71 71
72 72 # If the shutdown was requested over the network, we leave here the
73 73 # necessary reply message so it can be sent by our registered atexit
74 74 # handler. This ensures that the reply is only sent to clients truly at
75 75 # the end of our shutdown process (which happens after the underlying
76 76 # IPython shell's own shutdown).
77 77 _shutdown_message = None
78 78
79 79 def __init__(self, **kwargs):
80 80 super(Kernel, self).__init__(**kwargs)
81 81
82 82 # Before we even start up the shell, register *first* our exit handlers
83 83 # so they come before the shell's
84 84 atexit.register(self._at_shutdown)
85 85
86 86 # Initialize the InteractiveShell subclass
87 87 self.shell = ZMQInteractiveShell.instance()
88 88 self.shell.displayhook.session = self.session
89 89 self.shell.displayhook.pub_socket = self.pub_socket
90 90
91 91 # TMP - hack while developing
92 92 self.shell._reply_content = None
93 93
94 94 # Build dict of handlers for message types
95 95 msg_types = [ 'execute_request', 'complete_request',
96 96 'object_info_request', 'history_request',
97 97 'shutdown_request']
98 98 self.handlers = {}
99 99 for msg_type in msg_types:
100 100 self.handlers[msg_type] = getattr(self, msg_type)
101 101
102 102 def do_one_iteration(self):
103 103 """Do one iteration of the kernel's evaluation loop.
104 104 """
105 105 try:
106 106 ident = self.reply_socket.recv(zmq.NOBLOCK)
107 107 except zmq.ZMQError, e:
108 108 if e.errno == zmq.EAGAIN:
109 109 return
110 110 else:
111 111 raise
112 112 # FIXME: Bug in pyzmq/zmq?
113 113 # assert self.reply_socket.rcvmore(), "Missing message part."
114 114 msg = self.reply_socket.recv_json()
115 115
116 116 # Print some info about this message and leave a '--->' marker, so it's
117 117 # easier to trace visually the message chain when debugging. Each
118 118 # handler prints its message at the end.
119 119 # Eventually we'll move these from stdout to a logger.
120 120 io.raw_print('\n*** MESSAGE TYPE:', msg['msg_type'], '***')
121 121 io.raw_print(' Content: ', msg['content'],
122 122 '\n --->\n ', sep='', end='')
123 123
124 124 # Find and call actual handler for message
125 125 handler = self.handlers.get(msg['msg_type'], None)
126 126 if handler is None:
127 127 io.raw_print_err("UNKNOWN MESSAGE TYPE:", msg)
128 128 else:
129 129 handler(ident, msg)
130 130
131 131 # Check whether we should exit, in case the incoming message set the
132 132 # exit flag on
133 133 if self.shell.exit_now:
134 134 io.raw_print('\nExiting IPython kernel...')
135 135 # We do a normal, clean exit, which allows any actions registered
136 136 # via atexit (such as history saving) to take place.
137 137 sys.exit(0)
138 138
139 139
140 140 def start(self):
141 141 """ Start the kernel main loop.
142 142 """
143 143 while True:
144 144 time.sleep(self._poll_interval)
145 145 self.do_one_iteration()
146 146
147 147 #---------------------------------------------------------------------------
148 148 # Kernel request handlers
149 149 #---------------------------------------------------------------------------
150 150
151 151 def _publish_pyin(self, code, parent):
152 152 """Publish the code request on the pyin stream."""
153 153
154 154 pyin_msg = self.session.msg(u'pyin',{u'code':code}, parent=parent)
155 155 self.pub_socket.send_json(pyin_msg)
156 156
157 157 def execute_request(self, ident, parent):
158 158 try:
159 159 content = parent[u'content']
160 160 code = content[u'code']
161 161 silent = content[u'silent']
162 162 except:
163 163 io.raw_print_err("Got bad msg: ")
164 164 io.raw_print_err(Message(parent))
165 165 return
166 166
167 167 shell = self.shell # we'll need this a lot here
168 168
169 169 # Replace raw_input. Note that is not sufficient to replace
170 170 # raw_input in the user namespace.
171 171 raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
172 172 __builtin__.raw_input = raw_input
173 173
174 174 # Set the parent message of the display hook and out streams.
175 175 shell.displayhook.set_parent(parent)
176 176 sys.stdout.set_parent(parent)
177 177 sys.stderr.set_parent(parent)
178 178
179 179 # Re-broadcast our input for the benefit of listening clients, and
180 180 # start computing output
181 181 if not silent:
182 182 self._publish_pyin(code, parent)
183 183
184 184 reply_content = {}
185 185 try:
186 186 if silent:
187 187 # runcode uses 'exec' mode, so no displayhook will fire, and it
188 188 # doesn't call logging or history manipulations. Print
189 189 # statements in that code will obviously still execute.
190 190 shell.runcode(code)
191 191 else:
192 192 # FIXME: runlines calls the exception handler itself.
193 193 shell._reply_content = None
194 194
195 195 # For now leave this here until we're sure we can stop using it
196 196 #shell.runlines(code)
197 197
198 198 # Experimental: cell mode! Test more before turning into
199 199 # default and removing the hacks around runlines.
200 200 shell.run_cell(code)
201 201 except:
202 202 status = u'error'
203 203 # FIXME: this code right now isn't being used yet by default,
204 204 # because the runlines() call above directly fires off exception
205 205 # reporting. This code, therefore, is only active in the scenario
206 206 # where runlines itself has an unhandled exception. We need to
207 207 # uniformize this, for all exception construction to come from a
208 208 # single location in the codbase.
209 209 etype, evalue, tb = sys.exc_info()
210 210 tb_list = traceback.format_exception(etype, evalue, tb)
211 211 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
212 212 else:
213 213 status = u'ok'
214 214
215 215 reply_content[u'status'] = status
216 216 # Compute the execution counter so clients can display prompts
217 217 reply_content['execution_count'] = shell.displayhook.prompt_count
218 218
219 219 # FIXME - fish exception info out of shell, possibly left there by
220 220 # runlines. We'll need to clean up this logic later.
221 221 if shell._reply_content is not None:
222 222 reply_content.update(shell._reply_content)
223 223
224 224 # At this point, we can tell whether the main code execution succeeded
225 225 # or not. If it did, we proceed to evaluate user_variables/expressions
226 226 if reply_content['status'] == 'ok':
227 227 reply_content[u'user_variables'] = \
228 228 shell.get_user_variables(content[u'user_variables'])
229 229 reply_content[u'user_expressions'] = \
230 230 shell.eval_expressions(content[u'user_expressions'])
231 231 else:
232 232 # If there was an error, don't even try to compute variables or
233 233 # expressions
234 234 reply_content[u'user_variables'] = {}
235 235 reply_content[u'user_expressions'] = {}
236 236
237 237 # Payloads should be retrieved regardless of outcome, so we can both
238 238 # recover partial output (that could have been generated early in a
239 239 # block, before an error) and clear the payload system always.
240 240 reply_content[u'payload'] = shell.payload_manager.read_payload()
241 241 # Be agressive about clearing the payload because we don't want
242 242 # it to sit in memory until the next execute_request comes in.
243 243 shell.payload_manager.clear_payload()
244 244
245 245 # Send the reply.
246 246 reply_msg = self.session.msg(u'execute_reply', reply_content, parent)
247 247 io.raw_print(reply_msg)
248 248
249 249 # Flush output before sending the reply.
250 250 sys.stdout.flush()
251 251 sys.stderr.flush()
252 252 # FIXME: on rare occasions, the flush doesn't seem to make it to the
253 253 # clients... This seems to mitigate the problem, but we definitely need
254 254 # to better understand what's going on.
255 255 if self._execute_sleep:
256 256 time.sleep(self._execute_sleep)
257 257
258 258 self.reply_socket.send(ident, zmq.SNDMORE)
259 259 self.reply_socket.send_json(reply_msg)
260 260 if reply_msg['content']['status'] == u'error':
261 261 self._abort_queue()
262 262
263 263 def complete_request(self, ident, parent):
264 264 txt, matches = self._complete(parent)
265 265 matches = {'matches' : matches,
266 266 'matched_text' : txt,
267 267 'status' : 'ok'}
268 268 completion_msg = self.session.send(self.reply_socket, 'complete_reply',
269 269 matches, parent, ident)
270 270 io.raw_print(completion_msg)
271 271
272 272 def object_info_request(self, ident, parent):
273 273 object_info = self.shell.object_inspect(parent['content']['oname'])
274 274 # Before we send this object over, we turn it into a dict and we scrub
275 275 # it for JSON usage
276 276 oinfo = json_clean(object_info._asdict())
277 277 msg = self.session.send(self.reply_socket, 'object_info_reply',
278 278 oinfo, parent, ident)
279 279 io.raw_print(msg)
280 280
281 281 def history_request(self, ident, parent):
282 282 output = parent['content']['output']
283 283 index = parent['content']['index']
284 284 raw = parent['content']['raw']
285 285 hist = self.shell.get_history(index=index, raw=raw, output=output)
286 286 content = {'history' : hist}
287 287 msg = self.session.send(self.reply_socket, 'history_reply',
288 288 content, parent, ident)
289 289 io.raw_print(msg)
290 290
291 291 def shutdown_request(self, ident, parent):
292 292 self.shell.exit_now = True
293 293 self._shutdown_message = self.session.msg(u'shutdown_reply', {}, parent)
294 294 sys.exit(0)
295 295
296 296 #---------------------------------------------------------------------------
297 297 # Protected interface
298 298 #---------------------------------------------------------------------------
299 299
300 300 def _abort_queue(self):
301 301 while True:
302 302 try:
303 303 ident = self.reply_socket.recv(zmq.NOBLOCK)
304 304 except zmq.ZMQError, e:
305 305 if e.errno == zmq.EAGAIN:
306 306 break
307 307 else:
308 308 assert self.reply_socket.rcvmore(), \
309 309 "Unexpected missing message part."
310 310 msg = self.reply_socket.recv_json()
311 311 io.raw_print("Aborting:\n", Message(msg))
312 312 msg_type = msg['msg_type']
313 313 reply_type = msg_type.split('_')[0] + '_reply'
314 314 reply_msg = self.session.msg(reply_type, {'status' : 'aborted'}, msg)
315 315 io.raw_print(reply_msg)
316 316 self.reply_socket.send(ident,zmq.SNDMORE)
317 317 self.reply_socket.send_json(reply_msg)
318 318 # We need to wait a bit for requests to come in. This can probably
319 319 # be set shorter for true asynchronous clients.
320 320 time.sleep(0.1)
321 321
322 322 def _raw_input(self, prompt, ident, parent):
323 323 # Flush output before making the request.
324 324 sys.stderr.flush()
325 325 sys.stdout.flush()
326 326
327 327 # Send the input request.
328 328 content = dict(prompt=prompt)
329 329 msg = self.session.msg(u'input_request', content, parent)
330 330 self.req_socket.send_json(msg)
331 331
332 332 # Await a response.
333 333 reply = self.req_socket.recv_json()
334 334 try:
335 335 value = reply['content']['value']
336 336 except:
337 337 io.raw_print_err("Got bad raw_input reply: ")
338 338 io.raw_print_err(Message(parent))
339 339 value = ''
340 340 return value
341 341
342 342 def _complete(self, msg):
343 343 c = msg['content']
344 344 try:
345 345 cpos = int(c['cursor_pos'])
346 346 except:
347 347 # If we don't get something that we can convert to an integer, at
348 348 # least attempt the completion guessing the cursor is at the end of
349 349 # the text, if there's any, and otherwise of the line
350 350 cpos = len(c['text'])
351 351 if cpos==0:
352 352 cpos = len(c['line'])
353 353 return self.shell.complete(c['text'], c['line'], cpos)
354 354
355 355 def _object_info(self, context):
356 356 symbol, leftover = self._symbol_from_context(context)
357 357 if symbol is not None and not leftover:
358 358 doc = getattr(symbol, '__doc__', '')
359 359 else:
360 360 doc = ''
361 361 object_info = dict(docstring = doc)
362 362 return object_info
363 363
364 364 def _symbol_from_context(self, context):
365 365 if not context:
366 366 return None, context
367 367
368 368 base_symbol_string = context[0]
369 369 symbol = self.shell.user_ns.get(base_symbol_string, None)
370 370 if symbol is None:
371 371 symbol = __builtin__.__dict__.get(base_symbol_string, None)
372 372 if symbol is None:
373 373 return None, context
374 374
375 375 context = context[1:]
376 376 for i, name in enumerate(context):
377 377 new_symbol = getattr(symbol, name, None)
378 378 if new_symbol is None:
379 379 return symbol, context[i:]
380 380 else:
381 381 symbol = new_symbol
382 382
383 383 return symbol, []
384 384
385 385 def _at_shutdown(self):
386 386 """Actions taken at shutdown by the kernel, called by python's atexit.
387 387 """
388 388 # io.rprint("Kernel at_shutdown") # dbg
389 389 if self._shutdown_message is not None:
390 390 self.reply_socket.send_json(self._shutdown_message)
391 391 io.raw_print(self._shutdown_message)
392 392 # A very short sleep to give zmq time to flush its message buffers
393 393 # before Python truly shuts down.
394 394 time.sleep(0.01)
395 395
396 396
397 397 class QtKernel(Kernel):
398 398 """A Kernel subclass with Qt support."""
399 399
400 400 def start(self):
401 401 """Start a kernel with QtPy4 event loop integration."""
402 402
403 403 from PyQt4 import QtCore
404 404 from IPython.lib.guisupport import get_app_qt4, start_event_loop_qt4
405 405
406 406 self.app = get_app_qt4([" "])
407 407 self.app.setQuitOnLastWindowClosed(False)
408 408 self.timer = QtCore.QTimer()
409 409 self.timer.timeout.connect(self.do_one_iteration)
410 410 # Units for the timer are in milliseconds
411 411 self.timer.start(1000*self._poll_interval)
412 412 start_event_loop_qt4(self.app)
413 413
414 414
415 415 class WxKernel(Kernel):
416 416 """A Kernel subclass with Wx support."""
417 417
418 418 def start(self):
419 419 """Start a kernel with wx event loop support."""
420 420
421 421 import wx
422 422 from IPython.lib.guisupport import start_event_loop_wx
423 423
424 424 doi = self.do_one_iteration
425 425 # Wx uses milliseconds
426 426 poll_interval = int(1000*self._poll_interval)
427 427
428 428 # We have to put the wx.Timer in a wx.Frame for it to fire properly.
429 429 # We make the Frame hidden when we create it in the main app below.
430 430 class TimerFrame(wx.Frame):
431 431 def __init__(self, func):
432 432 wx.Frame.__init__(self, None, -1)
433 433 self.timer = wx.Timer(self)
434 434 # Units for the timer are in milliseconds
435 435 self.timer.Start(poll_interval)
436 436 self.Bind(wx.EVT_TIMER, self.on_timer)
437 437 self.func = func
438 438
439 439 def on_timer(self, event):
440 440 self.func()
441 441
442 442 # We need a custom wx.App to create our Frame subclass that has the
443 443 # wx.Timer to drive the ZMQ event loop.
444 444 class IPWxApp(wx.App):
445 445 def OnInit(self):
446 446 self.frame = TimerFrame(doi)
447 447 self.frame.Show(False)
448 448 return True
449 449
450 450 # The redirect=False here makes sure that wx doesn't replace
451 451 # sys.stdout/stderr with its own classes.
452 452 self.app = IPWxApp(redirect=False)
453 453 start_event_loop_wx(self.app)
454 454
455 455
456 456 class TkKernel(Kernel):
457 457 """A Kernel subclass with Tk support."""
458 458
459 459 def start(self):
460 460 """Start a Tk enabled event loop."""
461 461
462 462 import Tkinter
463 463 doi = self.do_one_iteration
464 464 # Tk uses milliseconds
465 465 poll_interval = int(1000*self._poll_interval)
466 466 # For Tkinter, we create a Tk object and call its withdraw method.
467 467 class Timer(object):
468 468 def __init__(self, func):
469 469 self.app = Tkinter.Tk()
470 470 self.app.withdraw()
471 471 self.func = func
472 472
473 473 def on_timer(self):
474 474 self.func()
475 475 self.app.after(poll_interval, self.on_timer)
476 476
477 477 def start(self):
478 478 self.on_timer() # Call it once to get things going.
479 479 self.app.mainloop()
480 480
481 481 self.timer = Timer(doi)
482 482 self.timer.start()
483 483
484 484
485 485 class GTKKernel(Kernel):
486 486 """A Kernel subclass with GTK support."""
487 487
488 488 def start(self):
489 489 """Start the kernel, coordinating with the GTK event loop"""
490 490 from .gui.gtkembed import GTKEmbed
491 491
492 492 gtk_kernel = GTKEmbed(self)
493 493 gtk_kernel.start()
494 494
495 495
496 496 #-----------------------------------------------------------------------------
497 497 # Kernel main and launch functions
498 498 #-----------------------------------------------------------------------------
499 499
500 500 def launch_kernel(xrep_port=0, pub_port=0, req_port=0, hb_port=0,
501 501 independent=False, pylab=False):
502 502 """Launches a localhost kernel, binding to the specified ports.
503 503
504 504 Parameters
505 505 ----------
506 506 xrep_port : int, optional
507 507 The port to use for XREP channel.
508 508
509 509 pub_port : int, optional
510 510 The port to use for the SUB channel.
511 511
512 512 req_port : int, optional
513 513 The port to use for the REQ (raw input) channel.
514 514
515 515 hb_port : int, optional
516 516 The port to use for the hearbeat REP channel.
517 517
518 518 independent : bool, optional (default False)
519 519 If set, the kernel process is guaranteed to survive if this process
520 520 dies. If not set, an effort is made to ensure that the kernel is killed
521 521 when this process dies. Note that in this case it is still good practice
522 522 to kill kernels manually before exiting.
523 523
524 524 pylab : bool or string, optional (default False)
525 525 If not False, the kernel will be launched with pylab enabled. If a
526 526 string is passed, matplotlib will use the specified backend. Otherwise,
527 527 matplotlib's default backend will be used.
528 528
529 529 Returns
530 530 -------
531 531 A tuple of form:
532 532 (kernel_process, xrep_port, pub_port, req_port)
533 533 where kernel_process is a Popen object and the ports are integers.
534 534 """
535 535 extra_arguments = []
536 536 if pylab:
537 537 extra_arguments.append('--pylab')
538 538 if isinstance(pylab, basestring):
539 539 extra_arguments.append(pylab)
540 540 return base_launch_kernel('from IPython.zmq.ipkernel import main; main()',
541 541 xrep_port, pub_port, req_port, hb_port,
542 542 independent, extra_arguments)
543 543
544 544
545 545 def main():
546 546 """ The IPython kernel main entry point.
547 547 """
548 548 parser = make_argument_parser()
549 549 parser.add_argument('--pylab', type=str, metavar='GUI', nargs='?',
550 550 const='auto', help = \
551 551 "Pre-load matplotlib and numpy for interactive use. If GUI is not \
552 552 given, the GUI backend is matplotlib's, otherwise use one of: \
553 ['tk', 'gtk', 'qt', 'wx', 'payload-svg'].")
553 ['tk', 'gtk', 'qt', 'wx', 'inline'].")
554 554 namespace = parser.parse_args()
555 555
556 556 kernel_class = Kernel
557 557
558 558 kernel_classes = {
559 559 'qt' : QtKernel,
560 560 'qt4': QtKernel,
561 'payload-svg': Kernel,
561 'inline': Kernel,
562 562 'wx' : WxKernel,
563 563 'tk' : TkKernel,
564 564 'gtk': GTKKernel,
565 565 }
566 566 if namespace.pylab:
567 567 if namespace.pylab == 'auto':
568 568 gui, backend = pylabtools.find_gui_and_backend()
569 569 else:
570 570 gui, backend = pylabtools.find_gui_and_backend(namespace.pylab)
571 571 kernel_class = kernel_classes.get(gui)
572 572 if kernel_class is None:
573 573 raise ValueError('GUI is not supported: %r' % gui)
574 574 pylabtools.activate_matplotlib(backend)
575 575
576 576 kernel = make_kernel(namespace, kernel_class, OutStream)
577 577
578 578 if namespace.pylab:
579 579 pylabtools.import_pylab(kernel.shell.user_ns, backend,
580 580 shell=kernel.shell)
581 581
582 582 start_kernel(namespace, kernel)
583 583
584 584
585 585 if __name__ == '__main__':
586 586 main()
1 NO CONTENT: file renamed from IPython/zmq/pylab/backend_payload_svg.py to IPython/zmq/pylab/backend_inline.py
General Comments 0
You need to be logged in to leave comments. Login now