##// END OF EJS Templates
DEV: Show tracebacks for failed extensions when running without stdout.
Scott Sanderson -
Show More
@@ -1,440 +1,441
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 from __future__ import print_function
25 25
26 26 import glob
27 27 import os
28 28 import sys
29 29
30 30 from IPython.config.application import boolean_flag
31 31 from IPython.config.configurable import Configurable
32 32 from IPython.config.loader import Config
33 33 from IPython.core import pylabtools
34 34 from IPython.utils import py3compat
35 35 from IPython.utils.contexts import preserve_keys
36 36 from IPython.utils.path import filefind
37 37 from IPython.utils.traitlets import (
38 38 Unicode, Instance, List, Bool, CaselessStrEnum
39 39 )
40 40 from IPython.lib.inputhook import guis
41 41
42 42 #-----------------------------------------------------------------------------
43 43 # Aliases and Flags
44 44 #-----------------------------------------------------------------------------
45 45
46 46 gui_keys = tuple(sorted([ key for key in guis if key is not None ]))
47 47
48 48 backend_keys = sorted(pylabtools.backends.keys())
49 49 backend_keys.insert(0, 'auto')
50 50
51 51 shell_flags = {}
52 52
53 53 addflag = lambda *args: shell_flags.update(boolean_flag(*args))
54 54 addflag('autoindent', 'InteractiveShell.autoindent',
55 55 'Turn on autoindenting.', 'Turn off autoindenting.'
56 56 )
57 57 addflag('automagic', 'InteractiveShell.automagic',
58 58 """Turn on the auto calling of magic commands. Type %%magic at the
59 59 IPython prompt for more information.""",
60 60 'Turn off the auto calling of magic commands.'
61 61 )
62 62 addflag('pdb', 'InteractiveShell.pdb',
63 63 "Enable auto calling the pdb debugger after every exception.",
64 64 "Disable auto calling the pdb debugger after every exception."
65 65 )
66 66 # pydb flag doesn't do any config, as core.debugger switches on import,
67 67 # which is before parsing. This just allows the flag to be passed.
68 68 shell_flags.update(dict(
69 69 pydb = ({},
70 70 """Use the third party 'pydb' package as debugger, instead of pdb.
71 71 Requires that pydb is installed."""
72 72 )
73 73 ))
74 74 addflag('pprint', 'PlainTextFormatter.pprint',
75 75 "Enable auto pretty printing of results.",
76 76 "Disable auto pretty printing of results."
77 77 )
78 78 addflag('color-info', 'InteractiveShell.color_info',
79 79 """IPython can display information about objects via a set of func-
80 80 tions, and optionally can use colors for this, syntax highlighting
81 81 source code and various other elements. However, because this
82 82 information is passed through a pager (like 'less') and many pagers get
83 83 confused with color codes, this option is off by default. You can test
84 84 it and turn it on permanently in your ipython_config.py file if it
85 85 works for you. Test it and turn it on permanently if it works with
86 86 your system. The magic function %%color_info allows you to toggle this
87 87 interactively for testing.""",
88 88 "Disable using colors for info related things."
89 89 )
90 90 addflag('deep-reload', 'InteractiveShell.deep_reload',
91 91 """Enable deep (recursive) reloading by default. IPython can use the
92 92 deep_reload module which reloads changes in modules recursively (it
93 93 replaces the reload() function, so you don't need to change anything to
94 94 use it). deep_reload() forces a full reload of modules whose code may
95 95 have changed, which the default reload() function does not. When
96 96 deep_reload is off, IPython will use the normal reload(), but
97 97 deep_reload will still be available as dreload(). This feature is off
98 98 by default [which means that you have both normal reload() and
99 99 dreload()].""",
100 100 "Disable deep (recursive) reloading by default."
101 101 )
102 102 nosep_config = Config()
103 103 nosep_config.InteractiveShell.separate_in = ''
104 104 nosep_config.InteractiveShell.separate_out = ''
105 105 nosep_config.InteractiveShell.separate_out2 = ''
106 106
107 107 shell_flags['nosep']=(nosep_config, "Eliminate all spacing between prompts.")
108 108 shell_flags['pylab'] = (
109 109 {'InteractiveShellApp' : {'pylab' : 'auto'}},
110 110 """Pre-load matplotlib and numpy for interactive use with
111 111 the default matplotlib backend."""
112 112 )
113 113 shell_flags['matplotlib'] = (
114 114 {'InteractiveShellApp' : {'matplotlib' : 'auto'}},
115 115 """Configure matplotlib for interactive use with
116 116 the default matplotlib backend."""
117 117 )
118 118
119 119 # it's possible we don't want short aliases for *all* of these:
120 120 shell_aliases = dict(
121 121 autocall='InteractiveShell.autocall',
122 122 colors='InteractiveShell.colors',
123 123 logfile='InteractiveShell.logfile',
124 124 logappend='InteractiveShell.logappend',
125 125 c='InteractiveShellApp.code_to_run',
126 126 m='InteractiveShellApp.module_to_run',
127 127 ext='InteractiveShellApp.extra_extension',
128 128 gui='InteractiveShellApp.gui',
129 129 pylab='InteractiveShellApp.pylab',
130 130 matplotlib='InteractiveShellApp.matplotlib',
131 131 )
132 132 shell_aliases['cache-size'] = 'InteractiveShell.cache_size'
133 133
134 134 #-----------------------------------------------------------------------------
135 135 # Main classes and functions
136 136 #-----------------------------------------------------------------------------
137 137
138 138 class InteractiveShellApp(Configurable):
139 139 """A Mixin for applications that start InteractiveShell instances.
140 140
141 141 Provides configurables for loading extensions and executing files
142 142 as part of configuring a Shell environment.
143 143
144 144 The following methods should be called by the :meth:`initialize` method
145 145 of the subclass:
146 146
147 147 - :meth:`init_path`
148 148 - :meth:`init_shell` (to be implemented by the subclass)
149 149 - :meth:`init_gui_pylab`
150 150 - :meth:`init_extensions`
151 151 - :meth:`init_code`
152 152 """
153 153 extensions = List(Unicode, config=True,
154 154 help="A list of dotted module names of IPython extensions to load."
155 155 )
156 156 extra_extension = Unicode('', config=True,
157 157 help="dotted module name of an IPython extension to load."
158 158 )
159 159 def _extra_extension_changed(self, name, old, new):
160 160 if new:
161 161 # add to self.extensions
162 162 self.extensions.append(new)
163 163
164 164 # Extensions that are always loaded (not configurable)
165 165 default_extensions = List(Unicode, [u'storemagic'], config=False)
166 166
167 167 hide_initial_ns = Bool(True, config=True,
168 168 help="""Should variables loaded at startup (by startup files, exec_lines, etc.)
169 169 be hidden from tools like %who?"""
170 170 )
171 171
172 172 exec_files = List(Unicode, config=True,
173 173 help="""List of files to run at IPython startup."""
174 174 )
175 175 exec_PYTHONSTARTUP = Bool(True, config=True,
176 176 help="""Run the file referenced by the PYTHONSTARTUP environment
177 177 variable at IPython startup."""
178 178 )
179 179 file_to_run = Unicode('', config=True,
180 180 help="""A file to be run""")
181 181
182 182 exec_lines = List(Unicode, config=True,
183 183 help="""lines of code to run at IPython startup."""
184 184 )
185 185 code_to_run = Unicode('', config=True,
186 186 help="Execute the given command string."
187 187 )
188 188 module_to_run = Unicode('', config=True,
189 189 help="Run the module as a script."
190 190 )
191 191 gui = CaselessStrEnum(gui_keys, config=True,
192 192 help="Enable GUI event loop integration with any of {0}.".format(gui_keys)
193 193 )
194 194 matplotlib = CaselessStrEnum(backend_keys,
195 195 config=True,
196 196 help="""Configure matplotlib for interactive use with
197 197 the default matplotlib backend."""
198 198 )
199 199 pylab = CaselessStrEnum(backend_keys,
200 200 config=True,
201 201 help="""Pre-load matplotlib and numpy for interactive use,
202 202 selecting a particular matplotlib backend and loop integration.
203 203 """
204 204 )
205 205 pylab_import_all = Bool(True, config=True,
206 206 help="""If true, IPython will populate the user namespace with numpy, pylab, etc.
207 207 and an ``import *`` is done from numpy and pylab, when using pylab mode.
208 208
209 209 When False, pylab mode should not import any names into the user namespace.
210 210 """
211 211 )
212 212 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
213 213
214 214 user_ns = Instance(dict, args=None, allow_none=True)
215 215 def _user_ns_changed(self, name, old, new):
216 216 if self.shell is not None:
217 217 self.shell.user_ns = new
218 218 self.shell.init_user_ns()
219 219
220 220 def init_path(self):
221 221 """Add current working directory, '', to sys.path"""
222 222 if sys.path[0] != '':
223 223 sys.path.insert(0, '')
224 224
225 225 def init_shell(self):
226 226 raise NotImplementedError("Override in subclasses")
227 227
228 228 def init_gui_pylab(self):
229 229 """Enable GUI event loop integration, taking pylab into account."""
230 230 enable = False
231 231 shell = self.shell
232 232 if self.pylab:
233 233 enable = lambda key: shell.enable_pylab(key, import_all=self.pylab_import_all)
234 234 key = self.pylab
235 235 elif self.matplotlib:
236 236 enable = shell.enable_matplotlib
237 237 key = self.matplotlib
238 238 elif self.gui:
239 239 enable = shell.enable_gui
240 240 key = self.gui
241 241
242 242 if not enable:
243 243 return
244 244
245 245 try:
246 246 r = enable(key)
247 247 except ImportError:
248 248 self.log.warn("Eventloop or matplotlib integration failed. Is matplotlib installed?")
249 249 self.shell.showtraceback()
250 250 return
251 251 except Exception:
252 252 self.log.warn("GUI event loop or pylab initialization failed")
253 253 self.shell.showtraceback()
254 254 return
255 255
256 256 if isinstance(r, tuple):
257 257 gui, backend = r[:2]
258 258 self.log.info("Enabling GUI event loop integration, "
259 259 "eventloop=%s, matplotlib=%s", gui, backend)
260 260 if key == "auto":
261 261 print("Using matplotlib backend: %s" % backend)
262 262 else:
263 263 gui = r
264 264 self.log.info("Enabling GUI event loop integration, "
265 265 "eventloop=%s", gui)
266 266
267 267 def init_extensions(self):
268 268 """Load all IPython extensions in IPythonApp.extensions.
269 269
270 270 This uses the :meth:`ExtensionManager.load_extensions` to load all
271 271 the extensions listed in ``self.extensions``.
272 272 """
273 273 try:
274 274 self.log.debug("Loading IPython extensions...")
275 275 extensions = self.default_extensions + self.extensions
276 276 for ext in extensions:
277 277 try:
278 278 self.log.info("Loading IPython extension: %s" % ext)
279 279 self.shell.extension_manager.load_extension(ext)
280 280 except:
281 self.log.warn("Error in loading extension: %s" % ext +
282 "\nCheck your config files in %s" % self.profile_dir.location
283 )
284 self.shell.showtraceback()
281 msg = ("Error in loading extension: {ext}\n"
282 "Check your config files in {location}".format(
283 ext=ext,
284 location=self.profile_dir.location
285 ))
286 self.log.warn(msg, exc_info=True)
285 287 except:
286 self.log.warn("Unknown error in loading extensions:")
287 self.shell.showtraceback()
288 self.log.warn("Unknown error in loading extensions:", exc_info=True)
288 289
289 290 def init_code(self):
290 291 """run the pre-flight code, specified via exec_lines"""
291 292 self._run_startup_files()
292 293 self._run_exec_lines()
293 294 self._run_exec_files()
294 295
295 296 # Hide variables defined here from %who etc.
296 297 if self.hide_initial_ns:
297 298 self.shell.user_ns_hidden.update(self.shell.user_ns)
298 299
299 300 # command-line execution (ipython -i script.py, ipython -m module)
300 301 # should *not* be excluded from %whos
301 302 self._run_cmd_line_code()
302 303 self._run_module()
303 304
304 305 # flush output, so itwon't be attached to the first cell
305 306 sys.stdout.flush()
306 307 sys.stderr.flush()
307 308
308 309 def _run_exec_lines(self):
309 310 """Run lines of code in IPythonApp.exec_lines in the user's namespace."""
310 311 if not self.exec_lines:
311 312 return
312 313 try:
313 314 self.log.debug("Running code from IPythonApp.exec_lines...")
314 315 for line in self.exec_lines:
315 316 try:
316 317 self.log.info("Running code in user namespace: %s" %
317 318 line)
318 319 self.shell.run_cell(line, store_history=False)
319 320 except:
320 321 self.log.warn("Error in executing line in user "
321 322 "namespace: %s" % line)
322 323 self.shell.showtraceback()
323 324 except:
324 325 self.log.warn("Unknown error in handling IPythonApp.exec_lines:")
325 326 self.shell.showtraceback()
326 327
327 328 def _exec_file(self, fname, shell_futures=False):
328 329 try:
329 330 full_filename = filefind(fname, [u'.', self.ipython_dir])
330 331 except IOError as e:
331 332 self.log.warn("File not found: %r"%fname)
332 333 return
333 334 # Make sure that the running script gets a proper sys.argv as if it
334 335 # were run from a system shell.
335 336 save_argv = sys.argv
336 337 sys.argv = [full_filename] + self.extra_args[1:]
337 338 # protect sys.argv from potential unicode strings on Python 2:
338 339 if not py3compat.PY3:
339 340 sys.argv = [ py3compat.cast_bytes(a) for a in sys.argv ]
340 341 try:
341 342 if os.path.isfile(full_filename):
342 343 self.log.info("Running file in user namespace: %s" %
343 344 full_filename)
344 345 # Ensure that __file__ is always defined to match Python
345 346 # behavior.
346 347 with preserve_keys(self.shell.user_ns, '__file__'):
347 348 self.shell.user_ns['__file__'] = fname
348 349 if full_filename.endswith('.ipy'):
349 350 self.shell.safe_execfile_ipy(full_filename,
350 351 shell_futures=shell_futures)
351 352 else:
352 353 # default to python, even without extension
353 354 self.shell.safe_execfile(full_filename,
354 355 self.shell.user_ns,
355 356 shell_futures=shell_futures)
356 357 finally:
357 358 sys.argv = save_argv
358 359
359 360 def _run_startup_files(self):
360 361 """Run files from profile startup directory"""
361 362 startup_dir = self.profile_dir.startup_dir
362 363 startup_files = []
363 364
364 365 if self.exec_PYTHONSTARTUP and os.environ.get('PYTHONSTARTUP', False) and \
365 366 not (self.file_to_run or self.code_to_run or self.module_to_run):
366 367 python_startup = os.environ['PYTHONSTARTUP']
367 368 self.log.debug("Running PYTHONSTARTUP file %s...", python_startup)
368 369 try:
369 370 self._exec_file(python_startup)
370 371 except:
371 372 self.log.warn("Unknown error in handling PYTHONSTARTUP file %s:", python_startup)
372 373 self.shell.showtraceback()
373 374 finally:
374 375 # Many PYTHONSTARTUP files set up the readline completions,
375 376 # but this is often at odds with IPython's own completions.
376 377 # Do not allow PYTHONSTARTUP to set up readline.
377 378 if self.shell.has_readline:
378 379 self.shell.set_readline_completer()
379 380
380 381 startup_files += glob.glob(os.path.join(startup_dir, '*.py'))
381 382 startup_files += glob.glob(os.path.join(startup_dir, '*.ipy'))
382 383 if not startup_files:
383 384 return
384 385
385 386 self.log.debug("Running startup files from %s...", startup_dir)
386 387 try:
387 388 for fname in sorted(startup_files):
388 389 self._exec_file(fname)
389 390 except:
390 391 self.log.warn("Unknown error in handling startup files:")
391 392 self.shell.showtraceback()
392 393
393 394 def _run_exec_files(self):
394 395 """Run files from IPythonApp.exec_files"""
395 396 if not self.exec_files:
396 397 return
397 398
398 399 self.log.debug("Running files in IPythonApp.exec_files...")
399 400 try:
400 401 for fname in self.exec_files:
401 402 self._exec_file(fname)
402 403 except:
403 404 self.log.warn("Unknown error in handling IPythonApp.exec_files:")
404 405 self.shell.showtraceback()
405 406
406 407 def _run_cmd_line_code(self):
407 408 """Run code or file specified at the command-line"""
408 409 if self.code_to_run:
409 410 line = self.code_to_run
410 411 try:
411 412 self.log.info("Running code given at command line (c=): %s" %
412 413 line)
413 414 self.shell.run_cell(line, store_history=False)
414 415 except:
415 416 self.log.warn("Error in executing line in user namespace: %s" %
416 417 line)
417 418 self.shell.showtraceback()
418 419
419 420 # Like Python itself, ignore the second if the first of these is present
420 421 elif self.file_to_run:
421 422 fname = self.file_to_run
422 423 try:
423 424 self._exec_file(fname, shell_futures=True)
424 425 except:
425 426 self.log.warn("Error in executing file in user namespace: %s" %
426 427 fname)
427 428 self.shell.showtraceback()
428 429
429 430 def _run_module(self):
430 431 """Run module specified at the command-line."""
431 432 if self.module_to_run:
432 433 # Make sure that the module gets a proper sys.argv as if it were
433 434 # run using `python -m`.
434 435 save_argv = sys.argv
435 436 sys.argv = [sys.executable] + self.extra_args
436 437 try:
437 438 self.shell.safe_run_module(self.module_to_run,
438 439 self.shell.user_ns)
439 440 finally:
440 441 sys.argv = save_argv
General Comments 0
You need to be logged in to leave comments. Login now