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