##// END OF EJS Templates
include parent Application in InteractiveShell.configurables...
MinRK -
Show More
@@ -1,396 +1,397 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 """
4 4 The :class:`~IPython.core.application.Application` object for the command
5 5 line :command:`ipython` program.
6 6
7 7 Authors
8 8 -------
9 9
10 10 * Brian Granger
11 11 * Fernando Perez
12 12 * Min Ragan-Kelley
13 13 """
14 14
15 15 #-----------------------------------------------------------------------------
16 16 # Copyright (C) 2008-2010 The IPython Development Team
17 17 #
18 18 # Distributed under the terms of the BSD License. The full license is in
19 19 # the file COPYING, distributed as part of this software.
20 20 #-----------------------------------------------------------------------------
21 21
22 22 #-----------------------------------------------------------------------------
23 23 # Imports
24 24 #-----------------------------------------------------------------------------
25 25
26 26 from __future__ import absolute_import
27 27
28 28 import logging
29 29 import os
30 30 import sys
31 31
32 32 from IPython.config.loader import (
33 33 Config, PyFileConfigLoader, ConfigFileNotFound
34 34 )
35 35 from IPython.config.application import boolean_flag, catch_config_error
36 36 from IPython.core import release
37 37 from IPython.core import usage
38 38 from IPython.core.completer import IPCompleter
39 39 from IPython.core.crashhandler import CrashHandler
40 40 from IPython.core.formatters import PlainTextFormatter
41 41 from IPython.core.application import (
42 42 ProfileDir, BaseIPythonApplication, base_flags, base_aliases
43 43 )
44 44 from IPython.core.shellapp import (
45 45 InteractiveShellApp, shell_flags, shell_aliases
46 46 )
47 47 from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
48 48 from IPython.lib import inputhook
49 49 from IPython.utils import warn
50 50 from IPython.utils.path import get_ipython_dir, check_for_old_config
51 51 from IPython.utils.traitlets import (
52 52 Bool, List, Dict, CaselessStrEnum
53 53 )
54 54
55 55 #-----------------------------------------------------------------------------
56 56 # Globals, utilities and helpers
57 57 #-----------------------------------------------------------------------------
58 58
59 59 #: The default config file name for this application.
60 60 default_config_file_name = u'ipython_config.py'
61 61
62 62 _examples = """
63 63 ipython --pylab # start in pylab mode
64 64 ipython --pylab=qt # start in pylab mode with the qt4 backend
65 65 ipython --log-level=DEBUG # set logging to DEBUG
66 66 ipython --profile=foo # start with profile foo
67 67
68 68 ipython qtconsole # start the qtconsole GUI application
69 69 ipython qtconsole -h # show the help string for the qtconsole subcmd
70 70
71 71 ipython profile create foo # create profile foo w/ default config files
72 72 ipython profile -h # show the help string for the profile subcmd
73 73 """
74 74
75 75 #-----------------------------------------------------------------------------
76 76 # Crash handler for this application
77 77 #-----------------------------------------------------------------------------
78 78
79 79 class IPAppCrashHandler(CrashHandler):
80 80 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
81 81
82 82 def __init__(self, app):
83 83 contact_name = release.authors['Fernando'][0]
84 84 contact_email = release.authors['Fernando'][1]
85 85 bug_tracker = 'http://github.com/ipython/ipython/issues'
86 86 super(IPAppCrashHandler,self).__init__(
87 87 app, contact_name, contact_email, bug_tracker
88 88 )
89 89
90 90 def make_report(self,traceback):
91 91 """Return a string containing a crash report."""
92 92
93 93 sec_sep = self.section_sep
94 94 # Start with parent report
95 95 report = [super(IPAppCrashHandler, self).make_report(traceback)]
96 96 # Add interactive-specific info we may have
97 97 rpt_add = report.append
98 98 try:
99 99 rpt_add(sec_sep+"History of session input:")
100 100 for line in self.app.shell.user_ns['_ih']:
101 101 rpt_add(line)
102 102 rpt_add('\n*** Last line of input (may not be in above history):\n')
103 103 rpt_add(self.app.shell._last_input_line+'\n')
104 104 except:
105 105 pass
106 106
107 107 return ''.join(report)
108 108
109 109 #-----------------------------------------------------------------------------
110 110 # Aliases and Flags
111 111 #-----------------------------------------------------------------------------
112 112 flags = dict(base_flags)
113 113 flags.update(shell_flags)
114 114 addflag = lambda *args: flags.update(boolean_flag(*args))
115 115 addflag('autoedit-syntax', 'TerminalInteractiveShell.autoedit_syntax',
116 116 'Turn on auto editing of files with syntax errors.',
117 117 'Turn off auto editing of files with syntax errors.'
118 118 )
119 119 addflag('banner', 'TerminalIPythonApp.display_banner',
120 120 "Display a banner upon starting IPython.",
121 121 "Don't display a banner upon starting IPython."
122 122 )
123 123 addflag('confirm-exit', 'TerminalInteractiveShell.confirm_exit',
124 124 """Set to confirm when you try to exit IPython with an EOF (Control-D
125 125 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
126 126 you can force a direct exit without any confirmation.""",
127 127 "Don't prompt the user when exiting."
128 128 )
129 129 addflag('term-title', 'TerminalInteractiveShell.term_title',
130 130 "Enable auto setting the terminal title.",
131 131 "Disable auto setting the terminal title."
132 132 )
133 133 classic_config = Config()
134 134 classic_config.InteractiveShell.cache_size = 0
135 135 classic_config.PlainTextFormatter.pprint = False
136 136 classic_config.InteractiveShell.prompt_in1 = '>>> '
137 137 classic_config.InteractiveShell.prompt_in2 = '... '
138 138 classic_config.InteractiveShell.prompt_out = ''
139 139 classic_config.InteractiveShell.separate_in = ''
140 140 classic_config.InteractiveShell.separate_out = ''
141 141 classic_config.InteractiveShell.separate_out2 = ''
142 142 classic_config.InteractiveShell.colors = 'NoColor'
143 143 classic_config.InteractiveShell.xmode = 'Plain'
144 144
145 145 flags['classic']=(
146 146 classic_config,
147 147 "Gives IPython a similar feel to the classic Python prompt."
148 148 )
149 149 # # log doesn't make so much sense this way anymore
150 150 # paa('--log','-l',
151 151 # action='store_true', dest='InteractiveShell.logstart',
152 152 # help="Start logging to the default log file (./ipython_log.py).")
153 153 #
154 154 # # quick is harder to implement
155 155 flags['quick']=(
156 156 {'TerminalIPythonApp' : {'quick' : True}},
157 157 "Enable quick startup with no config files."
158 158 )
159 159
160 160 flags['i'] = (
161 161 {'TerminalIPythonApp' : {'force_interact' : True}},
162 162 """If running code from the command line, become interactive afterwards.
163 163 Note: can also be given simply as '-i.'"""
164 164 )
165 165 flags['pylab'] = (
166 166 {'TerminalIPythonApp' : {'pylab' : 'auto'}},
167 167 """Pre-load matplotlib and numpy for interactive use with
168 168 the default matplotlib backend."""
169 169 )
170 170
171 171 aliases = dict(base_aliases)
172 172 aliases.update(shell_aliases)
173 173
174 174 # it's possible we don't want short aliases for *all* of these:
175 175 aliases.update(dict(
176 176 gui='TerminalIPythonApp.gui',
177 177 pylab='TerminalIPythonApp.pylab',
178 178 ))
179 179
180 180 #-----------------------------------------------------------------------------
181 181 # Main classes and functions
182 182 #-----------------------------------------------------------------------------
183 183
184 184 class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):
185 185 name = u'ipython'
186 186 description = usage.cl_usage
187 187 default_config_file_name = default_config_file_name
188 188 crash_handler_class = IPAppCrashHandler
189 189 examples = _examples
190 190
191 191 flags = Dict(flags)
192 192 aliases = Dict(aliases)
193 193 classes = List()
194 194 def _classes_default(self):
195 195 """This has to be in a method, for TerminalIPythonApp to be available."""
196 196 return [
197 197 InteractiveShellApp, # ShellApp comes before TerminalApp, because
198 198 self.__class__, # it will also affect subclasses (e.g. QtConsole)
199 199 TerminalInteractiveShell,
200 200 ProfileDir,
201 201 PlainTextFormatter,
202 202 IPCompleter,
203 203 ]
204 204
205 205 subcommands = Dict(dict(
206 206 qtconsole=('IPython.frontend.qt.console.qtconsoleapp.IPythonQtConsoleApp',
207 207 """Launch the IPython Qt Console."""
208 208 ),
209 209 notebook=('IPython.frontend.html.notebook.notebookapp.NotebookApp',
210 210 """Launch the IPython HTML Notebook Server"""
211 211 ),
212 212 profile = ("IPython.core.profileapp.ProfileApp",
213 213 "Create and manage IPython profiles."
214 214 ),
215 215 kernel = ("IPython.zmq.ipkernel.IPKernelApp",
216 216 "Start a kernel without an attached frontend."
217 217 ),
218 218 ))
219 219
220 220 # *do* autocreate requested profile, but don't create the config file.
221 221 auto_create=Bool(True)
222 222 # configurables
223 223 ignore_old_config=Bool(False, config=True,
224 224 help="Suppress warning messages about legacy config files"
225 225 )
226 226 quick = Bool(False, config=True,
227 227 help="""Start IPython quickly by skipping the loading of config files."""
228 228 )
229 229 def _quick_changed(self, name, old, new):
230 230 if new:
231 231 self.load_config_file = lambda *a, **kw: None
232 232 self.ignore_old_config=True
233 233
234 234 gui = CaselessStrEnum(('qt', 'wx', 'gtk', 'glut', 'pyglet'), config=True,
235 235 help="Enable GUI event loop integration ('qt', 'wx', 'gtk', 'glut', 'pyglet')."
236 236 )
237 237 pylab = CaselessStrEnum(['tk', 'qt', 'wx', 'gtk', 'osx', 'auto'],
238 238 config=True,
239 239 help="""Pre-load matplotlib and numpy for interactive use,
240 240 selecting a particular matplotlib backend and loop integration.
241 241 """
242 242 )
243 243 display_banner = Bool(True, config=True,
244 244 help="Whether to display a banner upon starting IPython."
245 245 )
246 246
247 247 # if there is code of files to run from the cmd line, don't interact
248 248 # unless the --i flag (App.force_interact) is true.
249 249 force_interact = Bool(False, config=True,
250 250 help="""If a command or file is given via the command-line,
251 251 e.g. 'ipython foo.py"""
252 252 )
253 253 def _force_interact_changed(self, name, old, new):
254 254 if new:
255 255 self.interact = True
256 256
257 257 def _file_to_run_changed(self, name, old, new):
258 258 if new and not self.force_interact:
259 259 self.interact = False
260 260 _code_to_run_changed = _file_to_run_changed
261 261
262 262 # internal, not-configurable
263 263 interact=Bool(True)
264 264
265 265
266 266 def parse_command_line(self, argv=None):
267 267 """override to allow old '-pylab' flag with deprecation warning"""
268 268
269 269 argv = sys.argv[1:] if argv is None else argv
270 270
271 271 if '-pylab' in argv:
272 272 # deprecated `-pylab` given,
273 273 # warn and transform into current syntax
274 274 argv = argv[:] # copy, don't clobber
275 275 idx = argv.index('-pylab')
276 276 warn.warn("`-pylab` flag has been deprecated.\n"
277 277 " Use `--pylab` instead, or `--pylab=foo` to specify a backend.")
278 278 sub = '--pylab'
279 279 if len(argv) > idx+1:
280 280 # check for gui arg, as in '-pylab qt'
281 281 gui = argv[idx+1]
282 282 if gui in ('wx', 'qt', 'qt4', 'gtk', 'auto'):
283 283 sub = '--pylab='+gui
284 284 argv.pop(idx+1)
285 285 argv[idx] = sub
286 286
287 287 return super(TerminalIPythonApp, self).parse_command_line(argv)
288 288
289 289 @catch_config_error
290 290 def initialize(self, argv=None):
291 291 """Do actions after construct, but before starting the app."""
292 292 super(TerminalIPythonApp, self).initialize(argv)
293 293 if self.subapp is not None:
294 294 # don't bother initializing further, starting subapp
295 295 return
296 296 if not self.ignore_old_config:
297 297 check_for_old_config(self.ipython_dir)
298 298 # print self.extra_args
299 299 if self.extra_args:
300 300 self.file_to_run = self.extra_args[0]
301 301 # create the shell
302 302 self.init_shell()
303 303 # and draw the banner
304 304 self.init_banner()
305 305 # Now a variety of things that happen after the banner is printed.
306 306 self.init_gui_pylab()
307 307 self.init_extensions()
308 308 self.init_code()
309 309
310 310 def init_shell(self):
311 311 """initialize the InteractiveShell instance"""
312 312 # I am a little hesitant to put these into InteractiveShell itself.
313 313 # But that might be the place for them
314 314 sys.path.insert(0, '')
315 315
316 316 # Create an InteractiveShell instance.
317 317 # shell.display_banner should always be False for the terminal
318 318 # based app, because we call shell.show_banner() by hand below
319 319 # so the banner shows *before* all extension loading stuff.
320 320 self.shell = TerminalInteractiveShell.instance(config=self.config,
321 321 display_banner=False, profile_dir=self.profile_dir,
322 322 ipython_dir=self.ipython_dir)
323 self.shell.configurables.append(self)
323 324
324 325 def init_banner(self):
325 326 """optionally display the banner"""
326 327 if self.display_banner and self.interact:
327 328 self.shell.show_banner()
328 329 # Make sure there is a space below the banner.
329 330 if self.log_level <= logging.INFO: print
330 331
331 332
332 333 def init_gui_pylab(self):
333 334 """Enable GUI event loop integration, taking pylab into account."""
334 335 gui = self.gui
335 336
336 337 # Using `pylab` will also require gui activation, though which toolkit
337 338 # to use may be chosen automatically based on mpl configuration.
338 339 if self.pylab:
339 340 activate = self.shell.enable_pylab
340 341 if self.pylab == 'auto':
341 342 gui = None
342 343 else:
343 344 gui = self.pylab
344 345 else:
345 346 # Enable only GUI integration, no pylab
346 347 activate = inputhook.enable_gui
347 348
348 349 if gui or self.pylab:
349 350 try:
350 351 self.log.info("Enabling GUI event loop integration, "
351 352 "toolkit=%s, pylab=%s" % (gui, self.pylab) )
352 353 if self.pylab:
353 354 activate(gui, import_all=self.pylab_import_all)
354 355 else:
355 356 activate(gui)
356 357 except:
357 358 self.log.warn("Error in enabling GUI event loop integration:")
358 359 self.shell.showtraceback()
359 360
360 361 def start(self):
361 362 if self.subapp is not None:
362 363 return self.subapp.start()
363 364 # perform any prexec steps:
364 365 if self.interact:
365 366 self.log.debug("Starting IPython's mainloop...")
366 367 self.shell.mainloop()
367 368 else:
368 369 self.log.debug("IPython not interactive...")
369 370
370 371
371 372 def load_default_config(ipython_dir=None):
372 373 """Load the default config file from the default ipython_dir.
373 374
374 375 This is useful for embedded shells.
375 376 """
376 377 if ipython_dir is None:
377 378 ipython_dir = get_ipython_dir()
378 379 profile_dir = os.path.join(ipython_dir, 'profile_default')
379 380 cl = PyFileConfigLoader(default_config_file_name, profile_dir)
380 381 try:
381 382 config = cl.load_config()
382 383 except ConfigFileNotFound:
383 384 # no config found
384 385 config = Config()
385 386 return config
386 387
387 388
388 389 def launch_new_instance():
389 390 """Create and run a full blown IPython instance"""
390 391 app = TerminalIPythonApp.instance()
391 392 app.initialize()
392 393 app.start()
393 394
394 395
395 396 if __name__ == '__main__':
396 397 launch_new_instance()
@@ -1,813 +1,814 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
26 26 # System library imports.
27 27 import zmq
28 28
29 29 # Local imports.
30 30 from IPython.config.configurable import Configurable
31 31 from IPython.config.application import boolean_flag, catch_config_error
32 32 from IPython.core.application import ProfileDir
33 33 from IPython.core.error import StdinNotImplementedError
34 34 from IPython.core.shellapp import (
35 35 InteractiveShellApp, shell_flags, shell_aliases
36 36 )
37 37 from IPython.utils import io
38 38 from IPython.utils import py3compat
39 39 from IPython.utils.jsonutil import json_clean
40 40 from IPython.lib import pylabtools
41 41 from IPython.utils.traitlets import (
42 42 Any, List, Instance, Float, Dict, Bool, Int, Unicode, CaselessStrEnum
43 43 )
44 44
45 45 from entry_point import base_launch_kernel
46 46 from kernelapp import KernelApp, kernel_flags, kernel_aliases
47 47 from iostream import OutStream
48 48 from session import Session, Message
49 49 from zmqshell import ZMQInteractiveShell
50 50
51 51
52 52 #-----------------------------------------------------------------------------
53 53 # Main kernel class
54 54 #-----------------------------------------------------------------------------
55 55
56 56 class Kernel(Configurable):
57 57
58 58 #---------------------------------------------------------------------------
59 59 # Kernel interface
60 60 #---------------------------------------------------------------------------
61 61
62 62 # attribute to override with a GUI
63 63 eventloop = Any(None)
64 64
65 65 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
66 66 session = Instance(Session)
67 67 profile_dir = Instance('IPython.core.profiledir.ProfileDir')
68 68 shell_socket = Instance('zmq.Socket')
69 69 iopub_socket = Instance('zmq.Socket')
70 70 stdin_socket = Instance('zmq.Socket')
71 71 log = Instance(logging.Logger)
72 72
73 73 # Private interface
74 74
75 75 # Time to sleep after flushing the stdout/err buffers in each execute
76 76 # cycle. While this introduces a hard limit on the minimal latency of the
77 77 # execute cycle, it helps prevent output synchronization problems for
78 78 # clients.
79 79 # Units are in seconds. The minimum zmq latency on local host is probably
80 80 # ~150 microseconds, set this to 500us for now. We may need to increase it
81 81 # a little if it's not enough after more interactive testing.
82 82 _execute_sleep = Float(0.0005, config=True)
83 83
84 84 # Frequency of the kernel's event loop.
85 85 # Units are in seconds, kernel subclasses for GUI toolkits may need to
86 86 # adapt to milliseconds.
87 87 _poll_interval = Float(0.05, config=True)
88 88
89 89 # If the shutdown was requested over the network, we leave here the
90 90 # necessary reply message so it can be sent by our registered atexit
91 91 # handler. This ensures that the reply is only sent to clients truly at
92 92 # the end of our shutdown process (which happens after the underlying
93 93 # IPython shell's own shutdown).
94 94 _shutdown_message = None
95 95
96 96 # This is a dict of port number that the kernel is listening on. It is set
97 97 # by record_ports and used by connect_request.
98 98 _recorded_ports = Dict()
99 99
100 100
101 101
102 102 def __init__(self, **kwargs):
103 103 super(Kernel, self).__init__(**kwargs)
104 104
105 105 # Before we even start up the shell, register *first* our exit handlers
106 106 # so they come before the shell's
107 107 atexit.register(self._at_shutdown)
108 108
109 109 # Initialize the InteractiveShell subclass
110 110 self.shell = ZMQInteractiveShell.instance(config=self.config,
111 111 profile_dir = self.profile_dir,
112 112 )
113 113 self.shell.displayhook.session = self.session
114 114 self.shell.displayhook.pub_socket = self.iopub_socket
115 115 self.shell.display_pub.session = self.session
116 116 self.shell.display_pub.pub_socket = self.iopub_socket
117 117
118 118 # TMP - hack while developing
119 119 self.shell._reply_content = None
120 120
121 121 # Build dict of handlers for message types
122 122 msg_types = [ 'execute_request', 'complete_request',
123 123 'object_info_request', 'history_request',
124 124 'connect_request', 'shutdown_request']
125 125 self.handlers = {}
126 126 for msg_type in msg_types:
127 127 self.handlers[msg_type] = getattr(self, msg_type)
128 128
129 129 def do_one_iteration(self):
130 130 """Do one iteration of the kernel's evaluation loop.
131 131 """
132 132 try:
133 133 ident,msg = self.session.recv(self.shell_socket, zmq.NOBLOCK)
134 134 except Exception:
135 135 self.log.warn("Invalid Message:", exc_info=True)
136 136 return
137 137 if msg is None:
138 138 return
139 139
140 140 msg_type = msg['header']['msg_type']
141 141
142 142 # This assert will raise in versions of zeromq 2.0.7 and lesser.
143 143 # We now require 2.0.8 or above, so we can uncomment for safety.
144 144 # print(ident,msg, file=sys.__stdout__)
145 145 assert ident is not None, "Missing message part."
146 146
147 147 # Print some info about this message and leave a '--->' marker, so it's
148 148 # easier to trace visually the message chain when debugging. Each
149 149 # handler prints its message at the end.
150 150 self.log.debug('\n*** MESSAGE TYPE:'+str(msg_type)+'***')
151 151 self.log.debug(' Content: '+str(msg['content'])+'\n --->\n ')
152 152
153 153 # Find and call actual handler for message
154 154 handler = self.handlers.get(msg_type, None)
155 155 if handler is None:
156 156 self.log.error("UNKNOWN MESSAGE TYPE:" +str(msg))
157 157 else:
158 158 handler(ident, msg)
159 159
160 160 # Check whether we should exit, in case the incoming message set the
161 161 # exit flag on
162 162 if self.shell.exit_now:
163 163 self.log.debug('\nExiting IPython kernel...')
164 164 # We do a normal, clean exit, which allows any actions registered
165 165 # via atexit (such as history saving) to take place.
166 166 sys.exit(0)
167 167
168 168
169 169 def start(self):
170 170 """ Start the kernel main loop.
171 171 """
172 172 poller = zmq.Poller()
173 173 poller.register(self.shell_socket, zmq.POLLIN)
174 174 # loop while self.eventloop has not been overridden
175 175 while self.eventloop is None:
176 176 try:
177 177 # scale by extra factor of 10, because there is no
178 178 # reason for this to be anything less than ~ 0.1s
179 179 # since it is a real poller and will respond
180 180 # to events immediately
181 181
182 182 # double nested try/except, to properly catch KeyboardInterrupt
183 183 # due to pyzmq Issue #130
184 184 try:
185 185 poller.poll(10*1000*self._poll_interval)
186 186 self.do_one_iteration()
187 187 except:
188 188 raise
189 189 except KeyboardInterrupt:
190 190 # Ctrl-C shouldn't crash the kernel
191 191 io.raw_print("KeyboardInterrupt caught in kernel")
192 192 if self.eventloop is not None:
193 193 try:
194 194 self.eventloop(self)
195 195 except KeyboardInterrupt:
196 196 # Ctrl-C shouldn't crash the kernel
197 197 io.raw_print("KeyboardInterrupt caught in kernel")
198 198
199 199
200 200 def record_ports(self, ports):
201 201 """Record the ports that this kernel is using.
202 202
203 203 The creator of the Kernel instance must call this methods if they
204 204 want the :meth:`connect_request` method to return the port numbers.
205 205 """
206 206 self._recorded_ports = ports
207 207
208 208 #---------------------------------------------------------------------------
209 209 # Kernel request handlers
210 210 #---------------------------------------------------------------------------
211 211
212 212 def _publish_pyin(self, code, parent):
213 213 """Publish the code request on the pyin stream."""
214 214
215 215 pyin_msg = self.session.send(self.iopub_socket, u'pyin',{u'code':code}, parent=parent)
216 216
217 217 def execute_request(self, ident, parent):
218 218
219 219 status_msg = self.session.send(self.iopub_socket,
220 220 u'status',
221 221 {u'execution_state':u'busy'},
222 222 parent=parent
223 223 )
224 224
225 225 try:
226 226 content = parent[u'content']
227 227 code = content[u'code']
228 228 silent = content[u'silent']
229 229 except:
230 230 self.log.error("Got bad msg: ")
231 231 self.log.error(str(Message(parent)))
232 232 return
233 233
234 234 shell = self.shell # we'll need this a lot here
235 235
236 236 # Replace raw_input. Note that is not sufficient to replace
237 237 # raw_input in the user namespace.
238 238 if content.get('allow_stdin', False):
239 239 raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
240 240 else:
241 241 raw_input = lambda prompt='' : self._no_raw_input()
242 242
243 243 if py3compat.PY3:
244 244 __builtin__.input = raw_input
245 245 else:
246 246 __builtin__.raw_input = raw_input
247 247
248 248 # Set the parent message of the display hook and out streams.
249 249 shell.displayhook.set_parent(parent)
250 250 shell.display_pub.set_parent(parent)
251 251 sys.stdout.set_parent(parent)
252 252 sys.stderr.set_parent(parent)
253 253
254 254 # Re-broadcast our input for the benefit of listening clients, and
255 255 # start computing output
256 256 if not silent:
257 257 self._publish_pyin(code, parent)
258 258
259 259 reply_content = {}
260 260 try:
261 261 if silent:
262 262 # run_code uses 'exec' mode, so no displayhook will fire, and it
263 263 # doesn't call logging or history manipulations. Print
264 264 # statements in that code will obviously still execute.
265 265 shell.run_code(code)
266 266 else:
267 267 # FIXME: the shell calls the exception handler itself.
268 268 shell.run_cell(code, store_history=True)
269 269 except:
270 270 status = u'error'
271 271 # FIXME: this code right now isn't being used yet by default,
272 272 # because the run_cell() call above directly fires off exception
273 273 # reporting. This code, therefore, is only active in the scenario
274 274 # where runlines itself has an unhandled exception. We need to
275 275 # uniformize this, for all exception construction to come from a
276 276 # single location in the codbase.
277 277 etype, evalue, tb = sys.exc_info()
278 278 tb_list = traceback.format_exception(etype, evalue, tb)
279 279 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
280 280 else:
281 281 status = u'ok'
282 282
283 283 reply_content[u'status'] = status
284 284
285 285 # Return the execution counter so clients can display prompts
286 286 reply_content['execution_count'] = shell.execution_count -1
287 287
288 288 # FIXME - fish exception info out of shell, possibly left there by
289 289 # runlines. We'll need to clean up this logic later.
290 290 if shell._reply_content is not None:
291 291 reply_content.update(shell._reply_content)
292 292 # reset after use
293 293 shell._reply_content = None
294 294
295 295 # At this point, we can tell whether the main code execution succeeded
296 296 # or not. If it did, we proceed to evaluate user_variables/expressions
297 297 if reply_content['status'] == 'ok':
298 298 reply_content[u'user_variables'] = \
299 299 shell.user_variables(content[u'user_variables'])
300 300 reply_content[u'user_expressions'] = \
301 301 shell.user_expressions(content[u'user_expressions'])
302 302 else:
303 303 # If there was an error, don't even try to compute variables or
304 304 # expressions
305 305 reply_content[u'user_variables'] = {}
306 306 reply_content[u'user_expressions'] = {}
307 307
308 308 # Payloads should be retrieved regardless of outcome, so we can both
309 309 # recover partial output (that could have been generated early in a
310 310 # block, before an error) and clear the payload system always.
311 311 reply_content[u'payload'] = shell.payload_manager.read_payload()
312 312 # Be agressive about clearing the payload because we don't want
313 313 # it to sit in memory until the next execute_request comes in.
314 314 shell.payload_manager.clear_payload()
315 315
316 316 # Flush output before sending the reply.
317 317 sys.stdout.flush()
318 318 sys.stderr.flush()
319 319 # FIXME: on rare occasions, the flush doesn't seem to make it to the
320 320 # clients... This seems to mitigate the problem, but we definitely need
321 321 # to better understand what's going on.
322 322 if self._execute_sleep:
323 323 time.sleep(self._execute_sleep)
324 324
325 325 # Send the reply.
326 326 reply_content = json_clean(reply_content)
327 327 reply_msg = self.session.send(self.shell_socket, u'execute_reply',
328 328 reply_content, parent, ident=ident)
329 329 self.log.debug(str(reply_msg))
330 330
331 331 if reply_msg['content']['status'] == u'error':
332 332 self._abort_queue()
333 333
334 334 status_msg = self.session.send(self.iopub_socket,
335 335 u'status',
336 336 {u'execution_state':u'idle'},
337 337 parent=parent
338 338 )
339 339
340 340 def complete_request(self, ident, parent):
341 341 txt, matches = self._complete(parent)
342 342 matches = {'matches' : matches,
343 343 'matched_text' : txt,
344 344 'status' : 'ok'}
345 345 matches = json_clean(matches)
346 346 completion_msg = self.session.send(self.shell_socket, 'complete_reply',
347 347 matches, parent, ident)
348 348 self.log.debug(str(completion_msg))
349 349
350 350 def object_info_request(self, ident, parent):
351 351 object_info = self.shell.object_inspect(parent['content']['oname'])
352 352 # Before we send this object over, we scrub it for JSON usage
353 353 oinfo = json_clean(object_info)
354 354 msg = self.session.send(self.shell_socket, 'object_info_reply',
355 355 oinfo, parent, ident)
356 356 self.log.debug(msg)
357 357
358 358 def history_request(self, ident, parent):
359 359 # We need to pull these out, as passing **kwargs doesn't work with
360 360 # unicode keys before Python 2.6.5.
361 361 hist_access_type = parent['content']['hist_access_type']
362 362 raw = parent['content']['raw']
363 363 output = parent['content']['output']
364 364 if hist_access_type == 'tail':
365 365 n = parent['content']['n']
366 366 hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
367 367 include_latest=True)
368 368
369 369 elif hist_access_type == 'range':
370 370 session = parent['content']['session']
371 371 start = parent['content']['start']
372 372 stop = parent['content']['stop']
373 373 hist = self.shell.history_manager.get_range(session, start, stop,
374 374 raw=raw, output=output)
375 375
376 376 elif hist_access_type == 'search':
377 377 pattern = parent['content']['pattern']
378 378 hist = self.shell.history_manager.search(pattern, raw=raw, output=output)
379 379
380 380 else:
381 381 hist = []
382 382 content = {'history' : list(hist)}
383 383 content = json_clean(content)
384 384 msg = self.session.send(self.shell_socket, 'history_reply',
385 385 content, parent, ident)
386 386 self.log.debug(str(msg))
387 387
388 388 def connect_request(self, ident, parent):
389 389 if self._recorded_ports is not None:
390 390 content = self._recorded_ports.copy()
391 391 else:
392 392 content = {}
393 393 msg = self.session.send(self.shell_socket, 'connect_reply',
394 394 content, parent, ident)
395 395 self.log.debug(msg)
396 396
397 397 def shutdown_request(self, ident, parent):
398 398 self.shell.exit_now = True
399 399 self._shutdown_message = self.session.msg(u'shutdown_reply', parent['content'], parent)
400 400 sys.exit(0)
401 401
402 402 #---------------------------------------------------------------------------
403 403 # Protected interface
404 404 #---------------------------------------------------------------------------
405 405
406 406 def _abort_queue(self):
407 407 while True:
408 408 try:
409 409 ident,msg = self.session.recv(self.shell_socket, zmq.NOBLOCK)
410 410 except Exception:
411 411 self.log.warn("Invalid Message:", exc_info=True)
412 412 continue
413 413 if msg is None:
414 414 break
415 415 else:
416 416 assert ident is not None, \
417 417 "Unexpected missing message part."
418 418
419 419 self.log.debug("Aborting:\n"+str(Message(msg)))
420 420 msg_type = msg['header']['msg_type']
421 421 reply_type = msg_type.split('_')[0] + '_reply'
422 422 reply_msg = self.session.send(self.shell_socket, reply_type,
423 423 {'status' : 'aborted'}, msg, ident=ident)
424 424 self.log.debug(reply_msg)
425 425 # We need to wait a bit for requests to come in. This can probably
426 426 # be set shorter for true asynchronous clients.
427 427 time.sleep(0.1)
428 428
429 429 def _no_raw_input(self):
430 430 """Raise StdinNotImplentedError if active frontend doesn't support stdin."""
431 431 raise StdinNotImplementedError("raw_input was called, but this frontend does not support stdin.")
432 432
433 433 def _raw_input(self, prompt, ident, parent):
434 434 # Flush output before making the request.
435 435 sys.stderr.flush()
436 436 sys.stdout.flush()
437 437
438 438 # Send the input request.
439 439 content = json_clean(dict(prompt=prompt))
440 440 msg = self.session.send(self.stdin_socket, u'input_request', content, parent, ident=ident)
441 441
442 442 # Await a response.
443 443 while True:
444 444 try:
445 445 ident, reply = self.session.recv(self.stdin_socket, 0)
446 446 except Exception:
447 447 self.log.warn("Invalid Message:", exc_info=True)
448 448 else:
449 449 break
450 450 try:
451 451 value = reply['content']['value']
452 452 except:
453 453 self.log.error("Got bad raw_input reply: ")
454 454 self.log.error(str(Message(parent)))
455 455 value = ''
456 456 return value
457 457
458 458 def _complete(self, msg):
459 459 c = msg['content']
460 460 try:
461 461 cpos = int(c['cursor_pos'])
462 462 except:
463 463 # If we don't get something that we can convert to an integer, at
464 464 # least attempt the completion guessing the cursor is at the end of
465 465 # the text, if there's any, and otherwise of the line
466 466 cpos = len(c['text'])
467 467 if cpos==0:
468 468 cpos = len(c['line'])
469 469 return self.shell.complete(c['text'], c['line'], cpos)
470 470
471 471 def _object_info(self, context):
472 472 symbol, leftover = self._symbol_from_context(context)
473 473 if symbol is not None and not leftover:
474 474 doc = getattr(symbol, '__doc__', '')
475 475 else:
476 476 doc = ''
477 477 object_info = dict(docstring = doc)
478 478 return object_info
479 479
480 480 def _symbol_from_context(self, context):
481 481 if not context:
482 482 return None, context
483 483
484 484 base_symbol_string = context[0]
485 485 symbol = self.shell.user_ns.get(base_symbol_string, None)
486 486 if symbol is None:
487 487 symbol = __builtin__.__dict__.get(base_symbol_string, None)
488 488 if symbol is None:
489 489 return None, context
490 490
491 491 context = context[1:]
492 492 for i, name in enumerate(context):
493 493 new_symbol = getattr(symbol, name, None)
494 494 if new_symbol is None:
495 495 return symbol, context[i:]
496 496 else:
497 497 symbol = new_symbol
498 498
499 499 return symbol, []
500 500
501 501 def _at_shutdown(self):
502 502 """Actions taken at shutdown by the kernel, called by python's atexit.
503 503 """
504 504 # io.rprint("Kernel at_shutdown") # dbg
505 505 if self._shutdown_message is not None:
506 506 self.session.send(self.shell_socket, self._shutdown_message)
507 507 self.session.send(self.iopub_socket, self._shutdown_message)
508 508 self.log.debug(str(self._shutdown_message))
509 509 # A very short sleep to give zmq time to flush its message buffers
510 510 # before Python truly shuts down.
511 511 time.sleep(0.01)
512 512
513 513
514 514 #------------------------------------------------------------------------------
515 515 # Eventloops for integrating the Kernel into different GUIs
516 516 #------------------------------------------------------------------------------
517 517
518 518
519 519 def loop_qt4(kernel):
520 520 """Start a kernel with PyQt4 event loop integration."""
521 521
522 522 from IPython.external.qt_for_kernel import QtCore
523 523 from IPython.lib.guisupport import get_app_qt4, start_event_loop_qt4
524 524
525 525 kernel.app = get_app_qt4([" "])
526 526 kernel.app.setQuitOnLastWindowClosed(False)
527 527 kernel.timer = QtCore.QTimer()
528 528 kernel.timer.timeout.connect(kernel.do_one_iteration)
529 529 # Units for the timer are in milliseconds
530 530 kernel.timer.start(1000*kernel._poll_interval)
531 531 start_event_loop_qt4(kernel.app)
532 532
533 533
534 534 def loop_wx(kernel):
535 535 """Start a kernel with wx event loop support."""
536 536
537 537 import wx
538 538 from IPython.lib.guisupport import start_event_loop_wx
539 539
540 540 doi = kernel.do_one_iteration
541 541 # Wx uses milliseconds
542 542 poll_interval = int(1000*kernel._poll_interval)
543 543
544 544 # We have to put the wx.Timer in a wx.Frame for it to fire properly.
545 545 # We make the Frame hidden when we create it in the main app below.
546 546 class TimerFrame(wx.Frame):
547 547 def __init__(self, func):
548 548 wx.Frame.__init__(self, None, -1)
549 549 self.timer = wx.Timer(self)
550 550 # Units for the timer are in milliseconds
551 551 self.timer.Start(poll_interval)
552 552 self.Bind(wx.EVT_TIMER, self.on_timer)
553 553 self.func = func
554 554
555 555 def on_timer(self, event):
556 556 self.func()
557 557
558 558 # We need a custom wx.App to create our Frame subclass that has the
559 559 # wx.Timer to drive the ZMQ event loop.
560 560 class IPWxApp(wx.App):
561 561 def OnInit(self):
562 562 self.frame = TimerFrame(doi)
563 563 self.frame.Show(False)
564 564 return True
565 565
566 566 # The redirect=False here makes sure that wx doesn't replace
567 567 # sys.stdout/stderr with its own classes.
568 568 kernel.app = IPWxApp(redirect=False)
569 569 start_event_loop_wx(kernel.app)
570 570
571 571
572 572 def loop_tk(kernel):
573 573 """Start a kernel with the Tk event loop."""
574 574
575 575 import Tkinter
576 576 doi = kernel.do_one_iteration
577 577 # Tk uses milliseconds
578 578 poll_interval = int(1000*kernel._poll_interval)
579 579 # For Tkinter, we create a Tk object and call its withdraw method.
580 580 class Timer(object):
581 581 def __init__(self, func):
582 582 self.app = Tkinter.Tk()
583 583 self.app.withdraw()
584 584 self.func = func
585 585
586 586 def on_timer(self):
587 587 self.func()
588 588 self.app.after(poll_interval, self.on_timer)
589 589
590 590 def start(self):
591 591 self.on_timer() # Call it once to get things going.
592 592 self.app.mainloop()
593 593
594 594 kernel.timer = Timer(doi)
595 595 kernel.timer.start()
596 596
597 597
598 598 def loop_gtk(kernel):
599 599 """Start the kernel, coordinating with the GTK event loop"""
600 600 from .gui.gtkembed import GTKEmbed
601 601
602 602 gtk_kernel = GTKEmbed(kernel)
603 603 gtk_kernel.start()
604 604
605 605
606 606 def loop_cocoa(kernel):
607 607 """Start the kernel, coordinating with the Cocoa CFRunLoop event loop
608 608 via the matplotlib MacOSX backend.
609 609 """
610 610 import matplotlib
611 611 if matplotlib.__version__ < '1.1.0':
612 612 kernel.log.warn(
613 613 "MacOSX backend in matplotlib %s doesn't have a Timer, "
614 614 "falling back on Tk for CFRunLoop integration. Note that "
615 615 "even this won't work if Tk is linked against X11 instead of "
616 616 "Cocoa (e.g. EPD). To use the MacOSX backend in the kernel, "
617 617 "you must use matplotlib >= 1.1.0, or a native libtk."
618 618 )
619 619 return loop_tk(kernel)
620 620
621 621 from matplotlib.backends.backend_macosx import TimerMac, show
622 622
623 623 # scale interval for sec->ms
624 624 poll_interval = int(1000*kernel._poll_interval)
625 625
626 626 real_excepthook = sys.excepthook
627 627 def handle_int(etype, value, tb):
628 628 """don't let KeyboardInterrupts look like crashes"""
629 629 if etype is KeyboardInterrupt:
630 630 io.raw_print("KeyboardInterrupt caught in CFRunLoop")
631 631 else:
632 632 real_excepthook(etype, value, tb)
633 633
634 634 # add doi() as a Timer to the CFRunLoop
635 635 def doi():
636 636 # restore excepthook during IPython code
637 637 sys.excepthook = real_excepthook
638 638 kernel.do_one_iteration()
639 639 # and back:
640 640 sys.excepthook = handle_int
641 641
642 642 t = TimerMac(poll_interval)
643 643 t.add_callback(doi)
644 644 t.start()
645 645
646 646 # but still need a Poller for when there are no active windows,
647 647 # during which time mainloop() returns immediately
648 648 poller = zmq.Poller()
649 649 poller.register(kernel.shell_socket, zmq.POLLIN)
650 650
651 651 while True:
652 652 try:
653 653 # double nested try/except, to properly catch KeyboardInterrupt
654 654 # due to pyzmq Issue #130
655 655 try:
656 656 # don't let interrupts during mainloop invoke crash_handler:
657 657 sys.excepthook = handle_int
658 658 show.mainloop()
659 659 sys.excepthook = real_excepthook
660 660 # use poller if mainloop returned (no windows)
661 661 # scale by extra factor of 10, since it's a real poll
662 662 poller.poll(10*poll_interval)
663 663 kernel.do_one_iteration()
664 664 except:
665 665 raise
666 666 except KeyboardInterrupt:
667 667 # Ctrl-C shouldn't crash the kernel
668 668 io.raw_print("KeyboardInterrupt caught in kernel")
669 669 finally:
670 670 # ensure excepthook is restored
671 671 sys.excepthook = real_excepthook
672 672
673 673 # mapping of keys to loop functions
674 674 loop_map = {
675 675 'qt' : loop_qt4,
676 676 'qt4': loop_qt4,
677 677 'inline': None,
678 678 'osx': loop_cocoa,
679 679 'wx' : loop_wx,
680 680 'tk' : loop_tk,
681 681 'gtk': loop_gtk,
682 682 }
683 683
684 684 def enable_gui(gui, kernel=None):
685 685 """Enable integration with a give GUI"""
686 686 if kernel is None:
687 687 kernel = IPKernelApp.instance().kernel
688 688 if gui not in loop_map:
689 689 raise ValueError("GUI %r not supported" % gui)
690 690 loop = loop_map[gui]
691 691 if kernel.eventloop is not None and kernel.eventloop is not loop:
692 692 raise RuntimeError("Cannot activate multiple GUI eventloops")
693 693 kernel.eventloop = loop
694 694
695 695
696 696 #-----------------------------------------------------------------------------
697 697 # Aliases and Flags for the IPKernelApp
698 698 #-----------------------------------------------------------------------------
699 699
700 700 flags = dict(kernel_flags)
701 701 flags.update(shell_flags)
702 702
703 703 addflag = lambda *args: flags.update(boolean_flag(*args))
704 704
705 705 flags['pylab'] = (
706 706 {'IPKernelApp' : {'pylab' : 'auto'}},
707 707 """Pre-load matplotlib and numpy for interactive use with
708 708 the default matplotlib backend."""
709 709 )
710 710
711 711 aliases = dict(kernel_aliases)
712 712 aliases.update(shell_aliases)
713 713
714 714 # it's possible we don't want short aliases for *all* of these:
715 715 aliases.update(dict(
716 716 pylab='IPKernelApp.pylab',
717 717 ))
718 718
719 719 #-----------------------------------------------------------------------------
720 720 # The IPKernelApp class
721 721 #-----------------------------------------------------------------------------
722 722
723 723 class IPKernelApp(KernelApp, InteractiveShellApp):
724 724 name = 'ipkernel'
725 725
726 726 aliases = Dict(aliases)
727 727 flags = Dict(flags)
728 728 classes = [Kernel, ZMQInteractiveShell, ProfileDir, Session]
729 729 # configurables
730 730 pylab = CaselessStrEnum(['tk', 'qt', 'wx', 'gtk', 'osx', 'inline', 'auto'],
731 731 config=True,
732 732 help="""Pre-load matplotlib and numpy for interactive use,
733 733 selecting a particular matplotlib backend and loop integration.
734 734 """
735 735 )
736 736
737 737 @catch_config_error
738 738 def initialize(self, argv=None):
739 739 super(IPKernelApp, self).initialize(argv)
740 740 self.init_shell()
741 741 self.init_extensions()
742 742 self.init_code()
743 743
744 744 def init_kernel(self):
745 745
746 746 kernel = Kernel(config=self.config, session=self.session,
747 747 shell_socket=self.shell_socket,
748 748 iopub_socket=self.iopub_socket,
749 749 stdin_socket=self.stdin_socket,
750 750 log=self.log,
751 751 profile_dir=self.profile_dir,
752 752 )
753 753 self.kernel = kernel
754 754 kernel.record_ports(self.ports)
755 755 shell = kernel.shell
756 756 if self.pylab:
757 757 try:
758 758 gui, backend = pylabtools.find_gui_and_backend(self.pylab)
759 759 shell.enable_pylab(gui, import_all=self.pylab_import_all)
760 760 except Exception:
761 761 self.log.error("Pylab initialization failed", exc_info=True)
762 762 # print exception straight to stdout, because normally
763 763 # _showtraceback associates the reply with an execution,
764 764 # which means frontends will never draw it, as this exception
765 765 # is not associated with any execute request.
766 766
767 767 # replace pyerr-sending traceback with stdout
768 768 _showtraceback = shell._showtraceback
769 769 def print_tb(etype, evalue, stb):
770 770 print ("Error initializing pylab, pylab mode will not be active", file=io.stderr)
771 771 print (shell.InteractiveTB.stb2text(stb), file=io.stdout)
772 772 shell._showtraceback = print_tb
773 773
774 774 # send the traceback over stdout
775 775 shell.showtraceback(tb_offset=0)
776 776
777 777 # restore proper _showtraceback method
778 778 shell._showtraceback = _showtraceback
779 779
780 780
781 781 def init_shell(self):
782 782 self.shell = self.kernel.shell
783 self.shell.configurables.append(self)
783 784
784 785
785 786 #-----------------------------------------------------------------------------
786 787 # Kernel main and launch functions
787 788 #-----------------------------------------------------------------------------
788 789
789 790 def launch_kernel(*args, **kwargs):
790 791 """Launches a localhost IPython kernel, binding to the specified ports.
791 792
792 793 This function simply calls entry_point.base_launch_kernel with the right first
793 794 command to start an ipkernel. See base_launch_kernel for arguments.
794 795
795 796 Returns
796 797 -------
797 798 A tuple of form:
798 799 (kernel_process, shell_port, iopub_port, stdin_port, hb_port)
799 800 where kernel_process is a Popen object and the ports are integers.
800 801 """
801 802 return base_launch_kernel('from IPython.zmq.ipkernel import main; main()',
802 803 *args, **kwargs)
803 804
804 805
805 806 def main():
806 807 """Run an IPKernel as an application"""
807 808 app = IPKernelApp.instance()
808 809 app.initialize()
809 810 app.start()
810 811
811 812
812 813 if __name__ == '__main__':
813 814 main()
General Comments 0
You need to be logged in to leave comments. Login now