##// END OF EJS Templates
Add message when kernel catches KeyboardInterrupt.
Thomas Kluyver -
Show More
@@ -1,689 +1,689 b''
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 import logging
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 # Globals
42 42 #-----------------------------------------------------------------------------
43 43
44 44 # Module-level logger
45 45 logger = logging.getLogger(__name__)
46 46
47 47 # FIXME: this needs to be done more cleanly later, once we have proper
48 48 # configuration support. This is a library, so it shouldn't set a stream
49 49 # handler, see:
50 50 # http://docs.python.org/library/logging.html#configuring-logging-for-a-library
51 51 # But this lets us at least do developer debugging for now by manually turning
52 52 # it on/off. And once we have full config support, the client entry points
53 53 # will select their logging handlers, as well as passing to this library the
54 54 # logging level.
55 55
56 56 if 0: # dbg - set to 1 to actually see the messages.
57 57 logger.addHandler(logging.StreamHandler())
58 58 logger.setLevel(logging.DEBUG)
59 59
60 60 # /FIXME
61 61
62 62 #-----------------------------------------------------------------------------
63 63 # Main kernel class
64 64 #-----------------------------------------------------------------------------
65 65
66 66 class Kernel(Configurable):
67 67
68 68 #---------------------------------------------------------------------------
69 69 # Kernel interface
70 70 #---------------------------------------------------------------------------
71 71
72 72 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
73 73 session = Instance(Session)
74 74 reply_socket = Instance('zmq.Socket')
75 75 pub_socket = Instance('zmq.Socket')
76 76 req_socket = Instance('zmq.Socket')
77 77
78 78 # Private interface
79 79
80 80 # Time to sleep after flushing the stdout/err buffers in each execute
81 81 # cycle. While this introduces a hard limit on the minimal latency of the
82 82 # execute cycle, it helps prevent output synchronization problems for
83 83 # clients.
84 84 # Units are in seconds. The minimum zmq latency on local host is probably
85 85 # ~150 microseconds, set this to 500us for now. We may need to increase it
86 86 # a little if it's not enough after more interactive testing.
87 87 _execute_sleep = Float(0.0005, config=True)
88 88
89 89 # Frequency of the kernel's event loop.
90 90 # Units are in seconds, kernel subclasses for GUI toolkits may need to
91 91 # adapt to milliseconds.
92 92 _poll_interval = Float(0.05, config=True)
93 93
94 94 # If the shutdown was requested over the network, we leave here the
95 95 # necessary reply message so it can be sent by our registered atexit
96 96 # handler. This ensures that the reply is only sent to clients truly at
97 97 # the end of our shutdown process (which happens after the underlying
98 98 # IPython shell's own shutdown).
99 99 _shutdown_message = None
100 100
101 101 # This is a dict of port number that the kernel is listening on. It is set
102 102 # by record_ports and used by connect_request.
103 103 _recorded_ports = None
104 104
105 105
106 106 def __init__(self, **kwargs):
107 107 super(Kernel, self).__init__(**kwargs)
108 108
109 109 # Before we even start up the shell, register *first* our exit handlers
110 110 # so they come before the shell's
111 111 atexit.register(self._at_shutdown)
112 112
113 113 # Initialize the InteractiveShell subclass
114 114 self.shell = ZMQInteractiveShell.instance()
115 115 self.shell.displayhook.session = self.session
116 116 self.shell.displayhook.pub_socket = self.pub_socket
117 117 self.shell.display_pub.session = self.session
118 118 self.shell.display_pub.pub_socket = self.pub_socket
119 119
120 120 # TMP - hack while developing
121 121 self.shell._reply_content = None
122 122
123 123 # Build dict of handlers for message types
124 124 msg_types = [ 'execute_request', 'complete_request',
125 125 'object_info_request', 'history_request',
126 126 'connect_request', 'shutdown_request']
127 127 self.handlers = {}
128 128 for msg_type in msg_types:
129 129 self.handlers[msg_type] = getattr(self, msg_type)
130 130
131 131 def do_one_iteration(self):
132 132 """Do one iteration of the kernel's evaluation loop.
133 133 """
134 134 ident,msg = self.session.recv(self.reply_socket, zmq.NOBLOCK)
135 135 if msg is None:
136 136 return
137 137
138 138 # This assert will raise in versions of zeromq 2.0.7 and lesser.
139 139 # We now require 2.0.8 or above, so we can uncomment for safety.
140 140 # print(ident,msg, file=sys.__stdout__)
141 141 assert ident is not None, "Missing message part."
142 142
143 143 # Print some info about this message and leave a '--->' marker, so it's
144 144 # easier to trace visually the message chain when debugging. Each
145 145 # handler prints its message at the end.
146 146 # Eventually we'll move these from stdout to a logger.
147 147 logger.debug('\n*** MESSAGE TYPE:'+str(msg['msg_type'])+'***')
148 148 logger.debug(' Content: '+str(msg['content'])+'\n --->\n ')
149 149
150 150 # Find and call actual handler for message
151 151 handler = self.handlers.get(msg['msg_type'], None)
152 152 if handler is None:
153 153 logger.error("UNKNOWN MESSAGE TYPE:" +str(msg))
154 154 else:
155 155 handler(ident, msg)
156 156
157 157 # Check whether we should exit, in case the incoming message set the
158 158 # exit flag on
159 159 if self.shell.exit_now:
160 160 logger.debug('\nExiting IPython kernel...')
161 161 # We do a normal, clean exit, which allows any actions registered
162 162 # via atexit (such as history saving) to take place.
163 163 sys.exit(0)
164 164
165 165
166 166 def start(self):
167 167 """ Start the kernel main loop.
168 168 """
169 169 while True:
170 170 try:
171 171 time.sleep(self._poll_interval)
172 172 self.do_one_iteration()
173 173 except KeyboardInterrupt:
174 174 # Ctrl-C shouldn't crash the kernel
175 continue
175 io.raw_print("KeyboardInterrupt caught in kernel")
176 176
177 177 def record_ports(self, xrep_port, pub_port, req_port, hb_port):
178 178 """Record the ports that this kernel is using.
179 179
180 180 The creator of the Kernel instance must call this methods if they
181 181 want the :meth:`connect_request` method to return the port numbers.
182 182 """
183 183 self._recorded_ports = {
184 184 'xrep_port' : xrep_port,
185 185 'pub_port' : pub_port,
186 186 'req_port' : req_port,
187 187 'hb_port' : hb_port
188 188 }
189 189
190 190 #---------------------------------------------------------------------------
191 191 # Kernel request handlers
192 192 #---------------------------------------------------------------------------
193 193
194 194 def _publish_pyin(self, code, parent):
195 195 """Publish the code request on the pyin stream."""
196 196
197 197 pyin_msg = self.session.send(self.pub_socket, u'pyin',{u'code':code}, parent=parent)
198 198
199 199 def execute_request(self, ident, parent):
200 200
201 201 status_msg = self.session.send(self.pub_socket,
202 202 u'status',
203 203 {u'execution_state':u'busy'},
204 204 parent=parent
205 205 )
206 206
207 207 try:
208 208 content = parent[u'content']
209 209 code = content[u'code']
210 210 silent = content[u'silent']
211 211 except:
212 212 logger.error("Got bad msg: ")
213 213 logger.error(str(Message(parent)))
214 214 return
215 215
216 216 shell = self.shell # we'll need this a lot here
217 217
218 218 # Replace raw_input. Note that is not sufficient to replace
219 219 # raw_input in the user namespace.
220 220 raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
221 221 __builtin__.raw_input = raw_input
222 222
223 223 # Set the parent message of the display hook and out streams.
224 224 shell.displayhook.set_parent(parent)
225 225 shell.display_pub.set_parent(parent)
226 226 sys.stdout.set_parent(parent)
227 227 sys.stderr.set_parent(parent)
228 228
229 229 # Re-broadcast our input for the benefit of listening clients, and
230 230 # start computing output
231 231 if not silent:
232 232 self._publish_pyin(code, parent)
233 233
234 234 reply_content = {}
235 235 try:
236 236 if silent:
237 237 # run_code uses 'exec' mode, so no displayhook will fire, and it
238 238 # doesn't call logging or history manipulations. Print
239 239 # statements in that code will obviously still execute.
240 240 shell.run_code(code)
241 241 else:
242 242 # FIXME: the shell calls the exception handler itself.
243 243 shell.run_cell(code)
244 244 except:
245 245 status = u'error'
246 246 # FIXME: this code right now isn't being used yet by default,
247 247 # because the run_cell() call above directly fires off exception
248 248 # reporting. This code, therefore, is only active in the scenario
249 249 # where runlines itself has an unhandled exception. We need to
250 250 # uniformize this, for all exception construction to come from a
251 251 # single location in the codbase.
252 252 etype, evalue, tb = sys.exc_info()
253 253 tb_list = traceback.format_exception(etype, evalue, tb)
254 254 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
255 255 else:
256 256 status = u'ok'
257 257
258 258 reply_content[u'status'] = status
259 259
260 260 # Return the execution counter so clients can display prompts
261 261 reply_content['execution_count'] = shell.execution_count -1
262 262
263 263 # FIXME - fish exception info out of shell, possibly left there by
264 264 # runlines. We'll need to clean up this logic later.
265 265 if shell._reply_content is not None:
266 266 reply_content.update(shell._reply_content)
267 267 # reset after use
268 268 shell._reply_content = None
269 269
270 270 # At this point, we can tell whether the main code execution succeeded
271 271 # or not. If it did, we proceed to evaluate user_variables/expressions
272 272 if reply_content['status'] == 'ok':
273 273 reply_content[u'user_variables'] = \
274 274 shell.user_variables(content[u'user_variables'])
275 275 reply_content[u'user_expressions'] = \
276 276 shell.user_expressions(content[u'user_expressions'])
277 277 else:
278 278 # If there was an error, don't even try to compute variables or
279 279 # expressions
280 280 reply_content[u'user_variables'] = {}
281 281 reply_content[u'user_expressions'] = {}
282 282
283 283 # Payloads should be retrieved regardless of outcome, so we can both
284 284 # recover partial output (that could have been generated early in a
285 285 # block, before an error) and clear the payload system always.
286 286 reply_content[u'payload'] = shell.payload_manager.read_payload()
287 287 # Be agressive about clearing the payload because we don't want
288 288 # it to sit in memory until the next execute_request comes in.
289 289 shell.payload_manager.clear_payload()
290 290
291 291 # Flush output before sending the reply.
292 292 sys.stdout.flush()
293 293 sys.stderr.flush()
294 294 # FIXME: on rare occasions, the flush doesn't seem to make it to the
295 295 # clients... This seems to mitigate the problem, but we definitely need
296 296 # to better understand what's going on.
297 297 if self._execute_sleep:
298 298 time.sleep(self._execute_sleep)
299 299
300 300 # Send the reply.
301 301 reply_msg = self.session.send(self.reply_socket, u'execute_reply',
302 302 reply_content, parent, ident=ident)
303 303 logger.debug(str(reply_msg))
304 304
305 305 if reply_msg['content']['status'] == u'error':
306 306 self._abort_queue()
307 307
308 308 status_msg = self.session.send(self.pub_socket,
309 309 u'status',
310 310 {u'execution_state':u'idle'},
311 311 parent=parent
312 312 )
313 313
314 314 def complete_request(self, ident, parent):
315 315 txt, matches = self._complete(parent)
316 316 matches = {'matches' : matches,
317 317 'matched_text' : txt,
318 318 'status' : 'ok'}
319 319 completion_msg = self.session.send(self.reply_socket, 'complete_reply',
320 320 matches, parent, ident)
321 321 logger.debug(str(completion_msg))
322 322
323 323 def object_info_request(self, ident, parent):
324 324 object_info = self.shell.object_inspect(parent['content']['oname'])
325 325 # Before we send this object over, we scrub it for JSON usage
326 326 oinfo = json_clean(object_info)
327 327 msg = self.session.send(self.reply_socket, 'object_info_reply',
328 328 oinfo, parent, ident)
329 329 logger.debug(msg)
330 330
331 331 def history_request(self, ident, parent):
332 332 # We need to pull these out, as passing **kwargs doesn't work with
333 333 # unicode keys before Python 2.6.5.
334 334 hist_access_type = parent['content']['hist_access_type']
335 335 raw = parent['content']['raw']
336 336 output = parent['content']['output']
337 337 if hist_access_type == 'tail':
338 338 n = parent['content']['n']
339 339 hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
340 340 include_latest=True)
341 341
342 342 elif hist_access_type == 'range':
343 343 session = parent['content']['session']
344 344 start = parent['content']['start']
345 345 stop = parent['content']['stop']
346 346 hist = self.shell.history_manager.get_range(session, start, stop,
347 347 raw=raw, output=output)
348 348
349 349 elif hist_access_type == 'search':
350 350 pattern = parent['content']['pattern']
351 351 hist = self.shell.history_manager.search(pattern, raw=raw, output=output)
352 352
353 353 else:
354 354 hist = []
355 355 content = {'history' : list(hist)}
356 356 msg = self.session.send(self.reply_socket, 'history_reply',
357 357 content, parent, ident)
358 358 logger.debug(str(msg))
359 359
360 360 def connect_request(self, ident, parent):
361 361 if self._recorded_ports is not None:
362 362 content = self._recorded_ports.copy()
363 363 else:
364 364 content = {}
365 365 msg = self.session.send(self.reply_socket, 'connect_reply',
366 366 content, parent, ident)
367 367 logger.debug(msg)
368 368
369 369 def shutdown_request(self, ident, parent):
370 370 self.shell.exit_now = True
371 371 self._shutdown_message = self.session.msg(u'shutdown_reply', parent['content'], parent)
372 372 sys.exit(0)
373 373
374 374 #---------------------------------------------------------------------------
375 375 # Protected interface
376 376 #---------------------------------------------------------------------------
377 377
378 378 def _abort_queue(self):
379 379 while True:
380 380 ident,msg = self.session.recv(self.reply_socket, zmq.NOBLOCK)
381 381 if msg is None:
382 382 break
383 383 else:
384 384 assert ident is not None, \
385 385 "Unexpected missing message part."
386 386
387 387 logger.debug("Aborting:\n"+str(Message(msg)))
388 388 msg_type = msg['msg_type']
389 389 reply_type = msg_type.split('_')[0] + '_reply'
390 390 reply_msg = self.session.send(self.reply_socket, reply_type,
391 391 {'status' : 'aborted'}, msg, ident=ident)
392 392 logger.debug(reply_msg)
393 393 # We need to wait a bit for requests to come in. This can probably
394 394 # be set shorter for true asynchronous clients.
395 395 time.sleep(0.1)
396 396
397 397 def _raw_input(self, prompt, ident, parent):
398 398 # Flush output before making the request.
399 399 sys.stderr.flush()
400 400 sys.stdout.flush()
401 401
402 402 # Send the input request.
403 403 content = dict(prompt=prompt)
404 404 msg = self.session.send(self.req_socket, u'input_request', content, parent)
405 405
406 406 # Await a response.
407 407 ident, reply = self.session.recv(self.req_socket, 0)
408 408 try:
409 409 value = reply['content']['value']
410 410 except:
411 411 logger.error("Got bad raw_input reply: ")
412 412 logger.error(str(Message(parent)))
413 413 value = ''
414 414 return value
415 415
416 416 def _complete(self, msg):
417 417 c = msg['content']
418 418 try:
419 419 cpos = int(c['cursor_pos'])
420 420 except:
421 421 # If we don't get something that we can convert to an integer, at
422 422 # least attempt the completion guessing the cursor is at the end of
423 423 # the text, if there's any, and otherwise of the line
424 424 cpos = len(c['text'])
425 425 if cpos==0:
426 426 cpos = len(c['line'])
427 427 return self.shell.complete(c['text'], c['line'], cpos)
428 428
429 429 def _object_info(self, context):
430 430 symbol, leftover = self._symbol_from_context(context)
431 431 if symbol is not None and not leftover:
432 432 doc = getattr(symbol, '__doc__', '')
433 433 else:
434 434 doc = ''
435 435 object_info = dict(docstring = doc)
436 436 return object_info
437 437
438 438 def _symbol_from_context(self, context):
439 439 if not context:
440 440 return None, context
441 441
442 442 base_symbol_string = context[0]
443 443 symbol = self.shell.user_ns.get(base_symbol_string, None)
444 444 if symbol is None:
445 445 symbol = __builtin__.__dict__.get(base_symbol_string, None)
446 446 if symbol is None:
447 447 return None, context
448 448
449 449 context = context[1:]
450 450 for i, name in enumerate(context):
451 451 new_symbol = getattr(symbol, name, None)
452 452 if new_symbol is None:
453 453 return symbol, context[i:]
454 454 else:
455 455 symbol = new_symbol
456 456
457 457 return symbol, []
458 458
459 459 def _at_shutdown(self):
460 460 """Actions taken at shutdown by the kernel, called by python's atexit.
461 461 """
462 462 # io.rprint("Kernel at_shutdown") # dbg
463 463 if self._shutdown_message is not None:
464 464 self.session.send(self.reply_socket, self._shutdown_message)
465 465 self.session.send(self.pub_socket, self._shutdown_message)
466 466 logger.debug(str(self._shutdown_message))
467 467 # A very short sleep to give zmq time to flush its message buffers
468 468 # before Python truly shuts down.
469 469 time.sleep(0.01)
470 470
471 471
472 472 class QtKernel(Kernel):
473 473 """A Kernel subclass with Qt support."""
474 474
475 475 def start(self):
476 476 """Start a kernel with QtPy4 event loop integration."""
477 477
478 478 from PyQt4 import QtCore
479 479 from IPython.lib.guisupport import get_app_qt4, start_event_loop_qt4
480 480
481 481 self.app = get_app_qt4([" "])
482 482 self.app.setQuitOnLastWindowClosed(False)
483 483 self.timer = QtCore.QTimer()
484 484 self.timer.timeout.connect(self.do_one_iteration)
485 485 # Units for the timer are in milliseconds
486 486 self.timer.start(1000*self._poll_interval)
487 487 start_event_loop_qt4(self.app)
488 488
489 489
490 490 class WxKernel(Kernel):
491 491 """A Kernel subclass with Wx support."""
492 492
493 493 def start(self):
494 494 """Start a kernel with wx event loop support."""
495 495
496 496 import wx
497 497 from IPython.lib.guisupport import start_event_loop_wx
498 498
499 499 doi = self.do_one_iteration
500 500 # Wx uses milliseconds
501 501 poll_interval = int(1000*self._poll_interval)
502 502
503 503 # We have to put the wx.Timer in a wx.Frame for it to fire properly.
504 504 # We make the Frame hidden when we create it in the main app below.
505 505 class TimerFrame(wx.Frame):
506 506 def __init__(self, func):
507 507 wx.Frame.__init__(self, None, -1)
508 508 self.timer = wx.Timer(self)
509 509 # Units for the timer are in milliseconds
510 510 self.timer.Start(poll_interval)
511 511 self.Bind(wx.EVT_TIMER, self.on_timer)
512 512 self.func = func
513 513
514 514 def on_timer(self, event):
515 515 self.func()
516 516
517 517 # We need a custom wx.App to create our Frame subclass that has the
518 518 # wx.Timer to drive the ZMQ event loop.
519 519 class IPWxApp(wx.App):
520 520 def OnInit(self):
521 521 self.frame = TimerFrame(doi)
522 522 self.frame.Show(False)
523 523 return True
524 524
525 525 # The redirect=False here makes sure that wx doesn't replace
526 526 # sys.stdout/stderr with its own classes.
527 527 self.app = IPWxApp(redirect=False)
528 528 start_event_loop_wx(self.app)
529 529
530 530
531 531 class TkKernel(Kernel):
532 532 """A Kernel subclass with Tk support."""
533 533
534 534 def start(self):
535 535 """Start a Tk enabled event loop."""
536 536
537 537 import Tkinter
538 538 doi = self.do_one_iteration
539 539 # Tk uses milliseconds
540 540 poll_interval = int(1000*self._poll_interval)
541 541 # For Tkinter, we create a Tk object and call its withdraw method.
542 542 class Timer(object):
543 543 def __init__(self, func):
544 544 self.app = Tkinter.Tk()
545 545 self.app.withdraw()
546 546 self.func = func
547 547
548 548 def on_timer(self):
549 549 self.func()
550 550 self.app.after(poll_interval, self.on_timer)
551 551
552 552 def start(self):
553 553 self.on_timer() # Call it once to get things going.
554 554 self.app.mainloop()
555 555
556 556 self.timer = Timer(doi)
557 557 self.timer.start()
558 558
559 559
560 560 class GTKKernel(Kernel):
561 561 """A Kernel subclass with GTK support."""
562 562
563 563 def start(self):
564 564 """Start the kernel, coordinating with the GTK event loop"""
565 565 from .gui.gtkembed import GTKEmbed
566 566
567 567 gtk_kernel = GTKEmbed(self)
568 568 gtk_kernel.start()
569 569
570 570
571 571 #-----------------------------------------------------------------------------
572 572 # Kernel main and launch functions
573 573 #-----------------------------------------------------------------------------
574 574
575 575 def launch_kernel(ip=None, xrep_port=0, pub_port=0, req_port=0, hb_port=0,
576 576 stdin=None, stdout=None, stderr=None,
577 577 executable=None, independent=False, pylab=False, colors=None):
578 578 """Launches a localhost kernel, binding to the specified ports.
579 579
580 580 Parameters
581 581 ----------
582 582 ip : str, optional
583 583 The ip address the kernel will bind to.
584 584
585 585 xrep_port : int, optional
586 586 The port to use for XREP channel.
587 587
588 588 pub_port : int, optional
589 589 The port to use for the SUB channel.
590 590
591 591 req_port : int, optional
592 592 The port to use for the REQ (raw input) channel.
593 593
594 594 hb_port : int, optional
595 595 The port to use for the hearbeat REP channel.
596 596
597 597 stdin, stdout, stderr : optional (default None)
598 598 Standards streams, as defined in subprocess.Popen.
599 599
600 600 executable : str, optional (default sys.executable)
601 601 The Python executable to use for the kernel process.
602 602
603 603 independent : bool, optional (default False)
604 604 If set, the kernel process is guaranteed to survive if this process
605 605 dies. If not set, an effort is made to ensure that the kernel is killed
606 606 when this process dies. Note that in this case it is still good practice
607 607 to kill kernels manually before exiting.
608 608
609 609 pylab : bool or string, optional (default False)
610 610 If not False, the kernel will be launched with pylab enabled. If a
611 611 string is passed, matplotlib will use the specified backend. Otherwise,
612 612 matplotlib's default backend will be used.
613 613
614 614 colors : None or string, optional (default None)
615 615 If not None, specify the color scheme. One of (NoColor, LightBG, Linux)
616 616
617 617 Returns
618 618 -------
619 619 A tuple of form:
620 620 (kernel_process, xrep_port, pub_port, req_port)
621 621 where kernel_process is a Popen object and the ports are integers.
622 622 """
623 623 extra_arguments = []
624 624 if pylab:
625 625 extra_arguments.append('--pylab')
626 626 if isinstance(pylab, basestring):
627 627 extra_arguments.append(pylab)
628 628 if ip is not None:
629 629 extra_arguments.append('--ip')
630 630 if isinstance(ip, basestring):
631 631 extra_arguments.append(ip)
632 632 if colors is not None:
633 633 extra_arguments.append('--colors')
634 634 extra_arguments.append(colors)
635 635 return base_launch_kernel('from IPython.zmq.ipkernel import main; main()',
636 636 xrep_port, pub_port, req_port, hb_port,
637 637 stdin, stdout, stderr,
638 638 executable, independent, extra_arguments)
639 639
640 640
641 641 def main():
642 642 """ The IPython kernel main entry point.
643 643 """
644 644 parser = make_argument_parser()
645 645 parser.add_argument('--pylab', type=str, metavar='GUI', nargs='?',
646 646 const='auto', help = \
647 647 "Pre-load matplotlib and numpy for interactive use. If GUI is not \
648 648 given, the GUI backend is matplotlib's, otherwise use one of: \
649 649 ['tk', 'gtk', 'qt', 'wx', 'osx', 'inline'].")
650 650 parser.add_argument('--colors',
651 651 type=str, dest='colors',
652 652 help="Set the color scheme (NoColor, Linux, and LightBG).",
653 653 metavar='ZMQInteractiveShell.colors')
654 654 namespace = parser.parse_args()
655 655
656 656 kernel_class = Kernel
657 657
658 658 kernel_classes = {
659 659 'qt' : QtKernel,
660 660 'qt4': QtKernel,
661 661 'inline': Kernel,
662 662 'osx': TkKernel,
663 663 'wx' : WxKernel,
664 664 'tk' : TkKernel,
665 665 'gtk': GTKKernel,
666 666 }
667 667 if namespace.pylab:
668 668 if namespace.pylab == 'auto':
669 669 gui, backend = pylabtools.find_gui_and_backend()
670 670 else:
671 671 gui, backend = pylabtools.find_gui_and_backend(namespace.pylab)
672 672 kernel_class = kernel_classes.get(gui)
673 673 if kernel_class is None:
674 674 raise ValueError('GUI is not supported: %r' % gui)
675 675 pylabtools.activate_matplotlib(backend)
676 676 if namespace.colors:
677 677 ZMQInteractiveShell.colors=namespace.colors
678 678
679 679 kernel = make_kernel(namespace, kernel_class, OutStream)
680 680
681 681 if namespace.pylab:
682 682 pylabtools.import_pylab(kernel.shell.user_ns, backend,
683 683 shell=kernel.shell)
684 684
685 685 start_kernel(namespace, kernel)
686 686
687 687
688 688 if __name__ == '__main__':
689 689 main()
General Comments 0
You need to be logged in to leave comments. Login now