##// END OF EJS Templates
add CWD to sys.path *after* stdlib...
Min RK -
Show More
@@ -1,408 +1,425 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 """Add current working directory, '', to sys.path"""
185 if sys.path[0] != '':
186 sys.path.insert(0, '')
184 """Add current working directory, '', to sys.path
185
186 Unlike Python's default, we insert before the first `site-packages`
187 or `dist-packages` directory,
188 so that it is after the standard library.
189
190 .. versionchanged:: 7.2
191 Try to insert after the standard library, instead of first.
192 """
193 if '' in sys.path:
194 return
195 for idx, path in enumerate(sys.path):
196 parent, last_part = os.path.split(path)
197 if last_part in {'site-packages', 'dist-packages'}:
198 break
199 else:
200 # no site-packages or dist-packages found (?!)
201 # back to original behavior of inserting at the front
202 idx = 0
203 sys.path.insert(idx, '')
187 204
188 205 def init_shell(self):
189 206 raise NotImplementedError("Override in subclasses")
190 207
191 208 def init_gui_pylab(self):
192 209 """Enable GUI event loop integration, taking pylab into account."""
193 210 enable = False
194 211 shell = self.shell
195 212 if self.pylab:
196 213 enable = lambda key: shell.enable_pylab(key, import_all=self.pylab_import_all)
197 214 key = self.pylab
198 215 elif self.matplotlib:
199 216 enable = shell.enable_matplotlib
200 217 key = self.matplotlib
201 218 elif self.gui:
202 219 enable = shell.enable_gui
203 220 key = self.gui
204 221
205 222 if not enable:
206 223 return
207 224
208 225 try:
209 226 r = enable(key)
210 227 except ImportError:
211 228 self.log.warning("Eventloop or matplotlib integration failed. Is matplotlib installed?")
212 229 self.shell.showtraceback()
213 230 return
214 231 except Exception:
215 232 self.log.warning("GUI event loop or pylab initialization failed")
216 233 self.shell.showtraceback()
217 234 return
218 235
219 236 if isinstance(r, tuple):
220 237 gui, backend = r[:2]
221 238 self.log.info("Enabling GUI event loop integration, "
222 239 "eventloop=%s, matplotlib=%s", gui, backend)
223 240 if key == "auto":
224 241 print("Using matplotlib backend: %s" % backend)
225 242 else:
226 243 gui = r
227 244 self.log.info("Enabling GUI event loop integration, "
228 245 "eventloop=%s", gui)
229 246
230 247 def init_extensions(self):
231 248 """Load all IPython extensions in IPythonApp.extensions.
232 249
233 250 This uses the :meth:`ExtensionManager.load_extensions` to load all
234 251 the extensions listed in ``self.extensions``.
235 252 """
236 253 try:
237 254 self.log.debug("Loading IPython extensions...")
238 255 extensions = self.default_extensions + self.extensions
239 256 if self.extra_extension:
240 257 extensions.append(self.extra_extension)
241 258 for ext in extensions:
242 259 try:
243 260 self.log.info("Loading IPython extension: %s" % ext)
244 261 self.shell.extension_manager.load_extension(ext)
245 262 except:
246 263 if self.reraise_ipython_extension_failures:
247 264 raise
248 265 msg = ("Error in loading extension: {ext}\n"
249 266 "Check your config files in {location}".format(
250 267 ext=ext,
251 268 location=self.profile_dir.location
252 269 ))
253 270 self.log.warning(msg, exc_info=True)
254 271 except:
255 272 if self.reraise_ipython_extension_failures:
256 273 raise
257 274 self.log.warning("Unknown error in loading extensions:", exc_info=True)
258 275
259 276 def init_code(self):
260 277 """run the pre-flight code, specified via exec_lines"""
261 278 self._run_startup_files()
262 279 self._run_exec_lines()
263 280 self._run_exec_files()
264 281
265 282 # Hide variables defined here from %who etc.
266 283 if self.hide_initial_ns:
267 284 self.shell.user_ns_hidden.update(self.shell.user_ns)
268 285
269 286 # command-line execution (ipython -i script.py, ipython -m module)
270 287 # should *not* be excluded from %whos
271 288 self._run_cmd_line_code()
272 289 self._run_module()
273 290
274 291 # flush output, so itwon't be attached to the first cell
275 292 sys.stdout.flush()
276 293 sys.stderr.flush()
277 294
278 295 def _run_exec_lines(self):
279 296 """Run lines of code in IPythonApp.exec_lines in the user's namespace."""
280 297 if not self.exec_lines:
281 298 return
282 299 try:
283 300 self.log.debug("Running code from IPythonApp.exec_lines...")
284 301 for line in self.exec_lines:
285 302 try:
286 303 self.log.info("Running code in user namespace: %s" %
287 304 line)
288 305 self.shell.run_cell(line, store_history=False)
289 306 except:
290 307 self.log.warning("Error in executing line in user "
291 308 "namespace: %s" % line)
292 309 self.shell.showtraceback()
293 310 except:
294 311 self.log.warning("Unknown error in handling IPythonApp.exec_lines:")
295 312 self.shell.showtraceback()
296 313
297 314 def _exec_file(self, fname, shell_futures=False):
298 315 try:
299 316 full_filename = filefind(fname, [u'.', self.ipython_dir])
300 317 except IOError:
301 318 self.log.warning("File not found: %r"%fname)
302 319 return
303 320 # Make sure that the running script gets a proper sys.argv as if it
304 321 # were run from a system shell.
305 322 save_argv = sys.argv
306 323 sys.argv = [full_filename] + self.extra_args[1:]
307 324 try:
308 325 if os.path.isfile(full_filename):
309 326 self.log.info("Running file in user namespace: %s" %
310 327 full_filename)
311 328 # Ensure that __file__ is always defined to match Python
312 329 # behavior.
313 330 with preserve_keys(self.shell.user_ns, '__file__'):
314 331 self.shell.user_ns['__file__'] = fname
315 332 if full_filename.endswith('.ipy'):
316 333 self.shell.safe_execfile_ipy(full_filename,
317 334 shell_futures=shell_futures)
318 335 else:
319 336 # default to python, even without extension
320 337 self.shell.safe_execfile(full_filename,
321 338 self.shell.user_ns,
322 339 shell_futures=shell_futures,
323 340 raise_exceptions=True)
324 341 finally:
325 342 sys.argv = save_argv
326 343
327 344 def _run_startup_files(self):
328 345 """Run files from profile startup directory"""
329 346 startup_dirs = [self.profile_dir.startup_dir] + [
330 347 os.path.join(p, 'startup') for p in chain(ENV_CONFIG_DIRS, SYSTEM_CONFIG_DIRS)
331 348 ]
332 349 startup_files = []
333 350
334 351 if self.exec_PYTHONSTARTUP and os.environ.get('PYTHONSTARTUP', False) and \
335 352 not (self.file_to_run or self.code_to_run or self.module_to_run):
336 353 python_startup = os.environ['PYTHONSTARTUP']
337 354 self.log.debug("Running PYTHONSTARTUP file %s...", python_startup)
338 355 try:
339 356 self._exec_file(python_startup)
340 357 except:
341 358 self.log.warning("Unknown error in handling PYTHONSTARTUP file %s:", python_startup)
342 359 self.shell.showtraceback()
343 360 for startup_dir in startup_dirs[::-1]:
344 361 startup_files += glob.glob(os.path.join(startup_dir, '*.py'))
345 362 startup_files += glob.glob(os.path.join(startup_dir, '*.ipy'))
346 363 if not startup_files:
347 364 return
348 365
349 366 self.log.debug("Running startup files from %s...", startup_dir)
350 367 try:
351 368 for fname in sorted(startup_files):
352 369 self._exec_file(fname)
353 370 except:
354 371 self.log.warning("Unknown error in handling startup files:")
355 372 self.shell.showtraceback()
356 373
357 374 def _run_exec_files(self):
358 375 """Run files from IPythonApp.exec_files"""
359 376 if not self.exec_files:
360 377 return
361 378
362 379 self.log.debug("Running files in IPythonApp.exec_files...")
363 380 try:
364 381 for fname in self.exec_files:
365 382 self._exec_file(fname)
366 383 except:
367 384 self.log.warning("Unknown error in handling IPythonApp.exec_files:")
368 385 self.shell.showtraceback()
369 386
370 387 def _run_cmd_line_code(self):
371 388 """Run code or file specified at the command-line"""
372 389 if self.code_to_run:
373 390 line = self.code_to_run
374 391 try:
375 392 self.log.info("Running code given at command line (c=): %s" %
376 393 line)
377 394 self.shell.run_cell(line, store_history=False)
378 395 except:
379 396 self.log.warning("Error in executing line in user namespace: %s" %
380 397 line)
381 398 self.shell.showtraceback()
382 399 if not self.interact:
383 400 self.exit(1)
384 401
385 402 # Like Python itself, ignore the second if the first of these is present
386 403 elif self.file_to_run:
387 404 fname = self.file_to_run
388 405 if os.path.isdir(fname):
389 406 fname = os.path.join(fname, "__main__.py")
390 407 try:
391 408 self._exec_file(fname, shell_futures=True)
392 409 except:
393 410 self.shell.showtraceback(tb_offset=4)
394 411 if not self.interact:
395 412 self.exit(1)
396 413
397 414 def _run_module(self):
398 415 """Run module specified at the command-line."""
399 416 if self.module_to_run:
400 417 # Make sure that the module gets a proper sys.argv as if it were
401 418 # run using `python -m`.
402 419 save_argv = sys.argv
403 420 sys.argv = [sys.executable] + self.extra_args
404 421 try:
405 422 self.shell.safe_run_module(self.module_to_run,
406 423 self.shell.user_ns)
407 424 finally:
408 425 sys.argv = save_argv
General Comments 0
You need to be logged in to leave comments. Login now