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