##// END OF EJS Templates
IPKernelApp now based on InteractiveShellApp
MinRK -
Show More
@@ -1,746 +1,673 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.config.application import boolean_flag
31 31 from IPython.core.newapplication import ProfileDir
32 from IPython.core.shellapp import (
33 InteractiveShellApp, shell_flags, shell_aliases
34 )
32 35 from IPython.utils import io
33 36 from IPython.utils.jsonutil import json_clean
34 37 from IPython.lib import pylabtools
35 38 from IPython.utils.traitlets import (
36 39 List, Instance, Float, Dict, Bool, Int, Unicode, CaselessStrEnum
37 40 )
41
38 42 from entry_point import base_launch_kernel
39 43 from kernelapp import KernelApp, kernel_flags, kernel_aliases
40 44 from iostream import OutStream
41 45 from session import Session, Message
42 46 from zmqshell import ZMQInteractiveShell
43 47
44 48
45 49
46 50 #-----------------------------------------------------------------------------
47 51 # Main kernel class
48 52 #-----------------------------------------------------------------------------
49 53
50 54 class Kernel(Configurable):
51 55
52 56 #---------------------------------------------------------------------------
53 57 # Kernel interface
54 58 #---------------------------------------------------------------------------
55 59
56 60 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
57 61 session = Instance(Session)
58 62 shell_socket = Instance('zmq.Socket')
59 63 iopub_socket = Instance('zmq.Socket')
60 64 stdin_socket = Instance('zmq.Socket')
61 65 log = Instance(logging.Logger)
62 66
63 67 # Private interface
64 68
65 69 # Time to sleep after flushing the stdout/err buffers in each execute
66 70 # cycle. While this introduces a hard limit on the minimal latency of the
67 71 # execute cycle, it helps prevent output synchronization problems for
68 72 # clients.
69 73 # Units are in seconds. The minimum zmq latency on local host is probably
70 74 # ~150 microseconds, set this to 500us for now. We may need to increase it
71 75 # a little if it's not enough after more interactive testing.
72 76 _execute_sleep = Float(0.0005, config=True)
73 77
74 78 # Frequency of the kernel's event loop.
75 79 # Units are in seconds, kernel subclasses for GUI toolkits may need to
76 80 # adapt to milliseconds.
77 81 _poll_interval = Float(0.05, config=True)
78 82
79 83 # If the shutdown was requested over the network, we leave here the
80 84 # necessary reply message so it can be sent by our registered atexit
81 85 # handler. This ensures that the reply is only sent to clients truly at
82 86 # the end of our shutdown process (which happens after the underlying
83 87 # IPython shell's own shutdown).
84 88 _shutdown_message = None
85 89
86 90 # This is a dict of port number that the kernel is listening on. It is set
87 91 # by record_ports and used by connect_request.
88 92 _recorded_ports = Dict()
89 93
90 94
91 95
92 96 def __init__(self, **kwargs):
93 97 super(Kernel, self).__init__(**kwargs)
94 98
95 99 # Before we even start up the shell, register *first* our exit handlers
96 100 # so they come before the shell's
97 101 atexit.register(self._at_shutdown)
98 102
99 103 # Initialize the InteractiveShell subclass
100 104 self.shell = ZMQInteractiveShell.instance(config=self.config)
101 105 self.shell.displayhook.session = self.session
102 106 self.shell.displayhook.pub_socket = self.iopub_socket
103 107 self.shell.display_pub.session = self.session
104 108 self.shell.display_pub.pub_socket = self.iopub_socket
105 109
106 110 # TMP - hack while developing
107 111 self.shell._reply_content = None
108 112
109 113 # Build dict of handlers for message types
110 114 msg_types = [ 'execute_request', 'complete_request',
111 115 'object_info_request', 'history_request',
112 116 'connect_request', 'shutdown_request']
113 117 self.handlers = {}
114 118 for msg_type in msg_types:
115 119 self.handlers[msg_type] = getattr(self, msg_type)
116 120
117 121 def do_one_iteration(self):
118 122 """Do one iteration of the kernel's evaluation loop.
119 123 """
120 124 ident,msg = self.session.recv(self.shell_socket, zmq.NOBLOCK)
121 125 if msg is None:
122 126 return
123 127
124 128 # This assert will raise in versions of zeromq 2.0.7 and lesser.
125 129 # We now require 2.0.8 or above, so we can uncomment for safety.
126 130 # print(ident,msg, file=sys.__stdout__)
127 131 assert ident is not None, "Missing message part."
128 132
129 133 # Print some info about this message and leave a '--->' marker, so it's
130 134 # easier to trace visually the message chain when debugging. Each
131 135 # handler prints its message at the end.
132 136 self.log.debug('\n*** MESSAGE TYPE:'+str(msg['msg_type'])+'***')
133 137 self.log.debug(' Content: '+str(msg['content'])+'\n --->\n ')
134 138
135 139 # Find and call actual handler for message
136 140 handler = self.handlers.get(msg['msg_type'], None)
137 141 if handler is None:
138 142 self.log.error("UNKNOWN MESSAGE TYPE:" +str(msg))
139 143 else:
140 144 handler(ident, msg)
141 145
142 146 # Check whether we should exit, in case the incoming message set the
143 147 # exit flag on
144 148 if self.shell.exit_now:
145 149 self.log.debug('\nExiting IPython kernel...')
146 150 # We do a normal, clean exit, which allows any actions registered
147 151 # via atexit (such as history saving) to take place.
148 152 sys.exit(0)
149 153
150 154
151 155 def start(self):
152 156 """ Start the kernel main loop.
153 157 """
154 158 poller = zmq.Poller()
155 159 poller.register(self.shell_socket, zmq.POLLIN)
156 160 while True:
157 161 try:
158 162 # scale by extra factor of 10, because there is no
159 163 # reason for this to be anything less than ~ 0.1s
160 164 # since it is a real poller and will respond
161 165 # to events immediately
162 166 poller.poll(10*1000*self._poll_interval)
163 167 self.do_one_iteration()
164 168 except KeyboardInterrupt:
165 169 # Ctrl-C shouldn't crash the kernel
166 170 io.raw_print("KeyboardInterrupt caught in kernel")
167 171
168 172 def record_ports(self, ports):
169 173 """Record the ports that this kernel is using.
170 174
171 175 The creator of the Kernel instance must call this methods if they
172 176 want the :meth:`connect_request` method to return the port numbers.
173 177 """
174 178 self._recorded_ports = ports
175 179
176 180 #---------------------------------------------------------------------------
177 181 # Kernel request handlers
178 182 #---------------------------------------------------------------------------
179 183
180 184 def _publish_pyin(self, code, parent):
181 185 """Publish the code request on the pyin stream."""
182 186
183 187 pyin_msg = self.session.send(self.iopub_socket, u'pyin',{u'code':code}, parent=parent)
184 188
185 189 def execute_request(self, ident, parent):
186 190
187 191 status_msg = self.session.send(self.iopub_socket,
188 192 u'status',
189 193 {u'execution_state':u'busy'},
190 194 parent=parent
191 195 )
192 196
193 197 try:
194 198 content = parent[u'content']
195 199 code = content[u'code']
196 200 silent = content[u'silent']
197 201 except:
198 202 self.log.error("Got bad msg: ")
199 203 self.log.error(str(Message(parent)))
200 204 return
201 205
202 206 shell = self.shell # we'll need this a lot here
203 207
204 208 # Replace raw_input. Note that is not sufficient to replace
205 209 # raw_input in the user namespace.
206 210 raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
207 211 __builtin__.raw_input = raw_input
208 212
209 213 # Set the parent message of the display hook and out streams.
210 214 shell.displayhook.set_parent(parent)
211 215 shell.display_pub.set_parent(parent)
212 216 sys.stdout.set_parent(parent)
213 217 sys.stderr.set_parent(parent)
214 218
215 219 # Re-broadcast our input for the benefit of listening clients, and
216 220 # start computing output
217 221 if not silent:
218 222 self._publish_pyin(code, parent)
219 223
220 224 reply_content = {}
221 225 try:
222 226 if silent:
223 227 # run_code uses 'exec' mode, so no displayhook will fire, and it
224 228 # doesn't call logging or history manipulations. Print
225 229 # statements in that code will obviously still execute.
226 230 shell.run_code(code)
227 231 else:
228 232 # FIXME: the shell calls the exception handler itself.
229 233 shell.run_cell(code)
230 234 except:
231 235 status = u'error'
232 236 # FIXME: this code right now isn't being used yet by default,
233 237 # because the run_cell() call above directly fires off exception
234 238 # reporting. This code, therefore, is only active in the scenario
235 239 # where runlines itself has an unhandled exception. We need to
236 240 # uniformize this, for all exception construction to come from a
237 241 # single location in the codbase.
238 242 etype, evalue, tb = sys.exc_info()
239 243 tb_list = traceback.format_exception(etype, evalue, tb)
240 244 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
241 245 else:
242 246 status = u'ok'
243 247
244 248 reply_content[u'status'] = status
245 249
246 250 # Return the execution counter so clients can display prompts
247 251 reply_content['execution_count'] = shell.execution_count -1
248 252
249 253 # FIXME - fish exception info out of shell, possibly left there by
250 254 # runlines. We'll need to clean up this logic later.
251 255 if shell._reply_content is not None:
252 256 reply_content.update(shell._reply_content)
253 257 # reset after use
254 258 shell._reply_content = None
255 259
256 260 # At this point, we can tell whether the main code execution succeeded
257 261 # or not. If it did, we proceed to evaluate user_variables/expressions
258 262 if reply_content['status'] == 'ok':
259 263 reply_content[u'user_variables'] = \
260 264 shell.user_variables(content[u'user_variables'])
261 265 reply_content[u'user_expressions'] = \
262 266 shell.user_expressions(content[u'user_expressions'])
263 267 else:
264 268 # If there was an error, don't even try to compute variables or
265 269 # expressions
266 270 reply_content[u'user_variables'] = {}
267 271 reply_content[u'user_expressions'] = {}
268 272
269 273 # Payloads should be retrieved regardless of outcome, so we can both
270 274 # recover partial output (that could have been generated early in a
271 275 # block, before an error) and clear the payload system always.
272 276 reply_content[u'payload'] = shell.payload_manager.read_payload()
273 277 # Be agressive about clearing the payload because we don't want
274 278 # it to sit in memory until the next execute_request comes in.
275 279 shell.payload_manager.clear_payload()
276 280
277 281 # Flush output before sending the reply.
278 282 sys.stdout.flush()
279 283 sys.stderr.flush()
280 284 # FIXME: on rare occasions, the flush doesn't seem to make it to the
281 285 # clients... This seems to mitigate the problem, but we definitely need
282 286 # to better understand what's going on.
283 287 if self._execute_sleep:
284 288 time.sleep(self._execute_sleep)
285 289
286 290 # Send the reply.
287 291 reply_msg = self.session.send(self.shell_socket, u'execute_reply',
288 292 reply_content, parent, ident=ident)
289 293 self.log.debug(str(reply_msg))
290 294
291 295 if reply_msg['content']['status'] == u'error':
292 296 self._abort_queue()
293 297
294 298 status_msg = self.session.send(self.iopub_socket,
295 299 u'status',
296 300 {u'execution_state':u'idle'},
297 301 parent=parent
298 302 )
299 303
300 304 def complete_request(self, ident, parent):
301 305 txt, matches = self._complete(parent)
302 306 matches = {'matches' : matches,
303 307 'matched_text' : txt,
304 308 'status' : 'ok'}
305 309 completion_msg = self.session.send(self.shell_socket, 'complete_reply',
306 310 matches, parent, ident)
307 311 self.log.debug(str(completion_msg))
308 312
309 313 def object_info_request(self, ident, parent):
310 314 object_info = self.shell.object_inspect(parent['content']['oname'])
311 315 # Before we send this object over, we scrub it for JSON usage
312 316 oinfo = json_clean(object_info)
313 317 msg = self.session.send(self.shell_socket, 'object_info_reply',
314 318 oinfo, parent, ident)
315 319 self.log.debug(msg)
316 320
317 321 def history_request(self, ident, parent):
318 322 # We need to pull these out, as passing **kwargs doesn't work with
319 323 # unicode keys before Python 2.6.5.
320 324 hist_access_type = parent['content']['hist_access_type']
321 325 raw = parent['content']['raw']
322 326 output = parent['content']['output']
323 327 if hist_access_type == 'tail':
324 328 n = parent['content']['n']
325 329 hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
326 330 include_latest=True)
327 331
328 332 elif hist_access_type == 'range':
329 333 session = parent['content']['session']
330 334 start = parent['content']['start']
331 335 stop = parent['content']['stop']
332 336 hist = self.shell.history_manager.get_range(session, start, stop,
333 337 raw=raw, output=output)
334 338
335 339 elif hist_access_type == 'search':
336 340 pattern = parent['content']['pattern']
337 341 hist = self.shell.history_manager.search(pattern, raw=raw, output=output)
338 342
339 343 else:
340 344 hist = []
341 345 content = {'history' : list(hist)}
342 346 msg = self.session.send(self.shell_socket, 'history_reply',
343 347 content, parent, ident)
344 348 self.log.debug(str(msg))
345 349
346 350 def connect_request(self, ident, parent):
347 351 if self._recorded_ports is not None:
348 352 content = self._recorded_ports.copy()
349 353 else:
350 354 content = {}
351 355 msg = self.session.send(self.shell_socket, 'connect_reply',
352 356 content, parent, ident)
353 357 self.log.debug(msg)
354 358
355 359 def shutdown_request(self, ident, parent):
356 360 self.shell.exit_now = True
357 361 self._shutdown_message = self.session.msg(u'shutdown_reply', parent['content'], parent)
358 362 sys.exit(0)
359 363
360 364 #---------------------------------------------------------------------------
361 365 # Protected interface
362 366 #---------------------------------------------------------------------------
363 367
364 368 def _abort_queue(self):
365 369 while True:
366 370 ident,msg = self.session.recv(self.shell_socket, zmq.NOBLOCK)
367 371 if msg is None:
368 372 break
369 373 else:
370 374 assert ident is not None, \
371 375 "Unexpected missing message part."
372 376
373 377 self.log.debug("Aborting:\n"+str(Message(msg)))
374 378 msg_type = msg['msg_type']
375 379 reply_type = msg_type.split('_')[0] + '_reply'
376 380 reply_msg = self.session.send(self.shell_socket, reply_type,
377 381 {'status' : 'aborted'}, msg, ident=ident)
378 382 self.log.debug(reply_msg)
379 383 # We need to wait a bit for requests to come in. This can probably
380 384 # be set shorter for true asynchronous clients.
381 385 time.sleep(0.1)
382 386
383 387 def _raw_input(self, prompt, ident, parent):
384 388 # Flush output before making the request.
385 389 sys.stderr.flush()
386 390 sys.stdout.flush()
387 391
388 392 # Send the input request.
389 393 content = dict(prompt=prompt)
390 394 msg = self.session.send(self.stdin_socket, u'input_request', content, parent)
391 395
392 396 # Await a response.
393 397 ident, reply = self.session.recv(self.stdin_socket, 0)
394 398 try:
395 399 value = reply['content']['value']
396 400 except:
397 401 self.log.error("Got bad raw_input reply: ")
398 402 self.log.error(str(Message(parent)))
399 403 value = ''
400 404 return value
401 405
402 406 def _complete(self, msg):
403 407 c = msg['content']
404 408 try:
405 409 cpos = int(c['cursor_pos'])
406 410 except:
407 411 # If we don't get something that we can convert to an integer, at
408 412 # least attempt the completion guessing the cursor is at the end of
409 413 # the text, if there's any, and otherwise of the line
410 414 cpos = len(c['text'])
411 415 if cpos==0:
412 416 cpos = len(c['line'])
413 417 return self.shell.complete(c['text'], c['line'], cpos)
414 418
415 419 def _object_info(self, context):
416 420 symbol, leftover = self._symbol_from_context(context)
417 421 if symbol is not None and not leftover:
418 422 doc = getattr(symbol, '__doc__', '')
419 423 else:
420 424 doc = ''
421 425 object_info = dict(docstring = doc)
422 426 return object_info
423 427
424 428 def _symbol_from_context(self, context):
425 429 if not context:
426 430 return None, context
427 431
428 432 base_symbol_string = context[0]
429 433 symbol = self.shell.user_ns.get(base_symbol_string, None)
430 434 if symbol is None:
431 435 symbol = __builtin__.__dict__.get(base_symbol_string, None)
432 436 if symbol is None:
433 437 return None, context
434 438
435 439 context = context[1:]
436 440 for i, name in enumerate(context):
437 441 new_symbol = getattr(symbol, name, None)
438 442 if new_symbol is None:
439 443 return symbol, context[i:]
440 444 else:
441 445 symbol = new_symbol
442 446
443 447 return symbol, []
444 448
445 449 def _at_shutdown(self):
446 450 """Actions taken at shutdown by the kernel, called by python's atexit.
447 451 """
448 452 # io.rprint("Kernel at_shutdown") # dbg
449 453 if self._shutdown_message is not None:
450 454 self.session.send(self.shell_socket, self._shutdown_message)
451 455 self.session.send(self.iopub_socket, self._shutdown_message)
452 456 self.log.debug(str(self._shutdown_message))
453 457 # A very short sleep to give zmq time to flush its message buffers
454 458 # before Python truly shuts down.
455 459 time.sleep(0.01)
456 460
457 461
458 462 class QtKernel(Kernel):
459 463 """A Kernel subclass with Qt support."""
460 464
461 465 def start(self):
462 466 """Start a kernel with QtPy4 event loop integration."""
463 467
464 468 from PyQt4 import QtCore
465 469 from IPython.lib.guisupport import get_app_qt4, start_event_loop_qt4
466 470
467 471 self.app = get_app_qt4([" "])
468 472 self.app.setQuitOnLastWindowClosed(False)
469 473 self.timer = QtCore.QTimer()
470 474 self.timer.timeout.connect(self.do_one_iteration)
471 475 # Units for the timer are in milliseconds
472 476 self.timer.start(1000*self._poll_interval)
473 477 start_event_loop_qt4(self.app)
474 478
475 479
476 480 class WxKernel(Kernel):
477 481 """A Kernel subclass with Wx support."""
478 482
479 483 def start(self):
480 484 """Start a kernel with wx event loop support."""
481 485
482 486 import wx
483 487 from IPython.lib.guisupport import start_event_loop_wx
484 488
485 489 doi = self.do_one_iteration
486 490 # Wx uses milliseconds
487 491 poll_interval = int(1000*self._poll_interval)
488 492
489 493 # We have to put the wx.Timer in a wx.Frame for it to fire properly.
490 494 # We make the Frame hidden when we create it in the main app below.
491 495 class TimerFrame(wx.Frame):
492 496 def __init__(self, func):
493 497 wx.Frame.__init__(self, None, -1)
494 498 self.timer = wx.Timer(self)
495 499 # Units for the timer are in milliseconds
496 500 self.timer.Start(poll_interval)
497 501 self.Bind(wx.EVT_TIMER, self.on_timer)
498 502 self.func = func
499 503
500 504 def on_timer(self, event):
501 505 self.func()
502 506
503 507 # We need a custom wx.App to create our Frame subclass that has the
504 508 # wx.Timer to drive the ZMQ event loop.
505 509 class IPWxApp(wx.App):
506 510 def OnInit(self):
507 511 self.frame = TimerFrame(doi)
508 512 self.frame.Show(False)
509 513 return True
510 514
511 515 # The redirect=False here makes sure that wx doesn't replace
512 516 # sys.stdout/stderr with its own classes.
513 517 self.app = IPWxApp(redirect=False)
514 518 start_event_loop_wx(self.app)
515 519
516 520
517 521 class TkKernel(Kernel):
518 522 """A Kernel subclass with Tk support."""
519 523
520 524 def start(self):
521 525 """Start a Tk enabled event loop."""
522 526
523 527 import Tkinter
524 528 doi = self.do_one_iteration
525 529 # Tk uses milliseconds
526 530 poll_interval = int(1000*self._poll_interval)
527 531 # For Tkinter, we create a Tk object and call its withdraw method.
528 532 class Timer(object):
529 533 def __init__(self, func):
530 534 self.app = Tkinter.Tk()
531 535 self.app.withdraw()
532 536 self.func = func
533 537
534 538 def on_timer(self):
535 539 self.func()
536 540 self.app.after(poll_interval, self.on_timer)
537 541
538 542 def start(self):
539 543 self.on_timer() # Call it once to get things going.
540 544 self.app.mainloop()
541 545
542 546 self.timer = Timer(doi)
543 547 self.timer.start()
544 548
545 549
546 550 class GTKKernel(Kernel):
547 551 """A Kernel subclass with GTK support."""
548 552
549 553 def start(self):
550 554 """Start the kernel, coordinating with the GTK event loop"""
551 555 from .gui.gtkembed import GTKEmbed
552 556
553 557 gtk_kernel = GTKEmbed(self)
554 558 gtk_kernel.start()
555 559
556 560
557 561 #-----------------------------------------------------------------------------
558 562 # Aliases and Flags for the IPKernelApp
559 563 #-----------------------------------------------------------------------------
560 564
561 565 flags = dict(kernel_flags)
566 flags.update(shell_flags)
562 567
563 568 addflag = lambda *args: flags.update(boolean_flag(*args))
564 addflag('automagic', 'InteractiveShell.automagic',
565 """Turn on the auto calling of magic commands. Type %%magic at the
566 IPython prompt for more information.""",
567 'Turn off the auto calling of magic commands.'
568 )
569 addflag('banner', 'InteractiveShell.display_banner',
570 "Display a banner upon starting IPython.",
571 "Don't display a banner upon starting IPython."
572 )
573 addflag('pdb', 'InteractiveShell.pdb',
574 "Enable auto calling the pdb debugger after every exception.",
575 "Disable auto calling the pdb debugger after every exception."
576 )
577 addflag('pprint', 'PlainTextFormatter.pprint',
578 "Enable auto pretty printing of results.",
579 "Disable auto auto pretty printing of results."
580 )
581 addflag('color-info', 'InteractiveShell.color_info',
582 """IPython can display information about objects via a set of func-
583 tions, and optionally can use colors for this, syntax highlighting
584 source code and various other elements. However, because this
585 information is passed through a pager (like 'less') and many pagers get
586 confused with color codes, this option is off by default. You can test
587 it and turn it on permanently in your ipython_config.py file if it
588 works for you. Test it and turn it on permanently if it works with
589 your system. The magic function %%color_info allows you to toggle this
590 inter- actively for testing.""",
591 "Disable using colors for info related things."
592 )
593 addflag('deep-reload', 'InteractiveShell.deep_reload',
594 """Enable deep (recursive) reloading by default. IPython can use the
595 deep_reload module which reloads changes in modules recursively (it
596 replaces the reload() function, so you don't need to change anything to
597 use it). deep_reload() forces a full reload of modules whose code may
598 have changed, which the default reload() function does not. When
599 deep_reload is off, IPython will use the normal reload(), but
600 deep_reload will still be available as dreload(). This fea- ture is off
601 by default [which means that you have both normal reload() and
602 dreload()].""",
603 "Disable deep (recursive) reloading by default."
604 )
605 addflag('readline', 'InteractiveShell.readline_use',
606 "Enable readline for command line usage.",
607 "Disable readline for command line usage."
608 )
609 569
610 570 flags['pylab'] = (
611 571 {'IPKernelApp' : {'pylab' : 'auto'}},
612 572 """Pre-load matplotlib and numpy for interactive use with
613 573 the default matplotlib backend."""
614 574 )
615 575
616 576 aliases = dict(kernel_aliases)
577 aliases.update(shell_aliases)
617 578
618 579 # it's possible we don't want short aliases for *all* of these:
619 580 aliases.update(dict(
620 autocall='InteractiveShell.autocall',
621 cache_size='InteractiveShell.cache_size',
622 colors='InteractiveShell.colors',
623 logfile='InteractiveShell.logfile',
624 log_append='InteractiveShell.logappend',
625 pi1='InteractiveShell.prompt_in1',
626 pi2='InteractiveShell.prompt_in2',
627 po='InteractiveShell.prompt_out',
628 si='InteractiveShell.separate_in',
629 so='InteractiveShell.separate_out',
630 so2='InteractiveShell.separate_out2',
631 xmode='InteractiveShell.xmode',
632 c='IPKernelApp.code_to_run',
633 ext='IPKernelApp.extra_extension',
634 581 pylab='IPKernelApp.pylab',
635 582 ))
636 583
637 584 #-----------------------------------------------------------------------------
638 585 # The IPKernelApp class
639 586 #-----------------------------------------------------------------------------
640 587
641 class IPKernelApp(KernelApp):
588 class IPKernelApp(KernelApp, InteractiveShellApp):
642 589 name = 'ipkernel'
643 590
644 591 aliases = Dict(aliases)
645 592 flags = Dict(flags)
646 593 classes = [Kernel, ZMQInteractiveShell, ProfileDir]
647 594 # configurables
648 595 pylab = CaselessStrEnum(['tk', 'qt', 'wx', 'gtk', 'osx', 'inline', 'auto'],
649 596 config=True,
650 597 help="""Pre-load matplotlib and numpy for interactive use,
651 598 selecting a particular matplotlib backend and loop integration.
652 599 """
653 600 )
654 extensions = List(Unicode, config=True,
655 help="A list of dotted module names of IPython extensions to load."
656 )
657 extra_extension = Unicode('', config=True,
658 help="dotted module name of an IPython extension to load."
659 )
660 def _extra_extension_changed(self, name, old, new):
661 if new:
662 # add to self.extensions
663 self.extensions.append(new)
664
665 exec_files = List(Unicode, config=True,
666 help="""List of files to run at IPython startup."""
667 )
668 file_to_run = Unicode('', config=True,
669 help="""A file to be run""")
670 def _file_to_run_changed(self, name, old, new):
671 self.exec_files.append(new)
672
673 exec_lines = List(Unicode, config=True,
674 help="""lines of code to run at IPython startup."""
675 )
676 code_to_run = Unicode('', config=True,
677 help="Execute the given command string."
678 )
679 def _code_to_run_changed(self, name, old, new):
680 self.exec_lines.append(new)
601 def initialize(self, argv=None):
602 super(IPKernelApp, self).initialize(argv)
603 self.init_shell()
604 self.init_extensions()
605 self.init_code()
681 606
682 607 def init_kernel(self):
683 608 kernel_factory = Kernel
684 609
685 610 kernel_map = {
686 611 'qt' : QtKernel,
687 612 'qt4': QtKernel,
688 613 'inline': Kernel,
689 614 'osx': TkKernel,
690 615 'wx' : WxKernel,
691 616 'tk' : TkKernel,
692 617 'gtk': GTKKernel,
693 618 }
694 619
695 620 if self.pylab:
696 621 key = None if self.pylab == 'auto' else self.pylab
697 622 gui, backend = pylabtools.find_gui_and_backend(key)
698 623 kernel_factory = kernel_map.get(gui)
699 624 if kernel_factory is None:
700 625 raise ValueError('GUI is not supported: %r' % gui)
701 626 pylabtools.activate_matplotlib(backend)
702 627
703 628 kernel = kernel_factory(config=self.config, session=self.session,
704 629 shell_socket=self.shell_socket,
705 630 iopub_socket=self.iopub_socket,
706 631 stdin_socket=self.stdin_socket,
707 632 log=self.log
708 633 )
709 634 self.kernel = kernel
710 635 kernel.record_ports(self.ports)
711 636
712 637 if self.pylab:
713 638 pylabtools.import_pylab(kernel.shell.user_ns, backend,
714 639 shell=kernel.shell)
715
640
641 def init_shell(self):
642 self.shell = self.kernel.shell
716 643
717 644
718 645 #-----------------------------------------------------------------------------
719 646 # Kernel main and launch functions
720 647 #-----------------------------------------------------------------------------
721 648
722 649 def launch_kernel(*args, **kwargs):
723 650 """Launches a localhost IPython kernel, binding to the specified ports.
724 651
725 652 This function simply calls entry_point.base_launch_kernel with the right first
726 653 command to start an ipkernel. See base_launch_kernel for arguments.
727 654
728 655 Returns
729 656 -------
730 657 A tuple of form:
731 658 (kernel_process, shell_port, iopub_port, stdin_port, hb_port)
732 659 where kernel_process is a Popen object and the ports are integers.
733 660 """
734 661 return base_launch_kernel('from IPython.zmq.ipkernel import main; main()',
735 662 *args, **kwargs)
736 663
737 664
738 665 def main():
739 """Run a PyKernel as an application"""
666 """Run an IPKernel as an application"""
740 667 app = IPKernelApp()
741 668 app.initialize()
742 669 app.start()
743 670
744 671
745 672 if __name__ == '__main__':
746 673 main()
General Comments 0
You need to be logged in to leave comments. Login now