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