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