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