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