##// END OF EJS Templates
Move gui and pylab options to InteractiveShellApp.
Bradley M. Froehle -
Show More
@@ -1,319 +1,360 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 A mixin for :class:`~IPython.core.application.Application` classes that
3 A mixin for :class:`~IPython.core.application.Application` classes that
4 launch InteractiveShell instances, load extensions, etc.
4 launch InteractiveShell instances, load extensions, etc.
5
5
6 Authors
6 Authors
7 -------
7 -------
8
8
9 * Min Ragan-Kelley
9 * Min Ragan-Kelley
10 """
10 """
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Copyright (C) 2008-2011 The IPython Development Team
13 # Copyright (C) 2008-2011 The IPython Development Team
14 #
14 #
15 # Distributed under the terms of the BSD License. The full license is in
15 # Distributed under the terms of the BSD License. The full license is in
16 # the file COPYING, distributed as part of this software.
16 # the file COPYING, distributed as part of this software.
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Imports
20 # Imports
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22
22
23 from __future__ import absolute_import
23 from __future__ import absolute_import
24
24
25 import glob
25 import glob
26 import os
26 import os
27 import sys
27 import sys
28
28
29 from IPython.config.application import boolean_flag
29 from IPython.config.application import boolean_flag
30 from IPython.config.configurable import Configurable
30 from IPython.config.configurable import Configurable
31 from IPython.config.loader import Config
31 from IPython.config.loader import Config
32 from IPython.core import pylabtools
32 from IPython.utils import py3compat
33 from IPython.utils import py3compat
33 from IPython.utils.path import filefind
34 from IPython.utils.path import filefind
34 from IPython.utils.traitlets import Unicode, Instance, List, Bool
35 from IPython.utils.traitlets import (
36 Unicode, Instance, List, Bool, CaselessStrEnum
37 )
35
38
36 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
37 # Aliases and Flags
40 # Aliases and Flags
38 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
39
42
40 shell_flags = {}
43 shell_flags = {}
41
44
42 addflag = lambda *args: shell_flags.update(boolean_flag(*args))
45 addflag = lambda *args: shell_flags.update(boolean_flag(*args))
43 addflag('autoindent', 'InteractiveShell.autoindent',
46 addflag('autoindent', 'InteractiveShell.autoindent',
44 'Turn on autoindenting.', 'Turn off autoindenting.'
47 'Turn on autoindenting.', 'Turn off autoindenting.'
45 )
48 )
46 addflag('automagic', 'InteractiveShell.automagic',
49 addflag('automagic', 'InteractiveShell.automagic',
47 """Turn on the auto calling of magic commands. Type %%magic at the
50 """Turn on the auto calling of magic commands. Type %%magic at the
48 IPython prompt for more information.""",
51 IPython prompt for more information.""",
49 'Turn off the auto calling of magic commands.'
52 'Turn off the auto calling of magic commands.'
50 )
53 )
51 addflag('pdb', 'InteractiveShell.pdb',
54 addflag('pdb', 'InteractiveShell.pdb',
52 "Enable auto calling the pdb debugger after every exception.",
55 "Enable auto calling the pdb debugger after every exception.",
53 "Disable auto calling the pdb debugger after every exception."
56 "Disable auto calling the pdb debugger after every exception."
54 )
57 )
55 # pydb flag doesn't do any config, as core.debugger switches on import,
58 # pydb flag doesn't do any config, as core.debugger switches on import,
56 # which is before parsing. This just allows the flag to be passed.
59 # which is before parsing. This just allows the flag to be passed.
57 shell_flags.update(dict(
60 shell_flags.update(dict(
58 pydb = ({},
61 pydb = ({},
59 """"Use the third party 'pydb' package as debugger, instead of pdb.
62 """"Use the third party 'pydb' package as debugger, instead of pdb.
60 Requires that pydb is installed."""
63 Requires that pydb is installed."""
61 )
64 )
62 ))
65 ))
63 addflag('pprint', 'PlainTextFormatter.pprint',
66 addflag('pprint', 'PlainTextFormatter.pprint',
64 "Enable auto pretty printing of results.",
67 "Enable auto pretty printing of results.",
65 "Disable auto auto pretty printing of results."
68 "Disable auto auto pretty printing of results."
66 )
69 )
67 addflag('color-info', 'InteractiveShell.color_info',
70 addflag('color-info', 'InteractiveShell.color_info',
68 """IPython can display information about objects via a set of func-
71 """IPython can display information about objects via a set of func-
69 tions, and optionally can use colors for this, syntax highlighting
72 tions, and optionally can use colors for this, syntax highlighting
70 source code and various other elements. However, because this
73 source code and various other elements. However, because this
71 information is passed through a pager (like 'less') and many pagers get
74 information is passed through a pager (like 'less') and many pagers get
72 confused with color codes, this option is off by default. You can test
75 confused with color codes, this option is off by default. You can test
73 it and turn it on permanently in your ipython_config.py file if it
76 it and turn it on permanently in your ipython_config.py file if it
74 works for you. Test it and turn it on permanently if it works with
77 works for you. Test it and turn it on permanently if it works with
75 your system. The magic function %%color_info allows you to toggle this
78 your system. The magic function %%color_info allows you to toggle this
76 interactively for testing.""",
79 interactively for testing.""",
77 "Disable using colors for info related things."
80 "Disable using colors for info related things."
78 )
81 )
79 addflag('deep-reload', 'InteractiveShell.deep_reload',
82 addflag('deep-reload', 'InteractiveShell.deep_reload',
80 """Enable deep (recursive) reloading by default. IPython can use the
83 """Enable deep (recursive) reloading by default. IPython can use the
81 deep_reload module which reloads changes in modules recursively (it
84 deep_reload module which reloads changes in modules recursively (it
82 replaces the reload() function, so you don't need to change anything to
85 replaces the reload() function, so you don't need to change anything to
83 use it). deep_reload() forces a full reload of modules whose code may
86 use it). deep_reload() forces a full reload of modules whose code may
84 have changed, which the default reload() function does not. When
87 have changed, which the default reload() function does not. When
85 deep_reload is off, IPython will use the normal reload(), but
88 deep_reload is off, IPython will use the normal reload(), but
86 deep_reload will still be available as dreload(). This feature is off
89 deep_reload will still be available as dreload(). This feature is off
87 by default [which means that you have both normal reload() and
90 by default [which means that you have both normal reload() and
88 dreload()].""",
91 dreload()].""",
89 "Disable deep (recursive) reloading by default."
92 "Disable deep (recursive) reloading by default."
90 )
93 )
91 nosep_config = Config()
94 nosep_config = Config()
92 nosep_config.InteractiveShell.separate_in = ''
95 nosep_config.InteractiveShell.separate_in = ''
93 nosep_config.InteractiveShell.separate_out = ''
96 nosep_config.InteractiveShell.separate_out = ''
94 nosep_config.InteractiveShell.separate_out2 = ''
97 nosep_config.InteractiveShell.separate_out2 = ''
95
98
96 shell_flags['nosep']=(nosep_config, "Eliminate all spacing between prompts.")
99 shell_flags['nosep']=(nosep_config, "Eliminate all spacing between prompts.")
97
100 shell_flags['pylab'] = (
101 {'InteractiveShellApp' : {'pylab' : 'auto'}},
102 """Pre-load matplotlib and numpy for interactive use with
103 the default matplotlib backend."""
104 )
98
105
99 # it's possible we don't want short aliases for *all* of these:
106 # it's possible we don't want short aliases for *all* of these:
100 shell_aliases = dict(
107 shell_aliases = dict(
101 autocall='InteractiveShell.autocall',
108 autocall='InteractiveShell.autocall',
102 colors='InteractiveShell.colors',
109 colors='InteractiveShell.colors',
103 logfile='InteractiveShell.logfile',
110 logfile='InteractiveShell.logfile',
104 logappend='InteractiveShell.logappend',
111 logappend='InteractiveShell.logappend',
105 c='InteractiveShellApp.code_to_run',
112 c='InteractiveShellApp.code_to_run',
106 m='InteractiveShellApp.module_to_run',
113 m='InteractiveShellApp.module_to_run',
107 ext='InteractiveShellApp.extra_extension',
114 ext='InteractiveShellApp.extra_extension',
115 gui='InteractiveShellApp.gui',
116 pylab='InteractiveShellApp.pylab',
108 )
117 )
109 shell_aliases['cache-size'] = 'InteractiveShell.cache_size'
118 shell_aliases['cache-size'] = 'InteractiveShell.cache_size'
110
119
111 #-----------------------------------------------------------------------------
120 #-----------------------------------------------------------------------------
112 # Main classes and functions
121 # Main classes and functions
113 #-----------------------------------------------------------------------------
122 #-----------------------------------------------------------------------------
114
123
115 class InteractiveShellApp(Configurable):
124 class InteractiveShellApp(Configurable):
116 """A Mixin for applications that start InteractiveShell instances.
125 """A Mixin for applications that start InteractiveShell instances.
117
126
118 Provides configurables for loading extensions and executing files
127 Provides configurables for loading extensions and executing files
119 as part of configuring a Shell environment.
128 as part of configuring a Shell environment.
120
129
121 Provides init_path(), to be called before, and init_extensions() and
130 The following methods should be called by the :meth:`initialize` method
122 init_code() methods, to be called after init_shell(), which must be
131 of the subclass:
123 implemented by subclasses.
132
133 - :meth:`init_path`
134 - :meth:`init_shell` (to be implemented by the subclass)
135 - :meth:`init_gui_pylab`
136 - :meth:`init_extensions`
137 - :meth:`init_code`
124 """
138 """
125 extensions = List(Unicode, config=True,
139 extensions = List(Unicode, config=True,
126 help="A list of dotted module names of IPython extensions to load."
140 help="A list of dotted module names of IPython extensions to load."
127 )
141 )
128 extra_extension = Unicode('', config=True,
142 extra_extension = Unicode('', config=True,
129 help="dotted module name of an IPython extension to load."
143 help="dotted module name of an IPython extension to load."
130 )
144 )
131 def _extra_extension_changed(self, name, old, new):
145 def _extra_extension_changed(self, name, old, new):
132 if new:
146 if new:
133 # add to self.extensions
147 # add to self.extensions
134 self.extensions.append(new)
148 self.extensions.append(new)
135
149
136 # Extensions that are always loaded (not configurable)
150 # Extensions that are always loaded (not configurable)
137 default_extensions = List(Unicode, [u'storemagic'], config=False)
151 default_extensions = List(Unicode, [u'storemagic'], config=False)
138
152
139 exec_files = List(Unicode, config=True,
153 exec_files = List(Unicode, config=True,
140 help="""List of files to run at IPython startup."""
154 help="""List of files to run at IPython startup."""
141 )
155 )
142 file_to_run = Unicode('', config=True,
156 file_to_run = Unicode('', config=True,
143 help="""A file to be run""")
157 help="""A file to be run""")
144
158
145 exec_lines = List(Unicode, config=True,
159 exec_lines = List(Unicode, config=True,
146 help="""lines of code to run at IPython startup."""
160 help="""lines of code to run at IPython startup."""
147 )
161 )
148 code_to_run = Unicode('', config=True,
162 code_to_run = Unicode('', config=True,
149 help="Execute the given command string."
163 help="Execute the given command string."
150 )
164 )
151 module_to_run = Unicode('', config=True,
165 module_to_run = Unicode('', config=True,
152 help="Run the module as a script."
166 help="Run the module as a script."
153 )
167 )
168 gui = CaselessStrEnum(('qt', 'wx', 'gtk', 'glut', 'pyglet'), config=True,
169 help="Enable GUI event loop integration ('qt', 'wx', 'gtk', 'glut', 'pyglet')."
170 )
171 pylab = CaselessStrEnum(['tk', 'qt', 'wx', 'gtk', 'osx', 'inline', 'auto'],
172 config=True,
173 help="""Pre-load matplotlib and numpy for interactive use,
174 selecting a particular matplotlib backend and loop integration.
175 """
176 )
154 pylab_import_all = Bool(True, config=True,
177 pylab_import_all = Bool(True, config=True,
155 help="""If true, an 'import *' is done from numpy and pylab,
178 help="""If true, an 'import *' is done from numpy and pylab,
156 when using pylab"""
179 when using pylab"""
157 )
180 )
158 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
181 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
159
182
160 def init_path(self):
183 def init_path(self):
161 """Add current working directory, '', to sys.path"""
184 """Add current working directory, '', to sys.path"""
162 if sys.path[0] != '':
185 if sys.path[0] != '':
163 sys.path.insert(0, '')
186 sys.path.insert(0, '')
164
187
165 def init_shell(self):
188 def init_shell(self):
166 raise NotImplementedError("Override in subclasses")
189 raise NotImplementedError("Override in subclasses")
167
190
191 def init_gui_pylab(self):
192 """Enable GUI event loop integration, taking pylab into account."""
193 if self.gui or self.pylab:
194 shell = self.shell
195 try:
196 if self.pylab:
197 gui, backend = pylabtools.find_gui_and_backend(self.pylab)
198 self.log.info("Enabling GUI event loop integration, "
199 "toolkit=%s, pylab=%s" % (gui, self.pylab))
200 shell.enable_pylab(gui, import_all=self.pylab_import_all)
201 else:
202 self.log.info("Enabling GUI event loop integration, "
203 "toolkit=%s" % self.gui)
204 shell.enable_gui(self.gui)
205 except Exception:
206 self.log.warn("GUI event loop or pylab initialization failed")
207 self.shell.showtraceback()
208
168 def init_extensions(self):
209 def init_extensions(self):
169 """Load all IPython extensions in IPythonApp.extensions.
210 """Load all IPython extensions in IPythonApp.extensions.
170
211
171 This uses the :meth:`ExtensionManager.load_extensions` to load all
212 This uses the :meth:`ExtensionManager.load_extensions` to load all
172 the extensions listed in ``self.extensions``.
213 the extensions listed in ``self.extensions``.
173 """
214 """
174 try:
215 try:
175 self.log.debug("Loading IPython extensions...")
216 self.log.debug("Loading IPython extensions...")
176 extensions = self.default_extensions + self.extensions
217 extensions = self.default_extensions + self.extensions
177 for ext in extensions:
218 for ext in extensions:
178 try:
219 try:
179 self.log.info("Loading IPython extension: %s" % ext)
220 self.log.info("Loading IPython extension: %s" % ext)
180 self.shell.extension_manager.load_extension(ext)
221 self.shell.extension_manager.load_extension(ext)
181 except:
222 except:
182 self.log.warn("Error in loading extension: %s" % ext +
223 self.log.warn("Error in loading extension: %s" % ext +
183 "\nCheck your config files in %s" % self.profile_dir.location
224 "\nCheck your config files in %s" % self.profile_dir.location
184 )
225 )
185 self.shell.showtraceback()
226 self.shell.showtraceback()
186 except:
227 except:
187 self.log.warn("Unknown error in loading extensions:")
228 self.log.warn("Unknown error in loading extensions:")
188 self.shell.showtraceback()
229 self.shell.showtraceback()
189
230
190 def init_code(self):
231 def init_code(self):
191 """run the pre-flight code, specified via exec_lines"""
232 """run the pre-flight code, specified via exec_lines"""
192 self._run_startup_files()
233 self._run_startup_files()
193 self._run_exec_lines()
234 self._run_exec_lines()
194 self._run_exec_files()
235 self._run_exec_files()
195 self._run_cmd_line_code()
236 self._run_cmd_line_code()
196 self._run_module()
237 self._run_module()
197
238
198 # flush output, so itwon't be attached to the first cell
239 # flush output, so itwon't be attached to the first cell
199 sys.stdout.flush()
240 sys.stdout.flush()
200 sys.stderr.flush()
241 sys.stderr.flush()
201
242
202 # Hide variables defined here from %who etc.
243 # Hide variables defined here from %who etc.
203 self.shell.user_ns_hidden.update(self.shell.user_ns)
244 self.shell.user_ns_hidden.update(self.shell.user_ns)
204
245
205 def _run_exec_lines(self):
246 def _run_exec_lines(self):
206 """Run lines of code in IPythonApp.exec_lines in the user's namespace."""
247 """Run lines of code in IPythonApp.exec_lines in the user's namespace."""
207 if not self.exec_lines:
248 if not self.exec_lines:
208 return
249 return
209 try:
250 try:
210 self.log.debug("Running code from IPythonApp.exec_lines...")
251 self.log.debug("Running code from IPythonApp.exec_lines...")
211 for line in self.exec_lines:
252 for line in self.exec_lines:
212 try:
253 try:
213 self.log.info("Running code in user namespace: %s" %
254 self.log.info("Running code in user namespace: %s" %
214 line)
255 line)
215 self.shell.run_cell(line, store_history=False)
256 self.shell.run_cell(line, store_history=False)
216 except:
257 except:
217 self.log.warn("Error in executing line in user "
258 self.log.warn("Error in executing line in user "
218 "namespace: %s" % line)
259 "namespace: %s" % line)
219 self.shell.showtraceback()
260 self.shell.showtraceback()
220 except:
261 except:
221 self.log.warn("Unknown error in handling IPythonApp.exec_lines:")
262 self.log.warn("Unknown error in handling IPythonApp.exec_lines:")
222 self.shell.showtraceback()
263 self.shell.showtraceback()
223
264
224 def _exec_file(self, fname):
265 def _exec_file(self, fname):
225 try:
266 try:
226 full_filename = filefind(fname, [u'.', self.ipython_dir])
267 full_filename = filefind(fname, [u'.', self.ipython_dir])
227 except IOError as e:
268 except IOError as e:
228 self.log.warn("File not found: %r"%fname)
269 self.log.warn("File not found: %r"%fname)
229 return
270 return
230 # Make sure that the running script gets a proper sys.argv as if it
271 # Make sure that the running script gets a proper sys.argv as if it
231 # were run from a system shell.
272 # were run from a system shell.
232 save_argv = sys.argv
273 save_argv = sys.argv
233 sys.argv = [full_filename] + self.extra_args[1:]
274 sys.argv = [full_filename] + self.extra_args[1:]
234 # protect sys.argv from potential unicode strings on Python 2:
275 # protect sys.argv from potential unicode strings on Python 2:
235 if not py3compat.PY3:
276 if not py3compat.PY3:
236 sys.argv = [ py3compat.cast_bytes(a) for a in sys.argv ]
277 sys.argv = [ py3compat.cast_bytes(a) for a in sys.argv ]
237 try:
278 try:
238 if os.path.isfile(full_filename):
279 if os.path.isfile(full_filename):
239 if full_filename.endswith('.ipy'):
280 if full_filename.endswith('.ipy'):
240 self.log.info("Running file in user namespace: %s" %
281 self.log.info("Running file in user namespace: %s" %
241 full_filename)
282 full_filename)
242 self.shell.safe_execfile_ipy(full_filename)
283 self.shell.safe_execfile_ipy(full_filename)
243 else:
284 else:
244 # default to python, even without extension
285 # default to python, even without extension
245 self.log.info("Running file in user namespace: %s" %
286 self.log.info("Running file in user namespace: %s" %
246 full_filename)
287 full_filename)
247 # Ensure that __file__ is always defined to match Python behavior
288 # Ensure that __file__ is always defined to match Python behavior
248 self.shell.user_ns['__file__'] = fname
289 self.shell.user_ns['__file__'] = fname
249 try:
290 try:
250 self.shell.safe_execfile(full_filename, self.shell.user_ns)
291 self.shell.safe_execfile(full_filename, self.shell.user_ns)
251 finally:
292 finally:
252 del self.shell.user_ns['__file__']
293 del self.shell.user_ns['__file__']
253 finally:
294 finally:
254 sys.argv = save_argv
295 sys.argv = save_argv
255
296
256 def _run_startup_files(self):
297 def _run_startup_files(self):
257 """Run files from profile startup directory"""
298 """Run files from profile startup directory"""
258 startup_dir = self.profile_dir.startup_dir
299 startup_dir = self.profile_dir.startup_dir
259 startup_files = glob.glob(os.path.join(startup_dir, '*.py'))
300 startup_files = glob.glob(os.path.join(startup_dir, '*.py'))
260 startup_files += glob.glob(os.path.join(startup_dir, '*.ipy'))
301 startup_files += glob.glob(os.path.join(startup_dir, '*.ipy'))
261 if not startup_files:
302 if not startup_files:
262 return
303 return
263
304
264 self.log.debug("Running startup files from %s...", startup_dir)
305 self.log.debug("Running startup files from %s...", startup_dir)
265 try:
306 try:
266 for fname in sorted(startup_files):
307 for fname in sorted(startup_files):
267 self._exec_file(fname)
308 self._exec_file(fname)
268 except:
309 except:
269 self.log.warn("Unknown error in handling startup files:")
310 self.log.warn("Unknown error in handling startup files:")
270 self.shell.showtraceback()
311 self.shell.showtraceback()
271
312
272 def _run_exec_files(self):
313 def _run_exec_files(self):
273 """Run files from IPythonApp.exec_files"""
314 """Run files from IPythonApp.exec_files"""
274 if not self.exec_files:
315 if not self.exec_files:
275 return
316 return
276
317
277 self.log.debug("Running files in IPythonApp.exec_files...")
318 self.log.debug("Running files in IPythonApp.exec_files...")
278 try:
319 try:
279 for fname in self.exec_files:
320 for fname in self.exec_files:
280 self._exec_file(fname)
321 self._exec_file(fname)
281 except:
322 except:
282 self.log.warn("Unknown error in handling IPythonApp.exec_files:")
323 self.log.warn("Unknown error in handling IPythonApp.exec_files:")
283 self.shell.showtraceback()
324 self.shell.showtraceback()
284
325
285 def _run_cmd_line_code(self):
326 def _run_cmd_line_code(self):
286 """Run code or file specified at the command-line"""
327 """Run code or file specified at the command-line"""
287 if self.code_to_run:
328 if self.code_to_run:
288 line = self.code_to_run
329 line = self.code_to_run
289 try:
330 try:
290 self.log.info("Running code given at command line (c=): %s" %
331 self.log.info("Running code given at command line (c=): %s" %
291 line)
332 line)
292 self.shell.run_cell(line, store_history=False)
333 self.shell.run_cell(line, store_history=False)
293 except:
334 except:
294 self.log.warn("Error in executing line in user namespace: %s" %
335 self.log.warn("Error in executing line in user namespace: %s" %
295 line)
336 line)
296 self.shell.showtraceback()
337 self.shell.showtraceback()
297
338
298 # Like Python itself, ignore the second if the first of these is present
339 # Like Python itself, ignore the second if the first of these is present
299 elif self.file_to_run:
340 elif self.file_to_run:
300 fname = self.file_to_run
341 fname = self.file_to_run
301 try:
342 try:
302 self._exec_file(fname)
343 self._exec_file(fname)
303 except:
344 except:
304 self.log.warn("Error in executing file in user namespace: %s" %
345 self.log.warn("Error in executing file in user namespace: %s" %
305 fname)
346 fname)
306 self.shell.showtraceback()
347 self.shell.showtraceback()
307
348
308 def _run_module(self):
349 def _run_module(self):
309 """Run module specified at the command-line."""
350 """Run module specified at the command-line."""
310 if self.module_to_run:
351 if self.module_to_run:
311 # Make sure that the module gets a proper sys.argv as if it were
352 # Make sure that the module gets a proper sys.argv as if it were
312 # run using `python -m`.
353 # run using `python -m`.
313 save_argv = sys.argv
354 save_argv = sys.argv
314 sys.argv = [sys.executable] + self.extra_args
355 sys.argv = [sys.executable] + self.extra_args
315 try:
356 try:
316 self.shell.safe_run_module(self.module_to_run,
357 self.shell.safe_run_module(self.module_to_run,
317 self.shell.user_ns)
358 self.shell.user_ns)
318 finally:
359 finally:
319 sys.argv = save_argv
360 sys.argv = save_argv
@@ -1,156 +1,154 b''
1 """ A minimal application using the ZMQ-based terminal IPython frontend.
1 """ A minimal application using the ZMQ-based terminal IPython frontend.
2
2
3 This is not a complete console app, as subprocess will not be able to receive
3 This is not a complete console app, as subprocess will not be able to receive
4 input, there is no real readline support, among other limitations.
4 input, there is no real readline support, among other limitations.
5
5
6 Authors:
6 Authors:
7
7
8 * Min RK
8 * Min RK
9 * Paul Ivanov
9 * Paul Ivanov
10
10
11 """
11 """
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 import signal
16 import signal
17 import sys
17 import sys
18 import time
18 import time
19
19
20 from IPython.frontend.terminal.ipapp import TerminalIPythonApp, frontend_flags as term_flags
20 from IPython.frontend.terminal.ipapp import TerminalIPythonApp, frontend_flags as term_flags
21
21
22 from IPython.utils.traitlets import (
22 from IPython.utils.traitlets import (
23 Dict, List, Unicode, Int, CaselessStrEnum, CBool, Any
23 Dict, List, Unicode, Int, CaselessStrEnum, CBool, Any
24 )
24 )
25 from IPython.utils.warn import warn,error
25 from IPython.utils.warn import warn,error
26
26
27 from IPython.zmq.ipkernel import IPKernelApp
27 from IPython.zmq.ipkernel import IPKernelApp
28 from IPython.zmq.session import Session, default_secure
28 from IPython.zmq.session import Session, default_secure
29 from IPython.zmq.zmqshell import ZMQInteractiveShell
29 from IPython.zmq.zmqshell import ZMQInteractiveShell
30 from IPython.frontend.consoleapp import (
30 from IPython.frontend.consoleapp import (
31 IPythonConsoleApp, app_aliases, app_flags, aliases, app_aliases, flags
31 IPythonConsoleApp, app_aliases, app_flags, aliases, app_aliases, flags
32 )
32 )
33
33
34 from IPython.frontend.terminal.console.interactiveshell import ZMQTerminalInteractiveShell
34 from IPython.frontend.terminal.console.interactiveshell import ZMQTerminalInteractiveShell
35
35
36 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
37 # Globals
37 # Globals
38 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
39
39
40 _examples = """
40 _examples = """
41 ipython console # start the ZMQ-based console
41 ipython console # start the ZMQ-based console
42 ipython console --existing # connect to an existing ipython session
42 ipython console --existing # connect to an existing ipython session
43 """
43 """
44
44
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46 # Flags and Aliases
46 # Flags and Aliases
47 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
48
48
49 # copy flags from mixin:
49 # copy flags from mixin:
50 flags = dict(flags)
50 flags = dict(flags)
51 # start with mixin frontend flags:
51 # start with mixin frontend flags:
52 frontend_flags = dict(app_flags)
52 frontend_flags = dict(app_flags)
53 # add TerminalIPApp flags:
53 # add TerminalIPApp flags:
54 frontend_flags.update(term_flags)
54 frontend_flags.update(term_flags)
55 # pylab is not frontend-specific in two-process IPython
56 frontend_flags.pop('pylab')
57 # disable quick startup, as it won't propagate to the kernel anyway
55 # disable quick startup, as it won't propagate to the kernel anyway
58 frontend_flags.pop('quick')
56 frontend_flags.pop('quick')
59 # update full dict with frontend flags:
57 # update full dict with frontend flags:
60 flags.update(frontend_flags)
58 flags.update(frontend_flags)
61
59
62 # copy flags from mixin
60 # copy flags from mixin
63 aliases = dict(aliases)
61 aliases = dict(aliases)
64 # start with mixin frontend flags
62 # start with mixin frontend flags
65 frontend_aliases = dict(app_aliases)
63 frontend_aliases = dict(app_aliases)
66 # load updated frontend flags into full dict
64 # load updated frontend flags into full dict
67 aliases.update(frontend_aliases)
65 aliases.update(frontend_aliases)
68
66
69 # get flags&aliases into sets, and remove a couple that
67 # get flags&aliases into sets, and remove a couple that
70 # shouldn't be scrubbed from backend flags:
68 # shouldn't be scrubbed from backend flags:
71 frontend_aliases = set(frontend_aliases.keys())
69 frontend_aliases = set(frontend_aliases.keys())
72 frontend_flags = set(frontend_flags.keys())
70 frontend_flags = set(frontend_flags.keys())
73
71
74
72
75 #-----------------------------------------------------------------------------
73 #-----------------------------------------------------------------------------
76 # Classes
74 # Classes
77 #-----------------------------------------------------------------------------
75 #-----------------------------------------------------------------------------
78
76
79
77
80 class ZMQTerminalIPythonApp(TerminalIPythonApp, IPythonConsoleApp):
78 class ZMQTerminalIPythonApp(TerminalIPythonApp, IPythonConsoleApp):
81 name = "ipython-console"
79 name = "ipython-console"
82 """Start a terminal frontend to the IPython zmq kernel."""
80 """Start a terminal frontend to the IPython zmq kernel."""
83
81
84 description = """
82 description = """
85 The IPython terminal-based Console.
83 The IPython terminal-based Console.
86
84
87 This launches a Console application inside a terminal.
85 This launches a Console application inside a terminal.
88
86
89 The Console supports various extra features beyond the traditional
87 The Console supports various extra features beyond the traditional
90 single-process Terminal IPython shell, such as connecting to an
88 single-process Terminal IPython shell, such as connecting to an
91 existing ipython session, via:
89 existing ipython session, via:
92
90
93 ipython console --existing
91 ipython console --existing
94
92
95 where the previous session could have been created by another ipython
93 where the previous session could have been created by another ipython
96 console, an ipython qtconsole, or by opening an ipython notebook.
94 console, an ipython qtconsole, or by opening an ipython notebook.
97
95
98 """
96 """
99 examples = _examples
97 examples = _examples
100
98
101 classes = List([IPKernelApp, ZMQTerminalInteractiveShell, Session])
99 classes = List([IPKernelApp, ZMQTerminalInteractiveShell, Session])
102 flags = Dict(flags)
100 flags = Dict(flags)
103 aliases = Dict(aliases)
101 aliases = Dict(aliases)
104 frontend_aliases = Any(frontend_aliases)
102 frontend_aliases = Any(frontend_aliases)
105 frontend_flags = Any(frontend_flags)
103 frontend_flags = Any(frontend_flags)
106
104
107 subcommands = Dict()
105 subcommands = Dict()
108
106
109 def parse_command_line(self, argv=None):
107 def parse_command_line(self, argv=None):
110 super(ZMQTerminalIPythonApp, self).parse_command_line(argv)
108 super(ZMQTerminalIPythonApp, self).parse_command_line(argv)
111 self.build_kernel_argv(argv)
109 self.build_kernel_argv(argv)
112
110
113 def init_shell(self):
111 def init_shell(self):
114 IPythonConsoleApp.initialize(self)
112 IPythonConsoleApp.initialize(self)
115 # relay sigint to kernel
113 # relay sigint to kernel
116 signal.signal(signal.SIGINT, self.handle_sigint)
114 signal.signal(signal.SIGINT, self.handle_sigint)
117 self.shell = ZMQTerminalInteractiveShell.instance(config=self.config,
115 self.shell = ZMQTerminalInteractiveShell.instance(config=self.config,
118 display_banner=False, profile_dir=self.profile_dir,
116 display_banner=False, profile_dir=self.profile_dir,
119 ipython_dir=self.ipython_dir, kernel_manager=self.kernel_manager)
117 ipython_dir=self.ipython_dir, kernel_manager=self.kernel_manager)
120
118
121 def init_gui_pylab(self):
119 def init_gui_pylab(self):
122 # no-op, because we don't want to import matplotlib in the frontend.
120 # no-op, because we don't want to import matplotlib in the frontend.
123 pass
121 pass
124
122
125 def handle_sigint(self, *args):
123 def handle_sigint(self, *args):
126 if self.shell._executing:
124 if self.shell._executing:
127 if self.kernel_manager.has_kernel:
125 if self.kernel_manager.has_kernel:
128 # interrupt already gets passed to subprocess by signal handler.
126 # interrupt already gets passed to subprocess by signal handler.
129 # Only if we prevent that should we need to explicitly call
127 # Only if we prevent that should we need to explicitly call
130 # interrupt_kernel, until which time, this would result in a
128 # interrupt_kernel, until which time, this would result in a
131 # double-interrupt:
129 # double-interrupt:
132 # self.kernel_manager.interrupt_kernel()
130 # self.kernel_manager.interrupt_kernel()
133 pass
131 pass
134 else:
132 else:
135 self.shell.write_err('\n')
133 self.shell.write_err('\n')
136 error("Cannot interrupt kernels we didn't start.\n")
134 error("Cannot interrupt kernels we didn't start.\n")
137 else:
135 else:
138 # raise the KeyboardInterrupt if we aren't waiting for execution,
136 # raise the KeyboardInterrupt if we aren't waiting for execution,
139 # so that the interact loop advances, and prompt is redrawn, etc.
137 # so that the interact loop advances, and prompt is redrawn, etc.
140 raise KeyboardInterrupt
138 raise KeyboardInterrupt
141
139
142
140
143 def init_code(self):
141 def init_code(self):
144 # no-op in the frontend, code gets run in the backend
142 # no-op in the frontend, code gets run in the backend
145 pass
143 pass
146
144
147 def launch_new_instance():
145 def launch_new_instance():
148 """Create and run a full blown IPython instance"""
146 """Create and run a full blown IPython instance"""
149 app = ZMQTerminalIPythonApp.instance()
147 app = ZMQTerminalIPythonApp.instance()
150 app.initialize()
148 app.initialize()
151 app.start()
149 app.start()
152
150
153
151
154 if __name__ == '__main__':
152 if __name__ == '__main__':
155 launch_new_instance()
153 launch_new_instance()
156
154
@@ -1,412 +1,370 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-2011 The IPython Development Team
16 # Copyright (C) 2008-2011 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.history import HistoryManager
41 from IPython.core.history import HistoryManager
42 from IPython.core.prompts import PromptManager
42 from IPython.core.prompts import PromptManager
43 from IPython.core.application import (
43 from IPython.core.application import (
44 ProfileDir, BaseIPythonApplication, base_flags, base_aliases
44 ProfileDir, BaseIPythonApplication, base_flags, base_aliases
45 )
45 )
46 from IPython.core.shellapp import (
46 from IPython.core.shellapp import (
47 InteractiveShellApp, shell_flags, shell_aliases
47 InteractiveShellApp, shell_flags, shell_aliases
48 )
48 )
49 from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
49 from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
50 from IPython.lib import inputhook
50 from IPython.lib import inputhook
51 from IPython.utils import warn
51 from IPython.utils import warn
52 from IPython.utils.path import get_ipython_dir, check_for_old_config
52 from IPython.utils.path import get_ipython_dir, check_for_old_config
53 from IPython.utils.traitlets import (
53 from IPython.utils.traitlets import (
54 Bool, List, Dict, CaselessStrEnum
54 Bool, List, Dict, CaselessStrEnum
55 )
55 )
56
56
57 #-----------------------------------------------------------------------------
57 #-----------------------------------------------------------------------------
58 # Globals, utilities and helpers
58 # Globals, utilities and helpers
59 #-----------------------------------------------------------------------------
59 #-----------------------------------------------------------------------------
60
60
61 #: The default config file name for this application.
61 #: The default config file name for this application.
62 default_config_file_name = u'ipython_config.py'
62 default_config_file_name = u'ipython_config.py'
63
63
64 _examples = """
64 _examples = """
65 ipython --pylab # start in pylab mode
65 ipython --pylab # start in pylab mode
66 ipython --pylab=qt # start in pylab mode with the qt4 backend
66 ipython --pylab=qt # start in pylab mode with the qt4 backend
67 ipython --log-level=DEBUG # set logging to DEBUG
67 ipython --log-level=DEBUG # set logging to DEBUG
68 ipython --profile=foo # start with profile foo
68 ipython --profile=foo # start with profile foo
69
69
70 ipython qtconsole # start the qtconsole GUI application
70 ipython qtconsole # start the qtconsole GUI application
71 ipython help qtconsole # show the help for the qtconsole subcmd
71 ipython help qtconsole # show the help for the qtconsole subcmd
72
72
73 ipython console # start the terminal-based console application
73 ipython console # start the terminal-based console application
74 ipython help console # show the help for the console subcmd
74 ipython help console # show the help for the console subcmd
75
75
76 ipython notebook # start the IPython notebook
76 ipython notebook # start the IPython notebook
77 ipython help notebook # show the help for the notebook subcmd
77 ipython help notebook # show the help for the notebook subcmd
78
78
79 ipython profile create foo # create profile foo w/ default config files
79 ipython profile create foo # create profile foo w/ default config files
80 ipython help profile # show the help for the profile subcmd
80 ipython help profile # show the help for the profile subcmd
81 """
81 """
82
82
83 #-----------------------------------------------------------------------------
83 #-----------------------------------------------------------------------------
84 # Crash handler for this application
84 # Crash handler for this application
85 #-----------------------------------------------------------------------------
85 #-----------------------------------------------------------------------------
86
86
87 class IPAppCrashHandler(CrashHandler):
87 class IPAppCrashHandler(CrashHandler):
88 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
88 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
89
89
90 def __init__(self, app):
90 def __init__(self, app):
91 contact_name = release.authors['Fernando'][0]
91 contact_name = release.authors['Fernando'][0]
92 contact_email = release.author_email
92 contact_email = release.author_email
93 bug_tracker = 'https://github.com/ipython/ipython/issues'
93 bug_tracker = 'https://github.com/ipython/ipython/issues'
94 super(IPAppCrashHandler,self).__init__(
94 super(IPAppCrashHandler,self).__init__(
95 app, contact_name, contact_email, bug_tracker
95 app, contact_name, contact_email, bug_tracker
96 )
96 )
97
97
98 def make_report(self,traceback):
98 def make_report(self,traceback):
99 """Return a string containing a crash report."""
99 """Return a string containing a crash report."""
100
100
101 sec_sep = self.section_sep
101 sec_sep = self.section_sep
102 # Start with parent report
102 # Start with parent report
103 report = [super(IPAppCrashHandler, self).make_report(traceback)]
103 report = [super(IPAppCrashHandler, self).make_report(traceback)]
104 # Add interactive-specific info we may have
104 # Add interactive-specific info we may have
105 rpt_add = report.append
105 rpt_add = report.append
106 try:
106 try:
107 rpt_add(sec_sep+"History of session input:")
107 rpt_add(sec_sep+"History of session input:")
108 for line in self.app.shell.user_ns['_ih']:
108 for line in self.app.shell.user_ns['_ih']:
109 rpt_add(line)
109 rpt_add(line)
110 rpt_add('\n*** Last line of input (may not be in above history):\n')
110 rpt_add('\n*** Last line of input (may not be in above history):\n')
111 rpt_add(self.app.shell._last_input_line+'\n')
111 rpt_add(self.app.shell._last_input_line+'\n')
112 except:
112 except:
113 pass
113 pass
114
114
115 return ''.join(report)
115 return ''.join(report)
116
116
117 #-----------------------------------------------------------------------------
117 #-----------------------------------------------------------------------------
118 # Aliases and Flags
118 # Aliases and Flags
119 #-----------------------------------------------------------------------------
119 #-----------------------------------------------------------------------------
120 flags = dict(base_flags)
120 flags = dict(base_flags)
121 flags.update(shell_flags)
121 flags.update(shell_flags)
122 frontend_flags = {}
122 frontend_flags = {}
123 addflag = lambda *args: frontend_flags.update(boolean_flag(*args))
123 addflag = lambda *args: frontend_flags.update(boolean_flag(*args))
124 addflag('autoedit-syntax', 'TerminalInteractiveShell.autoedit_syntax',
124 addflag('autoedit-syntax', 'TerminalInteractiveShell.autoedit_syntax',
125 'Turn on auto editing of files with syntax errors.',
125 'Turn on auto editing of files with syntax errors.',
126 'Turn off auto editing of files with syntax errors.'
126 'Turn off auto editing of files with syntax errors.'
127 )
127 )
128 addflag('banner', 'TerminalIPythonApp.display_banner',
128 addflag('banner', 'TerminalIPythonApp.display_banner',
129 "Display a banner upon starting IPython.",
129 "Display a banner upon starting IPython.",
130 "Don't display a banner upon starting IPython."
130 "Don't display a banner upon starting IPython."
131 )
131 )
132 addflag('confirm-exit', 'TerminalInteractiveShell.confirm_exit',
132 addflag('confirm-exit', 'TerminalInteractiveShell.confirm_exit',
133 """Set to confirm when you try to exit IPython with an EOF (Control-D
133 """Set to confirm when you try to exit IPython with an EOF (Control-D
134 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
134 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
135 you can force a direct exit without any confirmation.""",
135 you can force a direct exit without any confirmation.""",
136 "Don't prompt the user when exiting."
136 "Don't prompt the user when exiting."
137 )
137 )
138 addflag('term-title', 'TerminalInteractiveShell.term_title',
138 addflag('term-title', 'TerminalInteractiveShell.term_title',
139 "Enable auto setting the terminal title.",
139 "Enable auto setting the terminal title.",
140 "Disable auto setting the terminal title."
140 "Disable auto setting the terminal title."
141 )
141 )
142 classic_config = Config()
142 classic_config = Config()
143 classic_config.InteractiveShell.cache_size = 0
143 classic_config.InteractiveShell.cache_size = 0
144 classic_config.PlainTextFormatter.pprint = False
144 classic_config.PlainTextFormatter.pprint = False
145 classic_config.PromptManager.in_template = '>>> '
145 classic_config.PromptManager.in_template = '>>> '
146 classic_config.PromptManager.in2_template = '... '
146 classic_config.PromptManager.in2_template = '... '
147 classic_config.PromptManager.out_template = ''
147 classic_config.PromptManager.out_template = ''
148 classic_config.InteractiveShell.separate_in = ''
148 classic_config.InteractiveShell.separate_in = ''
149 classic_config.InteractiveShell.separate_out = ''
149 classic_config.InteractiveShell.separate_out = ''
150 classic_config.InteractiveShell.separate_out2 = ''
150 classic_config.InteractiveShell.separate_out2 = ''
151 classic_config.InteractiveShell.colors = 'NoColor'
151 classic_config.InteractiveShell.colors = 'NoColor'
152 classic_config.InteractiveShell.xmode = 'Plain'
152 classic_config.InteractiveShell.xmode = 'Plain'
153
153
154 frontend_flags['classic']=(
154 frontend_flags['classic']=(
155 classic_config,
155 classic_config,
156 "Gives IPython a similar feel to the classic Python prompt."
156 "Gives IPython a similar feel to the classic Python prompt."
157 )
157 )
158 # # log doesn't make so much sense this way anymore
158 # # log doesn't make so much sense this way anymore
159 # paa('--log','-l',
159 # paa('--log','-l',
160 # action='store_true', dest='InteractiveShell.logstart',
160 # action='store_true', dest='InteractiveShell.logstart',
161 # help="Start logging to the default log file (./ipython_log.py).")
161 # help="Start logging to the default log file (./ipython_log.py).")
162 #
162 #
163 # # quick is harder to implement
163 # # quick is harder to implement
164 frontend_flags['quick']=(
164 frontend_flags['quick']=(
165 {'TerminalIPythonApp' : {'quick' : True}},
165 {'TerminalIPythonApp' : {'quick' : True}},
166 "Enable quick startup with no config files."
166 "Enable quick startup with no config files."
167 )
167 )
168
168
169 frontend_flags['i'] = (
169 frontend_flags['i'] = (
170 {'TerminalIPythonApp' : {'force_interact' : True}},
170 {'TerminalIPythonApp' : {'force_interact' : True}},
171 """If running code from the command line, become interactive afterwards.
171 """If running code from the command line, become interactive afterwards.
172 Note: can also be given simply as '-i.'"""
172 Note: can also be given simply as '-i.'"""
173 )
173 )
174 frontend_flags['pylab'] = (
175 {'TerminalIPythonApp' : {'pylab' : 'auto'}},
176 """Pre-load matplotlib and numpy for interactive use with
177 the default matplotlib backend."""
178 )
179 flags.update(frontend_flags)
174 flags.update(frontend_flags)
180
175
181 aliases = dict(base_aliases)
176 aliases = dict(base_aliases)
182 aliases.update(shell_aliases)
177 aliases.update(shell_aliases)
183
178
184 # it's possible we don't want short aliases for *all* of these:
185 aliases.update(dict(
186 gui='TerminalIPythonApp.gui',
187 pylab='TerminalIPythonApp.pylab',
188 ))
189
190 #-----------------------------------------------------------------------------
179 #-----------------------------------------------------------------------------
191 # Main classes and functions
180 # Main classes and functions
192 #-----------------------------------------------------------------------------
181 #-----------------------------------------------------------------------------
193
182
194 class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):
183 class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):
195 name = u'ipython'
184 name = u'ipython'
196 description = usage.cl_usage
185 description = usage.cl_usage
197 default_config_file_name = default_config_file_name
186 default_config_file_name = default_config_file_name
198 crash_handler_class = IPAppCrashHandler
187 crash_handler_class = IPAppCrashHandler
199 examples = _examples
188 examples = _examples
200
189
201 flags = Dict(flags)
190 flags = Dict(flags)
202 aliases = Dict(aliases)
191 aliases = Dict(aliases)
203 classes = List()
192 classes = List()
204 def _classes_default(self):
193 def _classes_default(self):
205 """This has to be in a method, for TerminalIPythonApp to be available."""
194 """This has to be in a method, for TerminalIPythonApp to be available."""
206 return [
195 return [
207 InteractiveShellApp, # ShellApp comes before TerminalApp, because
196 InteractiveShellApp, # ShellApp comes before TerminalApp, because
208 self.__class__, # it will also affect subclasses (e.g. QtConsole)
197 self.__class__, # it will also affect subclasses (e.g. QtConsole)
209 TerminalInteractiveShell,
198 TerminalInteractiveShell,
210 PromptManager,
199 PromptManager,
211 HistoryManager,
200 HistoryManager,
212 ProfileDir,
201 ProfileDir,
213 PlainTextFormatter,
202 PlainTextFormatter,
214 IPCompleter,
203 IPCompleter,
215 ]
204 ]
216
205
217 subcommands = Dict(dict(
206 subcommands = Dict(dict(
218 qtconsole=('IPython.frontend.qt.console.qtconsoleapp.IPythonQtConsoleApp',
207 qtconsole=('IPython.frontend.qt.console.qtconsoleapp.IPythonQtConsoleApp',
219 """Launch the IPython Qt Console."""
208 """Launch the IPython Qt Console."""
220 ),
209 ),
221 notebook=('IPython.frontend.html.notebook.notebookapp.NotebookApp',
210 notebook=('IPython.frontend.html.notebook.notebookapp.NotebookApp',
222 """Launch the IPython HTML Notebook Server."""
211 """Launch the IPython HTML Notebook Server."""
223 ),
212 ),
224 profile = ("IPython.core.profileapp.ProfileApp",
213 profile = ("IPython.core.profileapp.ProfileApp",
225 "Create and manage IPython profiles."
214 "Create and manage IPython profiles."
226 ),
215 ),
227 kernel = ("IPython.zmq.ipkernel.IPKernelApp",
216 kernel = ("IPython.zmq.ipkernel.IPKernelApp",
228 "Start a kernel without an attached frontend."
217 "Start a kernel without an attached frontend."
229 ),
218 ),
230 console=('IPython.frontend.terminal.console.app.ZMQTerminalIPythonApp',
219 console=('IPython.frontend.terminal.console.app.ZMQTerminalIPythonApp',
231 """Launch the IPython terminal-based Console."""
220 """Launch the IPython terminal-based Console."""
232 ),
221 ),
233 ))
222 ))
234
223
235 # *do* autocreate requested profile, but don't create the config file.
224 # *do* autocreate requested profile, but don't create the config file.
236 auto_create=Bool(True)
225 auto_create=Bool(True)
237 # configurables
226 # configurables
238 ignore_old_config=Bool(False, config=True,
227 ignore_old_config=Bool(False, config=True,
239 help="Suppress warning messages about legacy config files"
228 help="Suppress warning messages about legacy config files"
240 )
229 )
241 quick = Bool(False, config=True,
230 quick = Bool(False, config=True,
242 help="""Start IPython quickly by skipping the loading of config files."""
231 help="""Start IPython quickly by skipping the loading of config files."""
243 )
232 )
244 def _quick_changed(self, name, old, new):
233 def _quick_changed(self, name, old, new):
245 if new:
234 if new:
246 self.load_config_file = lambda *a, **kw: None
235 self.load_config_file = lambda *a, **kw: None
247 self.ignore_old_config=True
236 self.ignore_old_config=True
248
237
249 gui = CaselessStrEnum(('qt', 'wx', 'gtk', 'glut', 'pyglet'), config=True,
250 help="Enable GUI event loop integration ('qt', 'wx', 'gtk', 'glut', 'pyglet')."
251 )
252 pylab = CaselessStrEnum(['tk', 'qt', 'wx', 'gtk', 'osx', 'auto'],
253 config=True,
254 help="""Pre-load matplotlib and numpy for interactive use,
255 selecting a particular matplotlib backend and loop integration.
256 """
257 )
258 display_banner = Bool(True, config=True,
238 display_banner = Bool(True, config=True,
259 help="Whether to display a banner upon starting IPython."
239 help="Whether to display a banner upon starting IPython."
260 )
240 )
261
241
262 # if there is code of files to run from the cmd line, don't interact
242 # if there is code of files to run from the cmd line, don't interact
263 # unless the --i flag (App.force_interact) is true.
243 # unless the --i flag (App.force_interact) is true.
264 force_interact = Bool(False, config=True,
244 force_interact = Bool(False, config=True,
265 help="""If a command or file is given via the command-line,
245 help="""If a command or file is given via the command-line,
266 e.g. 'ipython foo.py"""
246 e.g. 'ipython foo.py"""
267 )
247 )
268 def _force_interact_changed(self, name, old, new):
248 def _force_interact_changed(self, name, old, new):
269 if new:
249 if new:
270 self.interact = True
250 self.interact = True
271
251
272 def _file_to_run_changed(self, name, old, new):
252 def _file_to_run_changed(self, name, old, new):
273 if new:
253 if new:
274 self.something_to_run = True
254 self.something_to_run = True
275 if new and not self.force_interact:
255 if new and not self.force_interact:
276 self.interact = False
256 self.interact = False
277 _code_to_run_changed = _file_to_run_changed
257 _code_to_run_changed = _file_to_run_changed
278 _module_to_run_changed = _file_to_run_changed
258 _module_to_run_changed = _file_to_run_changed
279
259
280 # internal, not-configurable
260 # internal, not-configurable
281 interact=Bool(True)
261 interact=Bool(True)
282 something_to_run=Bool(False)
262 something_to_run=Bool(False)
283
263
284 def parse_command_line(self, argv=None):
264 def parse_command_line(self, argv=None):
285 """override to allow old '-pylab' flag with deprecation warning"""
265 """override to allow old '-pylab' flag with deprecation warning"""
286
266
287 argv = sys.argv[1:] if argv is None else argv
267 argv = sys.argv[1:] if argv is None else argv
288
268
289 if '-pylab' in argv:
269 if '-pylab' in argv:
290 # deprecated `-pylab` given,
270 # deprecated `-pylab` given,
291 # warn and transform into current syntax
271 # warn and transform into current syntax
292 argv = argv[:] # copy, don't clobber
272 argv = argv[:] # copy, don't clobber
293 idx = argv.index('-pylab')
273 idx = argv.index('-pylab')
294 warn.warn("`-pylab` flag has been deprecated.\n"
274 warn.warn("`-pylab` flag has been deprecated.\n"
295 " Use `--pylab` instead, or `--pylab=foo` to specify a backend.")
275 " Use `--pylab` instead, or `--pylab=foo` to specify a backend.")
296 sub = '--pylab'
276 sub = '--pylab'
297 if len(argv) > idx+1:
277 if len(argv) > idx+1:
298 # check for gui arg, as in '-pylab qt'
278 # check for gui arg, as in '-pylab qt'
299 gui = argv[idx+1]
279 gui = argv[idx+1]
300 if gui in ('wx', 'qt', 'qt4', 'gtk', 'auto'):
280 if gui in ('wx', 'qt', 'qt4', 'gtk', 'auto'):
301 sub = '--pylab='+gui
281 sub = '--pylab='+gui
302 argv.pop(idx+1)
282 argv.pop(idx+1)
303 argv[idx] = sub
283 argv[idx] = sub
304
284
305 return super(TerminalIPythonApp, self).parse_command_line(argv)
285 return super(TerminalIPythonApp, self).parse_command_line(argv)
306
286
307 @catch_config_error
287 @catch_config_error
308 def initialize(self, argv=None):
288 def initialize(self, argv=None):
309 """Do actions after construct, but before starting the app."""
289 """Do actions after construct, but before starting the app."""
310 super(TerminalIPythonApp, self).initialize(argv)
290 super(TerminalIPythonApp, self).initialize(argv)
311 if self.subapp is not None:
291 if self.subapp is not None:
312 # don't bother initializing further, starting subapp
292 # don't bother initializing further, starting subapp
313 return
293 return
314 if not self.ignore_old_config:
294 if not self.ignore_old_config:
315 check_for_old_config(self.ipython_dir)
295 check_for_old_config(self.ipython_dir)
316 # print self.extra_args
296 # print self.extra_args
317 if self.extra_args and not self.something_to_run:
297 if self.extra_args and not self.something_to_run:
318 self.file_to_run = self.extra_args[0]
298 self.file_to_run = self.extra_args[0]
319 self.init_path()
299 self.init_path()
320 # create the shell
300 # create the shell
321 self.init_shell()
301 self.init_shell()
322 # and draw the banner
302 # and draw the banner
323 self.init_banner()
303 self.init_banner()
324 # Now a variety of things that happen after the banner is printed.
304 # Now a variety of things that happen after the banner is printed.
325 self.init_gui_pylab()
305 self.init_gui_pylab()
326 self.init_extensions()
306 self.init_extensions()
327 self.init_code()
307 self.init_code()
328
308
329 def init_shell(self):
309 def init_shell(self):
330 """initialize the InteractiveShell instance"""
310 """initialize the InteractiveShell instance"""
331 # Create an InteractiveShell instance.
311 # Create an InteractiveShell instance.
332 # shell.display_banner should always be False for the terminal
312 # shell.display_banner should always be False for the terminal
333 # based app, because we call shell.show_banner() by hand below
313 # based app, because we call shell.show_banner() by hand below
334 # so the banner shows *before* all extension loading stuff.
314 # so the banner shows *before* all extension loading stuff.
335 self.shell = TerminalInteractiveShell.instance(config=self.config,
315 self.shell = TerminalInteractiveShell.instance(config=self.config,
336 display_banner=False, profile_dir=self.profile_dir,
316 display_banner=False, profile_dir=self.profile_dir,
337 ipython_dir=self.ipython_dir)
317 ipython_dir=self.ipython_dir)
338 self.shell.configurables.append(self)
318 self.shell.configurables.append(self)
339
319
340 def init_banner(self):
320 def init_banner(self):
341 """optionally display the banner"""
321 """optionally display the banner"""
342 if self.display_banner and self.interact:
322 if self.display_banner and self.interact:
343 self.shell.show_banner()
323 self.shell.show_banner()
344 # Make sure there is a space below the banner.
324 # Make sure there is a space below the banner.
345 if self.log_level <= logging.INFO: print
325 if self.log_level <= logging.INFO: print
346
326
347
327 def _pylab_changed(self, name, old, new):
348 def init_gui_pylab(self):
328 """Replace --pylab='inline' with --pylab='auto'"""
349 """Enable GUI event loop integration, taking pylab into account."""
329 if new == 'inline':
350 gui = self.gui
330 warn.warn("'inline' not available as pylab backend, "
351
331 "using 'auto' instead.\n")
352 # Using `pylab` will also require gui activation, though which toolkit
332 self.pylab = 'auto'
353 # to use may be chosen automatically based on mpl configuration.
354 if self.pylab:
355 activate = self.shell.enable_pylab
356 if self.pylab == 'auto':
357 gui = None
358 else:
359 gui = self.pylab
360 else:
361 # Enable only GUI integration, no pylab
362 activate = inputhook.enable_gui
363
364 if gui or self.pylab:
365 try:
366 self.log.info("Enabling GUI event loop integration, "
367 "toolkit=%s, pylab=%s" % (gui, self.pylab) )
368 if self.pylab:
369 activate(gui, import_all=self.pylab_import_all)
370 else:
371 activate(gui)
372 except:
373 self.log.warn("Error in enabling GUI event loop integration:")
374 self.shell.showtraceback()
375
333
376 def start(self):
334 def start(self):
377 if self.subapp is not None:
335 if self.subapp is not None:
378 return self.subapp.start()
336 return self.subapp.start()
379 # perform any prexec steps:
337 # perform any prexec steps:
380 if self.interact:
338 if self.interact:
381 self.log.debug("Starting IPython's mainloop...")
339 self.log.debug("Starting IPython's mainloop...")
382 self.shell.mainloop()
340 self.shell.mainloop()
383 else:
341 else:
384 self.log.debug("IPython not interactive...")
342 self.log.debug("IPython not interactive...")
385
343
386
344
387 def load_default_config(ipython_dir=None):
345 def load_default_config(ipython_dir=None):
388 """Load the default config file from the default ipython_dir.
346 """Load the default config file from the default ipython_dir.
389
347
390 This is useful for embedded shells.
348 This is useful for embedded shells.
391 """
349 """
392 if ipython_dir is None:
350 if ipython_dir is None:
393 ipython_dir = get_ipython_dir()
351 ipython_dir = get_ipython_dir()
394 profile_dir = os.path.join(ipython_dir, 'profile_default')
352 profile_dir = os.path.join(ipython_dir, 'profile_default')
395 cl = PyFileConfigLoader(default_config_file_name, profile_dir)
353 cl = PyFileConfigLoader(default_config_file_name, profile_dir)
396 try:
354 try:
397 config = cl.load_config()
355 config = cl.load_config()
398 except ConfigFileNotFound:
356 except ConfigFileNotFound:
399 # no config found
357 # no config found
400 config = Config()
358 config = Config()
401 return config
359 return config
402
360
403
361
404 def launch_new_instance():
362 def launch_new_instance():
405 """Create and run a full blown IPython instance"""
363 """Create and run a full blown IPython instance"""
406 app = TerminalIPythonApp.instance()
364 app = TerminalIPythonApp.instance()
407 app.initialize()
365 app.initialize()
408 app.start()
366 app.start()
409
367
410
368
411 if __name__ == '__main__':
369 if __name__ == '__main__':
412 launch_new_instance()
370 launch_new_instance()
@@ -1,934 +1,905 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 import uuid
25 import uuid
26
26
27 from datetime import datetime
27 from datetime import datetime
28 from signal import (
28 from signal import (
29 signal, getsignal, default_int_handler, SIGINT, SIG_IGN
29 signal, getsignal, default_int_handler, SIGINT, SIG_IGN
30 )
30 )
31
31
32 # System library imports
32 # System library imports
33 import zmq
33 import zmq
34 from zmq.eventloop import ioloop
34 from zmq.eventloop import ioloop
35 from zmq.eventloop.zmqstream import ZMQStream
35 from zmq.eventloop.zmqstream import ZMQStream
36
36
37 # Local imports
37 # Local imports
38 from IPython.core import pylabtools
39 from IPython.config.configurable import Configurable
38 from IPython.config.configurable import Configurable
40 from IPython.config.application import boolean_flag, catch_config_error
39 from IPython.config.application import boolean_flag, catch_config_error
41 from IPython.core.application import ProfileDir
40 from IPython.core.application import ProfileDir
42 from IPython.core.error import StdinNotImplementedError
41 from IPython.core.error import StdinNotImplementedError
43 from IPython.core.shellapp import (
42 from IPython.core.shellapp import (
44 InteractiveShellApp, shell_flags, shell_aliases
43 InteractiveShellApp, shell_flags, shell_aliases
45 )
44 )
46 from IPython.utils import io
45 from IPython.utils import io
47 from IPython.utils import py3compat
46 from IPython.utils import py3compat
48 from IPython.utils.frame import extract_module_locals
47 from IPython.utils.frame import extract_module_locals
49 from IPython.utils.jsonutil import json_clean
48 from IPython.utils.jsonutil import json_clean
50 from IPython.utils.traitlets import (
49 from IPython.utils.traitlets import (
51 Any, Instance, Float, Dict, CaselessStrEnum, List, Set, Integer, Unicode
50 Any, Instance, Float, Dict, CaselessStrEnum, List, Set, Integer, Unicode
52 )
51 )
53
52
54 from entry_point import base_launch_kernel
53 from entry_point import base_launch_kernel
55 from kernelapp import KernelApp, kernel_flags, kernel_aliases
54 from kernelapp import KernelApp, kernel_flags, kernel_aliases
56 from serialize import serialize_object, unpack_apply_message
55 from serialize import serialize_object, unpack_apply_message
57 from session import Session, Message
56 from session import Session, Message
58 from zmqshell import ZMQInteractiveShell
57 from zmqshell import ZMQInteractiveShell
59
58
60
59
61 #-----------------------------------------------------------------------------
60 #-----------------------------------------------------------------------------
62 # Main kernel class
61 # Main kernel class
63 #-----------------------------------------------------------------------------
62 #-----------------------------------------------------------------------------
64
63
65 class Kernel(Configurable):
64 class Kernel(Configurable):
66
65
67 #---------------------------------------------------------------------------
66 #---------------------------------------------------------------------------
68 # Kernel interface
67 # Kernel interface
69 #---------------------------------------------------------------------------
68 #---------------------------------------------------------------------------
70
69
71 # attribute to override with a GUI
70 # attribute to override with a GUI
72 eventloop = Any(None)
71 eventloop = Any(None)
73 def _eventloop_changed(self, name, old, new):
72 def _eventloop_changed(self, name, old, new):
74 """schedule call to eventloop from IOLoop"""
73 """schedule call to eventloop from IOLoop"""
75 loop = ioloop.IOLoop.instance()
74 loop = ioloop.IOLoop.instance()
76 loop.add_timeout(time.time()+0.1, self.enter_eventloop)
75 loop.add_timeout(time.time()+0.1, self.enter_eventloop)
77
76
78 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
77 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
79 session = Instance(Session)
78 session = Instance(Session)
80 profile_dir = Instance('IPython.core.profiledir.ProfileDir')
79 profile_dir = Instance('IPython.core.profiledir.ProfileDir')
81 shell_streams = List()
80 shell_streams = List()
82 control_stream = Instance(ZMQStream)
81 control_stream = Instance(ZMQStream)
83 iopub_socket = Instance(zmq.Socket)
82 iopub_socket = Instance(zmq.Socket)
84 stdin_socket = Instance(zmq.Socket)
83 stdin_socket = Instance(zmq.Socket)
85 log = Instance(logging.Logger)
84 log = Instance(logging.Logger)
86
85
87 user_module = Any()
86 user_module = Any()
88 def _user_module_changed(self, name, old, new):
87 def _user_module_changed(self, name, old, new):
89 if self.shell is not None:
88 if self.shell is not None:
90 self.shell.user_module = new
89 self.shell.user_module = new
91
90
92 user_ns = Dict(default_value=None)
91 user_ns = Dict(default_value=None)
93 def _user_ns_changed(self, name, old, new):
92 def _user_ns_changed(self, name, old, new):
94 if self.shell is not None:
93 if self.shell is not None:
95 self.shell.user_ns = new
94 self.shell.user_ns = new
96 self.shell.init_user_ns()
95 self.shell.init_user_ns()
97
96
98 # identities:
97 # identities:
99 int_id = Integer(-1)
98 int_id = Integer(-1)
100 ident = Unicode()
99 ident = Unicode()
101
100
102 def _ident_default(self):
101 def _ident_default(self):
103 return unicode(uuid.uuid4())
102 return unicode(uuid.uuid4())
104
103
105
104
106 # Private interface
105 # Private interface
107
106
108 # Time to sleep after flushing the stdout/err buffers in each execute
107 # Time to sleep after flushing the stdout/err buffers in each execute
109 # cycle. While this introduces a hard limit on the minimal latency of the
108 # cycle. While this introduces a hard limit on the minimal latency of the
110 # execute cycle, it helps prevent output synchronization problems for
109 # execute cycle, it helps prevent output synchronization problems for
111 # clients.
110 # clients.
112 # Units are in seconds. The minimum zmq latency on local host is probably
111 # Units are in seconds. The minimum zmq latency on local host is probably
113 # ~150 microseconds, set this to 500us for now. We may need to increase it
112 # ~150 microseconds, set this to 500us for now. We may need to increase it
114 # a little if it's not enough after more interactive testing.
113 # a little if it's not enough after more interactive testing.
115 _execute_sleep = Float(0.0005, config=True)
114 _execute_sleep = Float(0.0005, config=True)
116
115
117 # Frequency of the kernel's event loop.
116 # Frequency of the kernel's event loop.
118 # Units are in seconds, kernel subclasses for GUI toolkits may need to
117 # Units are in seconds, kernel subclasses for GUI toolkits may need to
119 # adapt to milliseconds.
118 # adapt to milliseconds.
120 _poll_interval = Float(0.05, config=True)
119 _poll_interval = Float(0.05, config=True)
121
120
122 # If the shutdown was requested over the network, we leave here the
121 # If the shutdown was requested over the network, we leave here the
123 # necessary reply message so it can be sent by our registered atexit
122 # necessary reply message so it can be sent by our registered atexit
124 # handler. This ensures that the reply is only sent to clients truly at
123 # handler. This ensures that the reply is only sent to clients truly at
125 # the end of our shutdown process (which happens after the underlying
124 # the end of our shutdown process (which happens after the underlying
126 # IPython shell's own shutdown).
125 # IPython shell's own shutdown).
127 _shutdown_message = None
126 _shutdown_message = None
128
127
129 # This is a dict of port number that the kernel is listening on. It is set
128 # This is a dict of port number that the kernel is listening on. It is set
130 # by record_ports and used by connect_request.
129 # by record_ports and used by connect_request.
131 _recorded_ports = Dict()
130 _recorded_ports = Dict()
132
131
133 # set of aborted msg_ids
132 # set of aborted msg_ids
134 aborted = Set()
133 aborted = Set()
135
134
136
135
137 def __init__(self, **kwargs):
136 def __init__(self, **kwargs):
138 super(Kernel, self).__init__(**kwargs)
137 super(Kernel, self).__init__(**kwargs)
139
138
140 # Initialize the InteractiveShell subclass
139 # Initialize the InteractiveShell subclass
141 self.shell = ZMQInteractiveShell.instance(config=self.config,
140 self.shell = ZMQInteractiveShell.instance(config=self.config,
142 profile_dir = self.profile_dir,
141 profile_dir = self.profile_dir,
143 user_module = self.user_module,
142 user_module = self.user_module,
144 user_ns = self.user_ns,
143 user_ns = self.user_ns,
145 )
144 )
146 self.shell.displayhook.session = self.session
145 self.shell.displayhook.session = self.session
147 self.shell.displayhook.pub_socket = self.iopub_socket
146 self.shell.displayhook.pub_socket = self.iopub_socket
148 self.shell.displayhook.topic = self._topic('pyout')
147 self.shell.displayhook.topic = self._topic('pyout')
149 self.shell.display_pub.session = self.session
148 self.shell.display_pub.session = self.session
150 self.shell.display_pub.pub_socket = self.iopub_socket
149 self.shell.display_pub.pub_socket = self.iopub_socket
151
150
152 # TMP - hack while developing
151 # TMP - hack while developing
153 self.shell._reply_content = None
152 self.shell._reply_content = None
154
153
155 # Build dict of handlers for message types
154 # Build dict of handlers for message types
156 msg_types = [ 'execute_request', 'complete_request',
155 msg_types = [ 'execute_request', 'complete_request',
157 'object_info_request', 'history_request',
156 'object_info_request', 'history_request',
158 'connect_request', 'shutdown_request',
157 'connect_request', 'shutdown_request',
159 'apply_request',
158 'apply_request',
160 ]
159 ]
161 self.shell_handlers = {}
160 self.shell_handlers = {}
162 for msg_type in msg_types:
161 for msg_type in msg_types:
163 self.shell_handlers[msg_type] = getattr(self, msg_type)
162 self.shell_handlers[msg_type] = getattr(self, msg_type)
164
163
165 control_msg_types = msg_types + [ 'clear_request', 'abort_request' ]
164 control_msg_types = msg_types + [ 'clear_request', 'abort_request' ]
166 self.control_handlers = {}
165 self.control_handlers = {}
167 for msg_type in control_msg_types:
166 for msg_type in control_msg_types:
168 self.control_handlers[msg_type] = getattr(self, msg_type)
167 self.control_handlers[msg_type] = getattr(self, msg_type)
169
168
170 def dispatch_control(self, msg):
169 def dispatch_control(self, msg):
171 """dispatch control requests"""
170 """dispatch control requests"""
172 idents,msg = self.session.feed_identities(msg, copy=False)
171 idents,msg = self.session.feed_identities(msg, copy=False)
173 try:
172 try:
174 msg = self.session.unserialize(msg, content=True, copy=False)
173 msg = self.session.unserialize(msg, content=True, copy=False)
175 except:
174 except:
176 self.log.error("Invalid Control Message", exc_info=True)
175 self.log.error("Invalid Control Message", exc_info=True)
177 return
176 return
178
177
179 self.log.debug("Control received: %s", msg)
178 self.log.debug("Control received: %s", msg)
180
179
181 header = msg['header']
180 header = msg['header']
182 msg_id = header['msg_id']
181 msg_id = header['msg_id']
183 msg_type = header['msg_type']
182 msg_type = header['msg_type']
184
183
185 handler = self.control_handlers.get(msg_type, None)
184 handler = self.control_handlers.get(msg_type, None)
186 if handler is None:
185 if handler is None:
187 self.log.error("UNKNOWN CONTROL MESSAGE TYPE: %r", msg_type)
186 self.log.error("UNKNOWN CONTROL MESSAGE TYPE: %r", msg_type)
188 else:
187 else:
189 try:
188 try:
190 handler(self.control_stream, idents, msg)
189 handler(self.control_stream, idents, msg)
191 except Exception:
190 except Exception:
192 self.log.error("Exception in control handler:", exc_info=True)
191 self.log.error("Exception in control handler:", exc_info=True)
193
192
194 def dispatch_shell(self, stream, msg):
193 def dispatch_shell(self, stream, msg):
195 """dispatch shell requests"""
194 """dispatch shell requests"""
196 # flush control requests first
195 # flush control requests first
197 if self.control_stream:
196 if self.control_stream:
198 self.control_stream.flush()
197 self.control_stream.flush()
199
198
200 idents,msg = self.session.feed_identities(msg, copy=False)
199 idents,msg = self.session.feed_identities(msg, copy=False)
201 try:
200 try:
202 msg = self.session.unserialize(msg, content=True, copy=False)
201 msg = self.session.unserialize(msg, content=True, copy=False)
203 except:
202 except:
204 self.log.error("Invalid Message", exc_info=True)
203 self.log.error("Invalid Message", exc_info=True)
205 return
204 return
206
205
207 header = msg['header']
206 header = msg['header']
208 msg_id = header['msg_id']
207 msg_id = header['msg_id']
209 msg_type = msg['header']['msg_type']
208 msg_type = msg['header']['msg_type']
210
209
211 # Print some info about this message and leave a '--->' marker, so it's
210 # Print some info about this message and leave a '--->' marker, so it's
212 # easier to trace visually the message chain when debugging. Each
211 # easier to trace visually the message chain when debugging. Each
213 # handler prints its message at the end.
212 # handler prints its message at the end.
214 self.log.debug('\n*** MESSAGE TYPE:%s***', msg_type)
213 self.log.debug('\n*** MESSAGE TYPE:%s***', msg_type)
215 self.log.debug(' Content: %s\n --->\n ', msg['content'])
214 self.log.debug(' Content: %s\n --->\n ', msg['content'])
216
215
217 if msg_id in self.aborted:
216 if msg_id in self.aborted:
218 self.aborted.remove(msg_id)
217 self.aborted.remove(msg_id)
219 # is it safe to assume a msg_id will not be resubmitted?
218 # is it safe to assume a msg_id will not be resubmitted?
220 reply_type = msg_type.split('_')[0] + '_reply'
219 reply_type = msg_type.split('_')[0] + '_reply'
221 status = {'status' : 'aborted'}
220 status = {'status' : 'aborted'}
222 sub = {'engine' : self.ident}
221 sub = {'engine' : self.ident}
223 sub.update(status)
222 sub.update(status)
224 reply_msg = self.session.send(stream, reply_type, subheader=sub,
223 reply_msg = self.session.send(stream, reply_type, subheader=sub,
225 content=status, parent=msg, ident=idents)
224 content=status, parent=msg, ident=idents)
226 return
225 return
227
226
228 handler = self.shell_handlers.get(msg_type, None)
227 handler = self.shell_handlers.get(msg_type, None)
229 if handler is None:
228 if handler is None:
230 self.log.error("UNKNOWN MESSAGE TYPE: %r", msg_type)
229 self.log.error("UNKNOWN MESSAGE TYPE: %r", msg_type)
231 else:
230 else:
232 # ensure default_int_handler during handler call
231 # ensure default_int_handler during handler call
233 sig = signal(SIGINT, default_int_handler)
232 sig = signal(SIGINT, default_int_handler)
234 try:
233 try:
235 handler(stream, idents, msg)
234 handler(stream, idents, msg)
236 except Exception:
235 except Exception:
237 self.log.error("Exception in message handler:", exc_info=True)
236 self.log.error("Exception in message handler:", exc_info=True)
238 finally:
237 finally:
239 signal(SIGINT, sig)
238 signal(SIGINT, sig)
240
239
241 def enter_eventloop(self):
240 def enter_eventloop(self):
242 """enter eventloop"""
241 """enter eventloop"""
243 self.log.info("entering eventloop")
242 self.log.info("entering eventloop")
244 # restore default_int_handler
243 # restore default_int_handler
245 signal(SIGINT, default_int_handler)
244 signal(SIGINT, default_int_handler)
246 while self.eventloop is not None:
245 while self.eventloop is not None:
247 try:
246 try:
248 self.eventloop(self)
247 self.eventloop(self)
249 except KeyboardInterrupt:
248 except KeyboardInterrupt:
250 # Ctrl-C shouldn't crash the kernel
249 # Ctrl-C shouldn't crash the kernel
251 self.log.error("KeyboardInterrupt caught in kernel")
250 self.log.error("KeyboardInterrupt caught in kernel")
252 continue
251 continue
253 else:
252 else:
254 # eventloop exited cleanly, this means we should stop (right?)
253 # eventloop exited cleanly, this means we should stop (right?)
255 self.eventloop = None
254 self.eventloop = None
256 break
255 break
257 self.log.info("exiting eventloop")
256 self.log.info("exiting eventloop")
258 # if eventloop exits, IOLoop should stop
257 # if eventloop exits, IOLoop should stop
259 ioloop.IOLoop.instance().stop()
258 ioloop.IOLoop.instance().stop()
260
259
261 def start(self):
260 def start(self):
262 """register dispatchers for streams"""
261 """register dispatchers for streams"""
263 self.shell.exit_now = False
262 self.shell.exit_now = False
264 if self.control_stream:
263 if self.control_stream:
265 self.control_stream.on_recv(self.dispatch_control, copy=False)
264 self.control_stream.on_recv(self.dispatch_control, copy=False)
266
265
267 def make_dispatcher(stream):
266 def make_dispatcher(stream):
268 def dispatcher(msg):
267 def dispatcher(msg):
269 return self.dispatch_shell(stream, msg)
268 return self.dispatch_shell(stream, msg)
270 return dispatcher
269 return dispatcher
271
270
272 for s in self.shell_streams:
271 for s in self.shell_streams:
273 s.on_recv(make_dispatcher(s), copy=False)
272 s.on_recv(make_dispatcher(s), copy=False)
274
273
275 def do_one_iteration(self):
274 def do_one_iteration(self):
276 """step eventloop just once"""
275 """step eventloop just once"""
277 if self.control_stream:
276 if self.control_stream:
278 self.control_stream.flush()
277 self.control_stream.flush()
279 for stream in self.shell_streams:
278 for stream in self.shell_streams:
280 # handle at most one request per iteration
279 # handle at most one request per iteration
281 stream.flush(zmq.POLLIN, 1)
280 stream.flush(zmq.POLLIN, 1)
282 stream.flush(zmq.POLLOUT)
281 stream.flush(zmq.POLLOUT)
283
282
284
283
285 def record_ports(self, ports):
284 def record_ports(self, ports):
286 """Record the ports that this kernel is using.
285 """Record the ports that this kernel is using.
287
286
288 The creator of the Kernel instance must call this methods if they
287 The creator of the Kernel instance must call this methods if they
289 want the :meth:`connect_request` method to return the port numbers.
288 want the :meth:`connect_request` method to return the port numbers.
290 """
289 """
291 self._recorded_ports = ports
290 self._recorded_ports = ports
292
291
293 #---------------------------------------------------------------------------
292 #---------------------------------------------------------------------------
294 # Kernel request handlers
293 # Kernel request handlers
295 #---------------------------------------------------------------------------
294 #---------------------------------------------------------------------------
296
295
297 def _make_subheader(self):
296 def _make_subheader(self):
298 """init subheader dict, for execute/apply_reply"""
297 """init subheader dict, for execute/apply_reply"""
299 return {
298 return {
300 'dependencies_met' : True,
299 'dependencies_met' : True,
301 'engine' : self.ident,
300 'engine' : self.ident,
302 'started': datetime.now(),
301 'started': datetime.now(),
303 }
302 }
304
303
305 def _publish_pyin(self, code, parent, execution_count):
304 def _publish_pyin(self, code, parent, execution_count):
306 """Publish the code request on the pyin stream."""
305 """Publish the code request on the pyin stream."""
307
306
308 self.session.send(self.iopub_socket, u'pyin',
307 self.session.send(self.iopub_socket, u'pyin',
309 {u'code':code, u'execution_count': execution_count},
308 {u'code':code, u'execution_count': execution_count},
310 parent=parent, ident=self._topic('pyin')
309 parent=parent, ident=self._topic('pyin')
311 )
310 )
312
311
313 def execute_request(self, stream, ident, parent):
312 def execute_request(self, stream, ident, parent):
314
313
315 self.session.send(self.iopub_socket,
314 self.session.send(self.iopub_socket,
316 u'status',
315 u'status',
317 {u'execution_state':u'busy'},
316 {u'execution_state':u'busy'},
318 parent=parent,
317 parent=parent,
319 ident=self._topic('status'),
318 ident=self._topic('status'),
320 )
319 )
321
320
322 try:
321 try:
323 content = parent[u'content']
322 content = parent[u'content']
324 code = content[u'code']
323 code = content[u'code']
325 silent = content[u'silent']
324 silent = content[u'silent']
326 except:
325 except:
327 self.log.error("Got bad msg: ")
326 self.log.error("Got bad msg: ")
328 self.log.error("%s", parent)
327 self.log.error("%s", parent)
329 return
328 return
330
329
331 sub = self._make_subheader()
330 sub = self._make_subheader()
332
331
333 shell = self.shell # we'll need this a lot here
332 shell = self.shell # we'll need this a lot here
334
333
335 # Replace raw_input. Note that is not sufficient to replace
334 # Replace raw_input. Note that is not sufficient to replace
336 # raw_input in the user namespace.
335 # raw_input in the user namespace.
337 if content.get('allow_stdin', False):
336 if content.get('allow_stdin', False):
338 raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
337 raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
339 else:
338 else:
340 raw_input = lambda prompt='' : self._no_raw_input()
339 raw_input = lambda prompt='' : self._no_raw_input()
341
340
342 if py3compat.PY3:
341 if py3compat.PY3:
343 __builtin__.input = raw_input
342 __builtin__.input = raw_input
344 else:
343 else:
345 __builtin__.raw_input = raw_input
344 __builtin__.raw_input = raw_input
346
345
347 # Set the parent message of the display hook and out streams.
346 # Set the parent message of the display hook and out streams.
348 shell.displayhook.set_parent(parent)
347 shell.displayhook.set_parent(parent)
349 shell.display_pub.set_parent(parent)
348 shell.display_pub.set_parent(parent)
350 sys.stdout.set_parent(parent)
349 sys.stdout.set_parent(parent)
351 sys.stderr.set_parent(parent)
350 sys.stderr.set_parent(parent)
352
351
353 # Re-broadcast our input for the benefit of listening clients, and
352 # Re-broadcast our input for the benefit of listening clients, and
354 # start computing output
353 # start computing output
355 if not silent:
354 if not silent:
356 self._publish_pyin(code, parent, shell.execution_count)
355 self._publish_pyin(code, parent, shell.execution_count)
357
356
358 reply_content = {}
357 reply_content = {}
359 try:
358 try:
360 # FIXME: the shell calls the exception handler itself.
359 # FIXME: the shell calls the exception handler itself.
361 shell.run_cell(code, store_history=not silent, silent=silent)
360 shell.run_cell(code, store_history=not silent, silent=silent)
362 except:
361 except:
363 status = u'error'
362 status = u'error'
364 # FIXME: this code right now isn't being used yet by default,
363 # FIXME: this code right now isn't being used yet by default,
365 # because the run_cell() call above directly fires off exception
364 # because the run_cell() call above directly fires off exception
366 # reporting. This code, therefore, is only active in the scenario
365 # reporting. This code, therefore, is only active in the scenario
367 # where runlines itself has an unhandled exception. We need to
366 # where runlines itself has an unhandled exception. We need to
368 # uniformize this, for all exception construction to come from a
367 # uniformize this, for all exception construction to come from a
369 # single location in the codbase.
368 # single location in the codbase.
370 etype, evalue, tb = sys.exc_info()
369 etype, evalue, tb = sys.exc_info()
371 tb_list = traceback.format_exception(etype, evalue, tb)
370 tb_list = traceback.format_exception(etype, evalue, tb)
372 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
371 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
373 else:
372 else:
374 status = u'ok'
373 status = u'ok'
375
374
376 reply_content[u'status'] = status
375 reply_content[u'status'] = status
377
376
378 # Return the execution counter so clients can display prompts
377 # Return the execution counter so clients can display prompts
379 reply_content['execution_count'] = shell.execution_count - 1
378 reply_content['execution_count'] = shell.execution_count - 1
380
379
381 # FIXME - fish exception info out of shell, possibly left there by
380 # FIXME - fish exception info out of shell, possibly left there by
382 # runlines. We'll need to clean up this logic later.
381 # runlines. We'll need to clean up this logic later.
383 if shell._reply_content is not None:
382 if shell._reply_content is not None:
384 reply_content.update(shell._reply_content)
383 reply_content.update(shell._reply_content)
385 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='execute')
384 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='execute')
386 reply_content['engine_info'] = e_info
385 reply_content['engine_info'] = e_info
387 # reset after use
386 # reset after use
388 shell._reply_content = None
387 shell._reply_content = None
389
388
390 # At this point, we can tell whether the main code execution succeeded
389 # At this point, we can tell whether the main code execution succeeded
391 # or not. If it did, we proceed to evaluate user_variables/expressions
390 # or not. If it did, we proceed to evaluate user_variables/expressions
392 if reply_content['status'] == 'ok':
391 if reply_content['status'] == 'ok':
393 reply_content[u'user_variables'] = \
392 reply_content[u'user_variables'] = \
394 shell.user_variables(content.get(u'user_variables', []))
393 shell.user_variables(content.get(u'user_variables', []))
395 reply_content[u'user_expressions'] = \
394 reply_content[u'user_expressions'] = \
396 shell.user_expressions(content.get(u'user_expressions', {}))
395 shell.user_expressions(content.get(u'user_expressions', {}))
397 else:
396 else:
398 # If there was an error, don't even try to compute variables or
397 # If there was an error, don't even try to compute variables or
399 # expressions
398 # expressions
400 reply_content[u'user_variables'] = {}
399 reply_content[u'user_variables'] = {}
401 reply_content[u'user_expressions'] = {}
400 reply_content[u'user_expressions'] = {}
402
401
403 # Payloads should be retrieved regardless of outcome, so we can both
402 # Payloads should be retrieved regardless of outcome, so we can both
404 # recover partial output (that could have been generated early in a
403 # recover partial output (that could have been generated early in a
405 # block, before an error) and clear the payload system always.
404 # block, before an error) and clear the payload system always.
406 reply_content[u'payload'] = shell.payload_manager.read_payload()
405 reply_content[u'payload'] = shell.payload_manager.read_payload()
407 # Be agressive about clearing the payload because we don't want
406 # Be agressive about clearing the payload because we don't want
408 # it to sit in memory until the next execute_request comes in.
407 # it to sit in memory until the next execute_request comes in.
409 shell.payload_manager.clear_payload()
408 shell.payload_manager.clear_payload()
410
409
411 # Flush output before sending the reply.
410 # Flush output before sending the reply.
412 sys.stdout.flush()
411 sys.stdout.flush()
413 sys.stderr.flush()
412 sys.stderr.flush()
414 # FIXME: on rare occasions, the flush doesn't seem to make it to the
413 # FIXME: on rare occasions, the flush doesn't seem to make it to the
415 # clients... This seems to mitigate the problem, but we definitely need
414 # clients... This seems to mitigate the problem, but we definitely need
416 # to better understand what's going on.
415 # to better understand what's going on.
417 if self._execute_sleep:
416 if self._execute_sleep:
418 time.sleep(self._execute_sleep)
417 time.sleep(self._execute_sleep)
419
418
420 # Send the reply.
419 # Send the reply.
421 reply_content = json_clean(reply_content)
420 reply_content = json_clean(reply_content)
422
421
423 sub['status'] = reply_content['status']
422 sub['status'] = reply_content['status']
424 if reply_content['status'] == 'error' and \
423 if reply_content['status'] == 'error' and \
425 reply_content['ename'] == 'UnmetDependency':
424 reply_content['ename'] == 'UnmetDependency':
426 sub['dependencies_met'] = False
425 sub['dependencies_met'] = False
427
426
428 reply_msg = self.session.send(stream, u'execute_reply',
427 reply_msg = self.session.send(stream, u'execute_reply',
429 reply_content, parent, subheader=sub,
428 reply_content, parent, subheader=sub,
430 ident=ident)
429 ident=ident)
431
430
432 self.log.debug("%s", reply_msg)
431 self.log.debug("%s", reply_msg)
433
432
434 if not silent and reply_msg['content']['status'] == u'error':
433 if not silent and reply_msg['content']['status'] == u'error':
435 self._abort_queues()
434 self._abort_queues()
436
435
437 self.session.send(self.iopub_socket,
436 self.session.send(self.iopub_socket,
438 u'status',
437 u'status',
439 {u'execution_state':u'idle'},
438 {u'execution_state':u'idle'},
440 parent=parent,
439 parent=parent,
441 ident=self._topic('status'))
440 ident=self._topic('status'))
442
441
443 def complete_request(self, stream, ident, parent):
442 def complete_request(self, stream, ident, parent):
444 txt, matches = self._complete(parent)
443 txt, matches = self._complete(parent)
445 matches = {'matches' : matches,
444 matches = {'matches' : matches,
446 'matched_text' : txt,
445 'matched_text' : txt,
447 'status' : 'ok'}
446 'status' : 'ok'}
448 matches = json_clean(matches)
447 matches = json_clean(matches)
449 completion_msg = self.session.send(stream, 'complete_reply',
448 completion_msg = self.session.send(stream, 'complete_reply',
450 matches, parent, ident)
449 matches, parent, ident)
451 self.log.debug("%s", completion_msg)
450 self.log.debug("%s", completion_msg)
452
451
453 def object_info_request(self, stream, ident, parent):
452 def object_info_request(self, stream, ident, parent):
454 content = parent['content']
453 content = parent['content']
455 object_info = self.shell.object_inspect(content['oname'],
454 object_info = self.shell.object_inspect(content['oname'],
456 detail_level = content.get('detail_level', 0)
455 detail_level = content.get('detail_level', 0)
457 )
456 )
458 # Before we send this object over, we scrub it for JSON usage
457 # Before we send this object over, we scrub it for JSON usage
459 oinfo = json_clean(object_info)
458 oinfo = json_clean(object_info)
460 msg = self.session.send(stream, 'object_info_reply',
459 msg = self.session.send(stream, 'object_info_reply',
461 oinfo, parent, ident)
460 oinfo, parent, ident)
462 self.log.debug("%s", msg)
461 self.log.debug("%s", msg)
463
462
464 def history_request(self, stream, ident, parent):
463 def history_request(self, stream, ident, parent):
465 # We need to pull these out, as passing **kwargs doesn't work with
464 # We need to pull these out, as passing **kwargs doesn't work with
466 # unicode keys before Python 2.6.5.
465 # unicode keys before Python 2.6.5.
467 hist_access_type = parent['content']['hist_access_type']
466 hist_access_type = parent['content']['hist_access_type']
468 raw = parent['content']['raw']
467 raw = parent['content']['raw']
469 output = parent['content']['output']
468 output = parent['content']['output']
470 if hist_access_type == 'tail':
469 if hist_access_type == 'tail':
471 n = parent['content']['n']
470 n = parent['content']['n']
472 hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
471 hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
473 include_latest=True)
472 include_latest=True)
474
473
475 elif hist_access_type == 'range':
474 elif hist_access_type == 'range':
476 session = parent['content']['session']
475 session = parent['content']['session']
477 start = parent['content']['start']
476 start = parent['content']['start']
478 stop = parent['content']['stop']
477 stop = parent['content']['stop']
479 hist = self.shell.history_manager.get_range(session, start, stop,
478 hist = self.shell.history_manager.get_range(session, start, stop,
480 raw=raw, output=output)
479 raw=raw, output=output)
481
480
482 elif hist_access_type == 'search':
481 elif hist_access_type == 'search':
483 pattern = parent['content']['pattern']
482 pattern = parent['content']['pattern']
484 hist = self.shell.history_manager.search(pattern, raw=raw,
483 hist = self.shell.history_manager.search(pattern, raw=raw,
485 output=output)
484 output=output)
486
485
487 else:
486 else:
488 hist = []
487 hist = []
489 hist = list(hist)
488 hist = list(hist)
490 content = {'history' : hist}
489 content = {'history' : hist}
491 content = json_clean(content)
490 content = json_clean(content)
492 msg = self.session.send(stream, 'history_reply',
491 msg = self.session.send(stream, 'history_reply',
493 content, parent, ident)
492 content, parent, ident)
494 self.log.debug("Sending history reply with %i entries", len(hist))
493 self.log.debug("Sending history reply with %i entries", len(hist))
495
494
496 def connect_request(self, stream, ident, parent):
495 def connect_request(self, stream, ident, parent):
497 if self._recorded_ports is not None:
496 if self._recorded_ports is not None:
498 content = self._recorded_ports.copy()
497 content = self._recorded_ports.copy()
499 else:
498 else:
500 content = {}
499 content = {}
501 msg = self.session.send(stream, 'connect_reply',
500 msg = self.session.send(stream, 'connect_reply',
502 content, parent, ident)
501 content, parent, ident)
503 self.log.debug("%s", msg)
502 self.log.debug("%s", msg)
504
503
505 def shutdown_request(self, stream, ident, parent):
504 def shutdown_request(self, stream, ident, parent):
506 self.shell.exit_now = True
505 self.shell.exit_now = True
507 content = dict(status='ok')
506 content = dict(status='ok')
508 content.update(parent['content'])
507 content.update(parent['content'])
509 self.session.send(stream, u'shutdown_reply', content, parent, ident=ident)
508 self.session.send(stream, u'shutdown_reply', content, parent, ident=ident)
510 # same content, but different msg_id for broadcasting on IOPub
509 # same content, but different msg_id for broadcasting on IOPub
511 self._shutdown_message = self.session.msg(u'shutdown_reply',
510 self._shutdown_message = self.session.msg(u'shutdown_reply',
512 content, parent
511 content, parent
513 )
512 )
514
513
515 self._at_shutdown()
514 self._at_shutdown()
516 # call sys.exit after a short delay
515 # call sys.exit after a short delay
517 loop = ioloop.IOLoop.instance()
516 loop = ioloop.IOLoop.instance()
518 loop.add_timeout(time.time()+0.1, loop.stop)
517 loop.add_timeout(time.time()+0.1, loop.stop)
519
518
520 #---------------------------------------------------------------------------
519 #---------------------------------------------------------------------------
521 # Engine methods
520 # Engine methods
522 #---------------------------------------------------------------------------
521 #---------------------------------------------------------------------------
523
522
524 def apply_request(self, stream, ident, parent):
523 def apply_request(self, stream, ident, parent):
525 try:
524 try:
526 content = parent[u'content']
525 content = parent[u'content']
527 bufs = parent[u'buffers']
526 bufs = parent[u'buffers']
528 msg_id = parent['header']['msg_id']
527 msg_id = parent['header']['msg_id']
529 except:
528 except:
530 self.log.error("Got bad msg: %s", parent, exc_info=True)
529 self.log.error("Got bad msg: %s", parent, exc_info=True)
531 return
530 return
532
531
533 # Set the parent message of the display hook and out streams.
532 # Set the parent message of the display hook and out streams.
534 self.shell.displayhook.set_parent(parent)
533 self.shell.displayhook.set_parent(parent)
535 self.shell.display_pub.set_parent(parent)
534 self.shell.display_pub.set_parent(parent)
536 sys.stdout.set_parent(parent)
535 sys.stdout.set_parent(parent)
537 sys.stderr.set_parent(parent)
536 sys.stderr.set_parent(parent)
538
537
539 # pyin_msg = self.session.msg(u'pyin',{u'code':code}, parent=parent)
538 # pyin_msg = self.session.msg(u'pyin',{u'code':code}, parent=parent)
540 # self.iopub_socket.send(pyin_msg)
539 # self.iopub_socket.send(pyin_msg)
541 # self.session.send(self.iopub_socket, u'pyin', {u'code':code},parent=parent)
540 # self.session.send(self.iopub_socket, u'pyin', {u'code':code},parent=parent)
542 sub = self._make_subheader()
541 sub = self._make_subheader()
543 try:
542 try:
544 working = self.shell.user_ns
543 working = self.shell.user_ns
545
544
546 prefix = "_"+str(msg_id).replace("-","")+"_"
545 prefix = "_"+str(msg_id).replace("-","")+"_"
547
546
548 f,args,kwargs = unpack_apply_message(bufs, working, copy=False)
547 f,args,kwargs = unpack_apply_message(bufs, working, copy=False)
549
548
550 fname = getattr(f, '__name__', 'f')
549 fname = getattr(f, '__name__', 'f')
551
550
552 fname = prefix+"f"
551 fname = prefix+"f"
553 argname = prefix+"args"
552 argname = prefix+"args"
554 kwargname = prefix+"kwargs"
553 kwargname = prefix+"kwargs"
555 resultname = prefix+"result"
554 resultname = prefix+"result"
556
555
557 ns = { fname : f, argname : args, kwargname : kwargs , resultname : None }
556 ns = { fname : f, argname : args, kwargname : kwargs , resultname : None }
558 # print ns
557 # print ns
559 working.update(ns)
558 working.update(ns)
560 code = "%s = %s(*%s,**%s)" % (resultname, fname, argname, kwargname)
559 code = "%s = %s(*%s,**%s)" % (resultname, fname, argname, kwargname)
561 try:
560 try:
562 exec code in self.shell.user_global_ns, self.shell.user_ns
561 exec code in self.shell.user_global_ns, self.shell.user_ns
563 result = working.get(resultname)
562 result = working.get(resultname)
564 finally:
563 finally:
565 for key in ns.iterkeys():
564 for key in ns.iterkeys():
566 working.pop(key)
565 working.pop(key)
567
566
568 packed_result,buf = serialize_object(result)
567 packed_result,buf = serialize_object(result)
569 result_buf = [packed_result]+buf
568 result_buf = [packed_result]+buf
570 except:
569 except:
571 exc_content = self._wrap_exception('apply')
570 exc_content = self._wrap_exception('apply')
572 # exc_msg = self.session.msg(u'pyerr', exc_content, parent)
571 # exc_msg = self.session.msg(u'pyerr', exc_content, parent)
573 self.session.send(self.iopub_socket, u'pyerr', exc_content, parent=parent,
572 self.session.send(self.iopub_socket, u'pyerr', exc_content, parent=parent,
574 ident=self._topic('pyerr'))
573 ident=self._topic('pyerr'))
575 reply_content = exc_content
574 reply_content = exc_content
576 result_buf = []
575 result_buf = []
577
576
578 if exc_content['ename'] == 'UnmetDependency':
577 if exc_content['ename'] == 'UnmetDependency':
579 sub['dependencies_met'] = False
578 sub['dependencies_met'] = False
580 else:
579 else:
581 reply_content = {'status' : 'ok'}
580 reply_content = {'status' : 'ok'}
582
581
583 # put 'ok'/'error' status in header, for scheduler introspection:
582 # put 'ok'/'error' status in header, for scheduler introspection:
584 sub['status'] = reply_content['status']
583 sub['status'] = reply_content['status']
585
584
586 # flush i/o
585 # flush i/o
587 sys.stdout.flush()
586 sys.stdout.flush()
588 sys.stderr.flush()
587 sys.stderr.flush()
589
588
590 reply_msg = self.session.send(stream, u'apply_reply', reply_content,
589 reply_msg = self.session.send(stream, u'apply_reply', reply_content,
591 parent=parent, ident=ident,buffers=result_buf, subheader=sub)
590 parent=parent, ident=ident,buffers=result_buf, subheader=sub)
592
591
593 #---------------------------------------------------------------------------
592 #---------------------------------------------------------------------------
594 # Control messages
593 # Control messages
595 #---------------------------------------------------------------------------
594 #---------------------------------------------------------------------------
596
595
597 def abort_request(self, stream, ident, parent):
596 def abort_request(self, stream, ident, parent):
598 """abort a specifig msg by id"""
597 """abort a specifig msg by id"""
599 msg_ids = parent['content'].get('msg_ids', None)
598 msg_ids = parent['content'].get('msg_ids', None)
600 if isinstance(msg_ids, basestring):
599 if isinstance(msg_ids, basestring):
601 msg_ids = [msg_ids]
600 msg_ids = [msg_ids]
602 if not msg_ids:
601 if not msg_ids:
603 self.abort_queues()
602 self.abort_queues()
604 for mid in msg_ids:
603 for mid in msg_ids:
605 self.aborted.add(str(mid))
604 self.aborted.add(str(mid))
606
605
607 content = dict(status='ok')
606 content = dict(status='ok')
608 reply_msg = self.session.send(stream, 'abort_reply', content=content,
607 reply_msg = self.session.send(stream, 'abort_reply', content=content,
609 parent=parent, ident=ident)
608 parent=parent, ident=ident)
610 self.log.debug("%s", reply_msg)
609 self.log.debug("%s", reply_msg)
611
610
612 def clear_request(self, stream, idents, parent):
611 def clear_request(self, stream, idents, parent):
613 """Clear our namespace."""
612 """Clear our namespace."""
614 self.shell.reset(False)
613 self.shell.reset(False)
615 msg = self.session.send(stream, 'clear_reply', ident=idents, parent=parent,
614 msg = self.session.send(stream, 'clear_reply', ident=idents, parent=parent,
616 content = dict(status='ok'))
615 content = dict(status='ok'))
617
616
618
617
619 #---------------------------------------------------------------------------
618 #---------------------------------------------------------------------------
620 # Protected interface
619 # Protected interface
621 #---------------------------------------------------------------------------
620 #---------------------------------------------------------------------------
622
621
623
622
624 def _wrap_exception(self, method=None):
623 def _wrap_exception(self, method=None):
625 # import here, because _wrap_exception is only used in parallel,
624 # import here, because _wrap_exception is only used in parallel,
626 # and parallel has higher min pyzmq version
625 # and parallel has higher min pyzmq version
627 from IPython.parallel.error import wrap_exception
626 from IPython.parallel.error import wrap_exception
628 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method=method)
627 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method=method)
629 content = wrap_exception(e_info)
628 content = wrap_exception(e_info)
630 return content
629 return content
631
630
632 def _topic(self, topic):
631 def _topic(self, topic):
633 """prefixed topic for IOPub messages"""
632 """prefixed topic for IOPub messages"""
634 if self.int_id >= 0:
633 if self.int_id >= 0:
635 base = "engine.%i" % self.int_id
634 base = "engine.%i" % self.int_id
636 else:
635 else:
637 base = "kernel.%s" % self.ident
636 base = "kernel.%s" % self.ident
638
637
639 return py3compat.cast_bytes("%s.%s" % (base, topic))
638 return py3compat.cast_bytes("%s.%s" % (base, topic))
640
639
641 def _abort_queues(self):
640 def _abort_queues(self):
642 for stream in self.shell_streams:
641 for stream in self.shell_streams:
643 if stream:
642 if stream:
644 self._abort_queue(stream)
643 self._abort_queue(stream)
645
644
646 def _abort_queue(self, stream):
645 def _abort_queue(self, stream):
647 poller = zmq.Poller()
646 poller = zmq.Poller()
648 poller.register(stream.socket, zmq.POLLIN)
647 poller.register(stream.socket, zmq.POLLIN)
649 while True:
648 while True:
650 idents,msg = self.session.recv(stream, zmq.NOBLOCK, content=True)
649 idents,msg = self.session.recv(stream, zmq.NOBLOCK, content=True)
651 if msg is None:
650 if msg is None:
652 return
651 return
653
652
654 self.log.info("Aborting:")
653 self.log.info("Aborting:")
655 self.log.info("%s", msg)
654 self.log.info("%s", msg)
656 msg_type = msg['header']['msg_type']
655 msg_type = msg['header']['msg_type']
657 reply_type = msg_type.split('_')[0] + '_reply'
656 reply_type = msg_type.split('_')[0] + '_reply'
658
657
659 status = {'status' : 'aborted'}
658 status = {'status' : 'aborted'}
660 sub = {'engine' : self.ident}
659 sub = {'engine' : self.ident}
661 sub.update(status)
660 sub.update(status)
662 reply_msg = self.session.send(stream, reply_type, subheader=sub,
661 reply_msg = self.session.send(stream, reply_type, subheader=sub,
663 content=status, parent=msg, ident=idents)
662 content=status, parent=msg, ident=idents)
664 self.log.debug("%s", reply_msg)
663 self.log.debug("%s", reply_msg)
665 # We need to wait a bit for requests to come in. This can probably
664 # We need to wait a bit for requests to come in. This can probably
666 # be set shorter for true asynchronous clients.
665 # be set shorter for true asynchronous clients.
667 poller.poll(50)
666 poller.poll(50)
668
667
669
668
670 def _no_raw_input(self):
669 def _no_raw_input(self):
671 """Raise StdinNotImplentedError if active frontend doesn't support
670 """Raise StdinNotImplentedError if active frontend doesn't support
672 stdin."""
671 stdin."""
673 raise StdinNotImplementedError("raw_input was called, but this "
672 raise StdinNotImplementedError("raw_input was called, but this "
674 "frontend does not support stdin.")
673 "frontend does not support stdin.")
675
674
676 def _raw_input(self, prompt, ident, parent):
675 def _raw_input(self, prompt, ident, parent):
677 # Flush output before making the request.
676 # Flush output before making the request.
678 sys.stderr.flush()
677 sys.stderr.flush()
679 sys.stdout.flush()
678 sys.stdout.flush()
680
679
681 # Send the input request.
680 # Send the input request.
682 content = json_clean(dict(prompt=prompt))
681 content = json_clean(dict(prompt=prompt))
683 self.session.send(self.stdin_socket, u'input_request', content, parent,
682 self.session.send(self.stdin_socket, u'input_request', content, parent,
684 ident=ident)
683 ident=ident)
685
684
686 # Await a response.
685 # Await a response.
687 while True:
686 while True:
688 try:
687 try:
689 ident, reply = self.session.recv(self.stdin_socket, 0)
688 ident, reply = self.session.recv(self.stdin_socket, 0)
690 except Exception:
689 except Exception:
691 self.log.warn("Invalid Message:", exc_info=True)
690 self.log.warn("Invalid Message:", exc_info=True)
692 else:
691 else:
693 break
692 break
694 try:
693 try:
695 value = reply['content']['value']
694 value = reply['content']['value']
696 except:
695 except:
697 self.log.error("Got bad raw_input reply: ")
696 self.log.error("Got bad raw_input reply: ")
698 self.log.error("%s", parent)
697 self.log.error("%s", parent)
699 value = ''
698 value = ''
700 if value == '\x04':
699 if value == '\x04':
701 # EOF
700 # EOF
702 raise EOFError
701 raise EOFError
703 return value
702 return value
704
703
705 def _complete(self, msg):
704 def _complete(self, msg):
706 c = msg['content']
705 c = msg['content']
707 try:
706 try:
708 cpos = int(c['cursor_pos'])
707 cpos = int(c['cursor_pos'])
709 except:
708 except:
710 # If we don't get something that we can convert to an integer, at
709 # If we don't get something that we can convert to an integer, at
711 # least attempt the completion guessing the cursor is at the end of
710 # least attempt the completion guessing the cursor is at the end of
712 # the text, if there's any, and otherwise of the line
711 # the text, if there's any, and otherwise of the line
713 cpos = len(c['text'])
712 cpos = len(c['text'])
714 if cpos==0:
713 if cpos==0:
715 cpos = len(c['line'])
714 cpos = len(c['line'])
716 return self.shell.complete(c['text'], c['line'], cpos)
715 return self.shell.complete(c['text'], c['line'], cpos)
717
716
718 def _object_info(self, context):
717 def _object_info(self, context):
719 symbol, leftover = self._symbol_from_context(context)
718 symbol, leftover = self._symbol_from_context(context)
720 if symbol is not None and not leftover:
719 if symbol is not None and not leftover:
721 doc = getattr(symbol, '__doc__', '')
720 doc = getattr(symbol, '__doc__', '')
722 else:
721 else:
723 doc = ''
722 doc = ''
724 object_info = dict(docstring = doc)
723 object_info = dict(docstring = doc)
725 return object_info
724 return object_info
726
725
727 def _symbol_from_context(self, context):
726 def _symbol_from_context(self, context):
728 if not context:
727 if not context:
729 return None, context
728 return None, context
730
729
731 base_symbol_string = context[0]
730 base_symbol_string = context[0]
732 symbol = self.shell.user_ns.get(base_symbol_string, None)
731 symbol = self.shell.user_ns.get(base_symbol_string, None)
733 if symbol is None:
732 if symbol is None:
734 symbol = __builtin__.__dict__.get(base_symbol_string, None)
733 symbol = __builtin__.__dict__.get(base_symbol_string, None)
735 if symbol is None:
734 if symbol is None:
736 return None, context
735 return None, context
737
736
738 context = context[1:]
737 context = context[1:]
739 for i, name in enumerate(context):
738 for i, name in enumerate(context):
740 new_symbol = getattr(symbol, name, None)
739 new_symbol = getattr(symbol, name, None)
741 if new_symbol is None:
740 if new_symbol is None:
742 return symbol, context[i:]
741 return symbol, context[i:]
743 else:
742 else:
744 symbol = new_symbol
743 symbol = new_symbol
745
744
746 return symbol, []
745 return symbol, []
747
746
748 def _at_shutdown(self):
747 def _at_shutdown(self):
749 """Actions taken at shutdown by the kernel, called by python's atexit.
748 """Actions taken at shutdown by the kernel, called by python's atexit.
750 """
749 """
751 # io.rprint("Kernel at_shutdown") # dbg
750 # io.rprint("Kernel at_shutdown") # dbg
752 if self._shutdown_message is not None:
751 if self._shutdown_message is not None:
753 self.session.send(self.iopub_socket, self._shutdown_message, ident=self._topic('shutdown'))
752 self.session.send(self.iopub_socket, self._shutdown_message, ident=self._topic('shutdown'))
754 self.log.debug("%s", self._shutdown_message)
753 self.log.debug("%s", self._shutdown_message)
755 [ s.flush(zmq.POLLOUT) for s in self.shell_streams ]
754 [ s.flush(zmq.POLLOUT) for s in self.shell_streams ]
756
755
757 #-----------------------------------------------------------------------------
756 #-----------------------------------------------------------------------------
758 # Aliases and Flags for the IPKernelApp
757 # Aliases and Flags for the IPKernelApp
759 #-----------------------------------------------------------------------------
758 #-----------------------------------------------------------------------------
760
759
761 flags = dict(kernel_flags)
760 flags = dict(kernel_flags)
762 flags.update(shell_flags)
761 flags.update(shell_flags)
763
762
764 addflag = lambda *args: flags.update(boolean_flag(*args))
763 addflag = lambda *args: flags.update(boolean_flag(*args))
765
764
766 flags['pylab'] = (
765 flags['pylab'] = (
767 {'IPKernelApp' : {'pylab' : 'auto'}},
766 {'IPKernelApp' : {'pylab' : 'auto'}},
768 """Pre-load matplotlib and numpy for interactive use with
767 """Pre-load matplotlib and numpy for interactive use with
769 the default matplotlib backend."""
768 the default matplotlib backend."""
770 )
769 )
771
770
772 aliases = dict(kernel_aliases)
771 aliases = dict(kernel_aliases)
773 aliases.update(shell_aliases)
772 aliases.update(shell_aliases)
774
773
775 # it's possible we don't want short aliases for *all* of these:
776 aliases.update(dict(
777 gui='IPKernelApp.gui',
778 pylab='IPKernelApp.pylab',
779 ))
780
781 #-----------------------------------------------------------------------------
774 #-----------------------------------------------------------------------------
782 # The IPKernelApp class
775 # The IPKernelApp class
783 #-----------------------------------------------------------------------------
776 #-----------------------------------------------------------------------------
784
777
785 class IPKernelApp(KernelApp, InteractiveShellApp):
778 class IPKernelApp(KernelApp, InteractiveShellApp):
786 name = 'ipkernel'
779 name = 'ipkernel'
787
780
788 aliases = Dict(aliases)
781 aliases = Dict(aliases)
789 flags = Dict(flags)
782 flags = Dict(flags)
790 classes = [Kernel, ZMQInteractiveShell, ProfileDir, Session]
783 classes = [Kernel, ZMQInteractiveShell, ProfileDir, Session]
791
784
792 # configurables
793 gui = CaselessStrEnum(('qt', 'wx', 'gtk', 'glut', 'pyglet'), config=True,
794 help="Enable GUI event loop integration ('qt', 'wx', 'gtk', 'glut', 'pyglet')."
795 )
796 pylab = CaselessStrEnum(['tk', 'qt', 'wx', 'gtk', 'osx', 'inline', 'auto'],
797 config=True,
798 help="""Pre-load matplotlib and numpy for interactive use,
799 selecting a particular matplotlib backend and loop integration.
800 """
801 )
802
803 @catch_config_error
785 @catch_config_error
804 def initialize(self, argv=None):
786 def initialize(self, argv=None):
805 super(IPKernelApp, self).initialize(argv)
787 super(IPKernelApp, self).initialize(argv)
806 self.init_path()
788 self.init_path()
807 self.init_shell()
789 self.init_shell()
808 self.init_gui_pylab()
790 self.init_gui_pylab()
809 self.init_extensions()
791 self.init_extensions()
810 self.init_code()
792 self.init_code()
811
793
812 def init_kernel(self):
794 def init_kernel(self):
813
795
814 shell_stream = ZMQStream(self.shell_socket)
796 shell_stream = ZMQStream(self.shell_socket)
815
797
816 kernel = Kernel(config=self.config, session=self.session,
798 kernel = Kernel(config=self.config, session=self.session,
817 shell_streams=[shell_stream],
799 shell_streams=[shell_stream],
818 iopub_socket=self.iopub_socket,
800 iopub_socket=self.iopub_socket,
819 stdin_socket=self.stdin_socket,
801 stdin_socket=self.stdin_socket,
820 log=self.log,
802 log=self.log,
821 profile_dir=self.profile_dir,
803 profile_dir=self.profile_dir,
822 )
804 )
823 self.kernel = kernel
805 self.kernel = kernel
824 kernel.record_ports(self.ports)
806 kernel.record_ports(self.ports)
825 shell = kernel.shell
807 shell = kernel.shell
826
808
827 def init_gui_pylab(self):
809 def init_gui_pylab(self):
828 """Enable GUI event loop integration, taking pylab into account."""
810 """Enable GUI event loop integration, taking pylab into account."""
829 if self.gui or self.pylab:
811
830 shell = self.shell
812 # Provide a wrapper for :meth:`InteractiveShellApp.init_gui_pylab`
831 try:
813 # to ensure that any exception is printed straight to stderr.
832 if self.pylab:
814 # Normally _showtraceback associates the reply with an execution,
833 gui, backend = pylabtools.find_gui_and_backend(self.pylab)
834 shell.enable_pylab(gui, import_all=self.pylab_import_all)
835 else:
836 shell.enable_gui(self.gui)
837 except Exception:
838 self.log.error("GUI event loop or pylab initialization failed",
839 exc_info=True)
840 # print exception straight to stdout, because normally
841 # _showtraceback associates the reply with an execution,
842 # which means frontends will never draw it, as this exception
815 # which means frontends will never draw it, as this exception
843 # is not associated with any execute request.
816 # is not associated with any execute request.
844
817
845 # replace pyerr-sending traceback with stdout
818 shell = self.shell
846 _showtraceback = shell._showtraceback
819 _showtraceback = shell._showtraceback
820 try:
821 # replace pyerr-sending traceback with stderr
847 def print_tb(etype, evalue, stb):
822 def print_tb(etype, evalue, stb):
848 print ("GUI event loop or pylab initialization failed",
823 print ("GUI event loop or pylab initialization failed",
849 file=io.stderr)
824 file=io.stderr)
850 print (shell.InteractiveTB.stb2text(stb), file=io.stdout)
825 print (shell.InteractiveTB.stb2text(stb), file=io.stderr)
851 shell._showtraceback = print_tb
826 shell._showtraceback = print_tb
852
827 InteractiveShellApp.init_gui_pylab(self)
853 # send the traceback over stdout
828 finally:
854 shell.showtraceback(tb_offset=0)
855
856 # restore proper _showtraceback method
857 shell._showtraceback = _showtraceback
829 shell._showtraceback = _showtraceback
858
830
859
860 def init_shell(self):
831 def init_shell(self):
861 self.shell = self.kernel.shell
832 self.shell = self.kernel.shell
862 self.shell.configurables.append(self)
833 self.shell.configurables.append(self)
863
834
864
835
865 #-----------------------------------------------------------------------------
836 #-----------------------------------------------------------------------------
866 # Kernel main and launch functions
837 # Kernel main and launch functions
867 #-----------------------------------------------------------------------------
838 #-----------------------------------------------------------------------------
868
839
869 def launch_kernel(*args, **kwargs):
840 def launch_kernel(*args, **kwargs):
870 """Launches a localhost IPython kernel, binding to the specified ports.
841 """Launches a localhost IPython kernel, binding to the specified ports.
871
842
872 This function simply calls entry_point.base_launch_kernel with the right
843 This function simply calls entry_point.base_launch_kernel with the right
873 first command to start an ipkernel. See base_launch_kernel for arguments.
844 first command to start an ipkernel. See base_launch_kernel for arguments.
874
845
875 Returns
846 Returns
876 -------
847 -------
877 A tuple of form:
848 A tuple of form:
878 (kernel_process, shell_port, iopub_port, stdin_port, hb_port)
849 (kernel_process, shell_port, iopub_port, stdin_port, hb_port)
879 where kernel_process is a Popen object and the ports are integers.
850 where kernel_process is a Popen object and the ports are integers.
880 """
851 """
881 return base_launch_kernel('from IPython.zmq.ipkernel import main; main()',
852 return base_launch_kernel('from IPython.zmq.ipkernel import main; main()',
882 *args, **kwargs)
853 *args, **kwargs)
883
854
884
855
885 def embed_kernel(module=None, local_ns=None, **kwargs):
856 def embed_kernel(module=None, local_ns=None, **kwargs):
886 """Embed and start an IPython kernel in a given scope.
857 """Embed and start an IPython kernel in a given scope.
887
858
888 Parameters
859 Parameters
889 ----------
860 ----------
890 module : ModuleType, optional
861 module : ModuleType, optional
891 The module to load into IPython globals (default: caller)
862 The module to load into IPython globals (default: caller)
892 local_ns : dict, optional
863 local_ns : dict, optional
893 The namespace to load into IPython user namespace (default: caller)
864 The namespace to load into IPython user namespace (default: caller)
894
865
895 kwargs : various, optional
866 kwargs : various, optional
896 Further keyword args are relayed to the KernelApp constructor,
867 Further keyword args are relayed to the KernelApp constructor,
897 allowing configuration of the Kernel. Will only have an effect
868 allowing configuration of the Kernel. Will only have an effect
898 on the first embed_kernel call for a given process.
869 on the first embed_kernel call for a given process.
899
870
900 """
871 """
901 # get the app if it exists, or set it up if it doesn't
872 # get the app if it exists, or set it up if it doesn't
902 if IPKernelApp.initialized():
873 if IPKernelApp.initialized():
903 app = IPKernelApp.instance()
874 app = IPKernelApp.instance()
904 else:
875 else:
905 app = IPKernelApp.instance(**kwargs)
876 app = IPKernelApp.instance(**kwargs)
906 app.initialize([])
877 app.initialize([])
907 # Undo unnecessary sys module mangling from init_sys_modules.
878 # Undo unnecessary sys module mangling from init_sys_modules.
908 # This would not be necessary if we could prevent it
879 # This would not be necessary if we could prevent it
909 # in the first place by using a different InteractiveShell
880 # in the first place by using a different InteractiveShell
910 # subclass, as in the regular embed case.
881 # subclass, as in the regular embed case.
911 main = app.kernel.shell._orig_sys_modules_main_mod
882 main = app.kernel.shell._orig_sys_modules_main_mod
912 if main is not None:
883 if main is not None:
913 sys.modules[app.kernel.shell._orig_sys_modules_main_name] = main
884 sys.modules[app.kernel.shell._orig_sys_modules_main_name] = main
914
885
915 # load the calling scope if not given
886 # load the calling scope if not given
916 (caller_module, caller_locals) = extract_module_locals(1)
887 (caller_module, caller_locals) = extract_module_locals(1)
917 if module is None:
888 if module is None:
918 module = caller_module
889 module = caller_module
919 if local_ns is None:
890 if local_ns is None:
920 local_ns = caller_locals
891 local_ns = caller_locals
921
892
922 app.kernel.user_module = module
893 app.kernel.user_module = module
923 app.kernel.user_ns = local_ns
894 app.kernel.user_ns = local_ns
924 app.start()
895 app.start()
925
896
926 def main():
897 def main():
927 """Run an IPKernel as an application"""
898 """Run an IPKernel as an application"""
928 app = IPKernelApp.instance()
899 app = IPKernelApp.instance()
929 app.initialize()
900 app.initialize()
930 app.start()
901 app.start()
931
902
932
903
933 if __name__ == '__main__':
904 if __name__ == '__main__':
934 main()
905 main()
General Comments 0
You need to be logged in to leave comments. Login now