##// END OF EJS Templates
Merge pull request #10652 from ipython/auto-backport-of-pr-10644...
Matthias Bussonnier -
r23769:61da6efb merge
parent child Browse files
Show More
@@ -0,0 +1,5 b''
1
2 - IPython now looks for config files in ``{sys.prefix}/etc/ipython``
3 for environment-specific configuration.
4 - Startup files can be found in ``/etc/ipython/startup`` or ``{sys.prefix}/etc/ipython/startup``
5 in addition to the profile directory, for system-wide or env-specific startup files.
@@ -1,458 +1,467 b''
1 1 # encoding: utf-8
2 2 """
3 3 An application for IPython.
4 4
5 5 All top-level applications should use the classes in this module for
6 6 handling configuration and creating configurables.
7 7
8 8 The job of an :class:`Application` is to create the master configuration
9 9 object and then create the configurable objects, passing the config to them.
10 10 """
11 11
12 12 # Copyright (c) IPython Development Team.
13 13 # Distributed under the terms of the Modified BSD License.
14 14
15 15 import atexit
16 16 from copy import deepcopy
17 17 import glob
18 18 import logging
19 19 import os
20 20 import shutil
21 21 import sys
22 22
23 23 from traitlets.config.application import Application, catch_config_error
24 24 from traitlets.config.loader import ConfigFileNotFound, PyFileConfigLoader
25 25 from IPython.core import release, crashhandler
26 26 from IPython.core.profiledir import ProfileDir, ProfileDirError
27 27 from IPython.paths import get_ipython_dir, get_ipython_package_dir
28 28 from IPython.utils.path import ensure_dir_exists
29 29 from IPython.utils import py3compat
30 30 from traitlets import (
31 31 List, Unicode, Type, Bool, Dict, Set, Instance, Undefined,
32 32 default, observe,
33 33 )
34 34
35 35 if os.name == 'nt':
36 36 programdata = os.environ.get('PROGRAMDATA', None)
37 37 if programdata:
38 38 SYSTEM_CONFIG_DIRS = [os.path.join(programdata, 'ipython')]
39 39 else: # PROGRAMDATA is not defined by default on XP.
40 40 SYSTEM_CONFIG_DIRS = []
41 41 else:
42 42 SYSTEM_CONFIG_DIRS = [
43 43 "/usr/local/etc/ipython",
44 44 "/etc/ipython",
45 45 ]
46 46
47
48 ENV_CONFIG_DIRS = []
49 _env_config_dir = os.path.join(sys.prefix, 'etc', 'ipython')
50 if _env_config_dir not in SYSTEM_CONFIG_DIRS:
51 # only add ENV_CONFIG if sys.prefix is not already included
52 ENV_CONFIG_DIRS.append(_env_config_dir)
53
54
47 55 _envvar = os.environ.get('IPYTHON_SUPPRESS_CONFIG_ERRORS')
48 56 if _envvar in {None, ''}:
49 57 IPYTHON_SUPPRESS_CONFIG_ERRORS = None
50 58 else:
51 59 if _envvar.lower() in {'1','true'}:
52 60 IPYTHON_SUPPRESS_CONFIG_ERRORS = True
53 61 elif _envvar.lower() in {'0','false'} :
54 62 IPYTHON_SUPPRESS_CONFIG_ERRORS = False
55 63 else:
56 64 sys.exit("Unsupported value for environment variable: 'IPYTHON_SUPPRESS_CONFIG_ERRORS' is set to '%s' which is none of {'0', '1', 'false', 'true', ''}."% _envvar )
57 65
58 66 # aliases and flags
59 67
60 68 base_aliases = {
61 69 'profile-dir' : 'ProfileDir.location',
62 70 'profile' : 'BaseIPythonApplication.profile',
63 71 'ipython-dir' : 'BaseIPythonApplication.ipython_dir',
64 72 'log-level' : 'Application.log_level',
65 73 'config' : 'BaseIPythonApplication.extra_config_file',
66 74 }
67 75
68 76 base_flags = dict(
69 77 debug = ({'Application' : {'log_level' : logging.DEBUG}},
70 78 "set log level to logging.DEBUG (maximize logging output)"),
71 79 quiet = ({'Application' : {'log_level' : logging.CRITICAL}},
72 80 "set log level to logging.CRITICAL (minimize logging output)"),
73 81 init = ({'BaseIPythonApplication' : {
74 82 'copy_config_files' : True,
75 83 'auto_create' : True}
76 84 }, """Initialize profile with default config files. This is equivalent
77 85 to running `ipython profile create <profile>` prior to startup.
78 86 """)
79 87 )
80 88
81 89 class ProfileAwareConfigLoader(PyFileConfigLoader):
82 90 """A Python file config loader that is aware of IPython profiles."""
83 91 def load_subconfig(self, fname, path=None, profile=None):
84 92 if profile is not None:
85 93 try:
86 94 profile_dir = ProfileDir.find_profile_dir_by_name(
87 95 get_ipython_dir(),
88 96 profile,
89 97 )
90 98 except ProfileDirError:
91 99 return
92 100 path = profile_dir.location
93 101 return super(ProfileAwareConfigLoader, self).load_subconfig(fname, path=path)
94 102
95 103 class BaseIPythonApplication(Application):
96 104
97 105 name = Unicode(u'ipython')
98 106 description = Unicode(u'IPython: an enhanced interactive Python shell.')
99 107 version = Unicode(release.version)
100 108
101 109 aliases = Dict(base_aliases)
102 110 flags = Dict(base_flags)
103 111 classes = List([ProfileDir])
104 112
105 113 # enable `load_subconfig('cfg.py', profile='name')`
106 114 python_config_loader_class = ProfileAwareConfigLoader
107 115
108 116 # Track whether the config_file has changed,
109 117 # because some logic happens only if we aren't using the default.
110 118 config_file_specified = Set()
111 119
112 120 config_file_name = Unicode()
113 121 @default('config_file_name')
114 122 def _config_file_name_default(self):
115 123 return self.name.replace('-','_') + u'_config.py'
116 124 @observe('config_file_name')
117 125 def _config_file_name_changed(self, change):
118 126 if change['new'] != change['old']:
119 127 self.config_file_specified.add(change['new'])
120 128
121 129 # The directory that contains IPython's builtin profiles.
122 130 builtin_profile_dir = Unicode(
123 131 os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
124 132 )
125 133
126 134 config_file_paths = List(Unicode())
127 135 @default('config_file_paths')
128 136 def _config_file_paths_default(self):
129 137 return [py3compat.getcwd()]
130 138
131 139 extra_config_file = Unicode(
132 140 help="""Path to an extra config file to load.
133 141
134 142 If specified, load this config file in addition to any other IPython config.
135 143 """).tag(config=True)
136 144 @observe('extra_config_file')
137 145 def _extra_config_file_changed(self, change):
138 146 old = change['old']
139 147 new = change['new']
140 148 try:
141 149 self.config_files.remove(old)
142 150 except ValueError:
143 151 pass
144 152 self.config_file_specified.add(new)
145 153 self.config_files.append(new)
146 154
147 155 profile = Unicode(u'default',
148 156 help="""The IPython profile to use."""
149 157 ).tag(config=True)
150 158
151 159 @observe('profile')
152 160 def _profile_changed(self, change):
153 161 self.builtin_profile_dir = os.path.join(
154 162 get_ipython_package_dir(), u'config', u'profile', change['new']
155 163 )
156 164
157 165 ipython_dir = Unicode(
158 166 help="""
159 167 The name of the IPython directory. This directory is used for logging
160 168 configuration (through profiles), history storage, etc. The default
161 169 is usually $HOME/.ipython. This option can also be specified through
162 170 the environment variable IPYTHONDIR.
163 171 """
164 172 ).tag(config=True)
165 173 @default('ipython_dir')
166 174 def _ipython_dir_default(self):
167 175 d = get_ipython_dir()
168 176 self._ipython_dir_changed({
169 177 'name': 'ipython_dir',
170 178 'old': d,
171 179 'new': d,
172 180 })
173 181 return d
174 182
175 183 _in_init_profile_dir = False
176 184 profile_dir = Instance(ProfileDir, allow_none=True)
177 185 @default('profile_dir')
178 186 def _profile_dir_default(self):
179 187 # avoid recursion
180 188 if self._in_init_profile_dir:
181 189 return
182 190 # profile_dir requested early, force initialization
183 191 self.init_profile_dir()
184 192 return self.profile_dir
185 193
186 194 overwrite = Bool(False,
187 195 help="""Whether to overwrite existing config files when copying"""
188 196 ).tag(config=True)
189 197 auto_create = Bool(False,
190 198 help="""Whether to create profile dir if it doesn't exist"""
191 199 ).tag(config=True)
192 200
193 201 config_files = List(Unicode())
194 202 @default('config_files')
195 203 def _config_files_default(self):
196 204 return [self.config_file_name]
197 205
198 206 copy_config_files = Bool(False,
199 207 help="""Whether to install the default config files into the profile dir.
200 208 If a new profile is being created, and IPython contains config files for that
201 209 profile, then they will be staged into the new directory. Otherwise,
202 210 default config files will be automatically generated.
203 211 """).tag(config=True)
204 212
205 213 verbose_crash = Bool(False,
206 214 help="""Create a massive crash report when IPython encounters what may be an
207 215 internal error. The default is to append a short message to the
208 216 usual traceback""").tag(config=True)
209 217
210 218 # The class to use as the crash handler.
211 219 crash_handler_class = Type(crashhandler.CrashHandler)
212 220
213 221 @catch_config_error
214 222 def __init__(self, **kwargs):
215 223 super(BaseIPythonApplication, self).__init__(**kwargs)
216 224 # ensure current working directory exists
217 225 try:
218 226 py3compat.getcwd()
219 227 except:
220 228 # exit if cwd doesn't exist
221 229 self.log.error("Current working directory doesn't exist.")
222 230 self.exit(1)
223 231
224 232 #-------------------------------------------------------------------------
225 233 # Various stages of Application creation
226 234 #-------------------------------------------------------------------------
227 235
228 236 deprecated_subcommands = {}
229 237
230 238 def initialize_subcommand(self, subc, argv=None):
231 239 if subc in self.deprecated_subcommands:
232 240 self.log.warning("Subcommand `ipython {sub}` is deprecated and will be removed "
233 241 "in future versions.".format(sub=subc))
234 242 self.log.warning("You likely want to use `jupyter {sub}` in the "
235 243 "future".format(sub=subc))
236 244 return super(BaseIPythonApplication, self).initialize_subcommand(subc, argv)
237 245
238 246 def init_crash_handler(self):
239 247 """Create a crash handler, typically setting sys.excepthook to it."""
240 248 self.crash_handler = self.crash_handler_class(self)
241 249 sys.excepthook = self.excepthook
242 250 def unset_crashhandler():
243 251 sys.excepthook = sys.__excepthook__
244 252 atexit.register(unset_crashhandler)
245 253
246 254 def excepthook(self, etype, evalue, tb):
247 255 """this is sys.excepthook after init_crashhandler
248 256
249 257 set self.verbose_crash=True to use our full crashhandler, instead of
250 258 a regular traceback with a short message (crash_handler_lite)
251 259 """
252 260
253 261 if self.verbose_crash:
254 262 return self.crash_handler(etype, evalue, tb)
255 263 else:
256 264 return crashhandler.crash_handler_lite(etype, evalue, tb)
257 265
258 266 @observe('ipython_dir')
259 267 def _ipython_dir_changed(self, change):
260 268 old = change['old']
261 269 new = change['new']
262 270 if old is not Undefined:
263 271 str_old = py3compat.cast_bytes_py2(os.path.abspath(old),
264 272 sys.getfilesystemencoding()
265 273 )
266 274 if str_old in sys.path:
267 275 sys.path.remove(str_old)
268 276 str_path = py3compat.cast_bytes_py2(os.path.abspath(new),
269 277 sys.getfilesystemencoding()
270 278 )
271 279 sys.path.append(str_path)
272 280 ensure_dir_exists(new)
273 281 readme = os.path.join(new, 'README')
274 282 readme_src = os.path.join(get_ipython_package_dir(), u'config', u'profile', 'README')
275 283 if not os.path.exists(readme) and os.path.exists(readme_src):
276 284 shutil.copy(readme_src, readme)
277 285 for d in ('extensions', 'nbextensions'):
278 286 path = os.path.join(new, d)
279 287 try:
280 288 ensure_dir_exists(path)
281 289 except OSError as e:
282 290 # this will not be EEXIST
283 291 self.log.error("couldn't create path %s: %s", path, e)
284 292 self.log.debug("IPYTHONDIR set to: %s" % new)
285 293
286 294 def load_config_file(self, suppress_errors=IPYTHON_SUPPRESS_CONFIG_ERRORS):
287 295 """Load the config file.
288 296
289 297 By default, errors in loading config are handled, and a warning
290 298 printed on screen. For testing, the suppress_errors option is set
291 299 to False, so errors will make tests fail.
292 300
293 301 `supress_errors` default value is to be `None` in which case the
294 302 behavior default to the one of `traitlets.Application`.
295 303
296 304 The default value can be set :
297 305 - to `False` by setting 'IPYTHON_SUPPRESS_CONFIG_ERRORS' environment variable to '0', or 'false' (case insensitive).
298 306 - to `True` by setting 'IPYTHON_SUPPRESS_CONFIG_ERRORS' environment variable to '1' or 'true' (case insensitive).
299 307 - to `None` by setting 'IPYTHON_SUPPRESS_CONFIG_ERRORS' environment variable to '' (empty string) or leaving it unset.
300 308
301 309 Any other value are invalid, and will make IPython exit with a non-zero return code.
302 310 """
303 311
304 312
305 313 self.log.debug("Searching path %s for config files", self.config_file_paths)
306 314 base_config = 'ipython_config.py'
307 315 self.log.debug("Attempting to load config file: %s" %
308 316 base_config)
309 317 try:
310 318 if suppress_errors is not None:
311 319 old_value = Application.raise_config_file_errors
312 320 Application.raise_config_file_errors = not suppress_errors;
313 321 Application.load_config_file(
314 322 self,
315 323 base_config,
316 324 path=self.config_file_paths
317 325 )
318 326 except ConfigFileNotFound:
319 327 # ignore errors loading parent
320 328 self.log.debug("Config file %s not found", base_config)
321 329 pass
322 330 if suppress_errors is not None:
323 331 Application.raise_config_file_errors = old_value
324 332
325 333 for config_file_name in self.config_files:
326 334 if not config_file_name or config_file_name == base_config:
327 335 continue
328 336 self.log.debug("Attempting to load config file: %s" %
329 337 self.config_file_name)
330 338 try:
331 339 Application.load_config_file(
332 340 self,
333 341 config_file_name,
334 342 path=self.config_file_paths
335 343 )
336 344 except ConfigFileNotFound:
337 345 # Only warn if the default config file was NOT being used.
338 346 if config_file_name in self.config_file_specified:
339 347 msg = self.log.warning
340 348 else:
341 349 msg = self.log.debug
342 350 msg("Config file not found, skipping: %s", config_file_name)
343 351 except Exception:
344 352 # For testing purposes.
345 353 if not suppress_errors:
346 354 raise
347 355 self.log.warning("Error loading config file: %s" %
348 356 self.config_file_name, exc_info=True)
349 357
350 358 def init_profile_dir(self):
351 359 """initialize the profile dir"""
352 360 self._in_init_profile_dir = True
353 361 if self.profile_dir is not None:
354 362 # already ran
355 363 return
356 364 if 'ProfileDir.location' not in self.config:
357 365 # location not specified, find by profile name
358 366 try:
359 367 p = ProfileDir.find_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
360 368 except ProfileDirError:
361 369 # not found, maybe create it (always create default profile)
362 370 if self.auto_create or self.profile == 'default':
363 371 try:
364 372 p = ProfileDir.create_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
365 373 except ProfileDirError:
366 374 self.log.fatal("Could not create profile: %r"%self.profile)
367 375 self.exit(1)
368 376 else:
369 377 self.log.info("Created profile dir: %r"%p.location)
370 378 else:
371 379 self.log.fatal("Profile %r not found."%self.profile)
372 380 self.exit(1)
373 381 else:
374 382 self.log.debug("Using existing profile dir: %r"%p.location)
375 383 else:
376 384 location = self.config.ProfileDir.location
377 385 # location is fully specified
378 386 try:
379 387 p = ProfileDir.find_profile_dir(location, self.config)
380 388 except ProfileDirError:
381 389 # not found, maybe create it
382 390 if self.auto_create:
383 391 try:
384 392 p = ProfileDir.create_profile_dir(location, self.config)
385 393 except ProfileDirError:
386 394 self.log.fatal("Could not create profile directory: %r"%location)
387 395 self.exit(1)
388 396 else:
389 397 self.log.debug("Creating new profile dir: %r"%location)
390 398 else:
391 399 self.log.fatal("Profile directory %r not found."%location)
392 400 self.exit(1)
393 401 else:
394 402 self.log.info("Using existing profile dir: %r"%location)
395 403 # if profile_dir is specified explicitly, set profile name
396 404 dir_name = os.path.basename(p.location)
397 405 if dir_name.startswith('profile_'):
398 406 self.profile = dir_name[8:]
399 407
400 408 self.profile_dir = p
401 409 self.config_file_paths.append(p.location)
402 410 self._in_init_profile_dir = False
403 411
404 412 def init_config_files(self):
405 413 """[optionally] copy default config files into profile dir."""
414 self.config_file_paths.extend(ENV_CONFIG_DIRS)
406 415 self.config_file_paths.extend(SYSTEM_CONFIG_DIRS)
407 416 # copy config files
408 417 path = self.builtin_profile_dir
409 418 if self.copy_config_files:
410 419 src = self.profile
411 420
412 421 cfg = self.config_file_name
413 422 if path and os.path.exists(os.path.join(path, cfg)):
414 423 self.log.warning("Staging %r from %s into %r [overwrite=%s]"%(
415 424 cfg, src, self.profile_dir.location, self.overwrite)
416 425 )
417 426 self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite)
418 427 else:
419 428 self.stage_default_config_file()
420 429 else:
421 430 # Still stage *bundled* config files, but not generated ones
422 431 # This is necessary for `ipython profile=sympy` to load the profile
423 432 # on the first go
424 433 files = glob.glob(os.path.join(path, '*.py'))
425 434 for fullpath in files:
426 435 cfg = os.path.basename(fullpath)
427 436 if self.profile_dir.copy_config_file(cfg, path=path, overwrite=False):
428 437 # file was copied
429 438 self.log.warning("Staging bundled %s from %s into %r"%(
430 439 cfg, self.profile, self.profile_dir.location)
431 440 )
432 441
433 442
434 443 def stage_default_config_file(self):
435 444 """auto generate default config file, and stage it into the profile."""
436 445 s = self.generate_config_file()
437 446 fname = os.path.join(self.profile_dir.location, self.config_file_name)
438 447 if self.overwrite or not os.path.exists(fname):
439 448 self.log.warning("Generating default config file: %r"%(fname))
440 449 with open(fname, 'w') as f:
441 450 f.write(s)
442 451
443 452 @catch_config_error
444 453 def initialize(self, argv=None):
445 454 # don't hook up crash handler before parsing command-line
446 455 self.parse_command_line(argv)
447 456 self.init_crash_handler()
448 457 if self.subapp is not None:
449 458 # stop here if subapp is taking over
450 459 return
451 460 # save a copy of CLI config to re-load after config files
452 461 # so that it has highest priority
453 462 cl_config = deepcopy(self.config)
454 463 self.init_profile_dir()
455 464 self.init_config_files()
456 465 self.load_config_file()
457 466 # enforce cl-opts override configfile opts:
458 467 self.update_config(cl_config)
@@ -1,411 +1,415 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 from itertools import chain
14 15 import os
15 16 import sys
16 17
17 18 from traitlets.config.application import boolean_flag
18 19 from traitlets.config.configurable import Configurable
19 20 from traitlets.config.loader import Config
21 from IPython.core.application import SYSTEM_CONFIG_DIRS, ENV_CONFIG_DIRS
20 22 from IPython.core import pylabtools
21 23 from IPython.utils import py3compat
22 24 from IPython.utils.contexts import preserve_keys
23 25 from IPython.utils.path import filefind
24 26 from traitlets import (
25 27 Unicode, Instance, List, Bool, CaselessStrEnum, observe,
26 28 )
27 29 from IPython.terminal import pt_inputhooks
28 30
29 31 #-----------------------------------------------------------------------------
30 32 # Aliases and Flags
31 33 #-----------------------------------------------------------------------------
32 34
33 35 gui_keys = tuple(sorted(pt_inputhooks.backends) + sorted(pt_inputhooks.aliases))
34 36
35 37 backend_keys = sorted(pylabtools.backends.keys())
36 38 backend_keys.insert(0, 'auto')
37 39
38 40 shell_flags = {}
39 41
40 42 addflag = lambda *args: shell_flags.update(boolean_flag(*args))
41 43 addflag('autoindent', 'InteractiveShell.autoindent',
42 44 'Turn on autoindenting.', 'Turn off autoindenting.'
43 45 )
44 46 addflag('automagic', 'InteractiveShell.automagic',
45 47 """Turn on the auto calling of magic commands. Type %%magic at the
46 48 IPython prompt for more information.""",
47 49 'Turn off the auto calling of magic commands.'
48 50 )
49 51 addflag('pdb', 'InteractiveShell.pdb',
50 52 "Enable auto calling the pdb debugger after every exception.",
51 53 "Disable auto calling the pdb debugger after every exception."
52 54 )
53 55 addflag('pprint', 'PlainTextFormatter.pprint',
54 56 "Enable auto pretty printing of results.",
55 57 "Disable auto pretty printing of results."
56 58 )
57 59 addflag('color-info', 'InteractiveShell.color_info',
58 60 """IPython can display information about objects via a set of functions,
59 61 and optionally can use colors for this, syntax highlighting
60 62 source code and various other elements. This is on by default, but can cause
61 63 problems with some pagers. If you see such problems, you can disable the
62 64 colours.""",
63 65 "Disable using colors for info related things."
64 66 )
65 67 nosep_config = Config()
66 68 nosep_config.InteractiveShell.separate_in = ''
67 69 nosep_config.InteractiveShell.separate_out = ''
68 70 nosep_config.InteractiveShell.separate_out2 = ''
69 71
70 72 shell_flags['nosep']=(nosep_config, "Eliminate all spacing between prompts.")
71 73 shell_flags['pylab'] = (
72 74 {'InteractiveShellApp' : {'pylab' : 'auto'}},
73 75 """Pre-load matplotlib and numpy for interactive use with
74 76 the default matplotlib backend."""
75 77 )
76 78 shell_flags['matplotlib'] = (
77 79 {'InteractiveShellApp' : {'matplotlib' : 'auto'}},
78 80 """Configure matplotlib for interactive use with
79 81 the default matplotlib backend."""
80 82 )
81 83
82 84 # it's possible we don't want short aliases for *all* of these:
83 85 shell_aliases = dict(
84 86 autocall='InteractiveShell.autocall',
85 87 colors='InteractiveShell.colors',
86 88 logfile='InteractiveShell.logfile',
87 89 logappend='InteractiveShell.logappend',
88 90 c='InteractiveShellApp.code_to_run',
89 91 m='InteractiveShellApp.module_to_run',
90 92 ext='InteractiveShellApp.extra_extension',
91 93 gui='InteractiveShellApp.gui',
92 94 pylab='InteractiveShellApp.pylab',
93 95 matplotlib='InteractiveShellApp.matplotlib',
94 96 )
95 97 shell_aliases['cache-size'] = 'InteractiveShell.cache_size'
96 98
97 99 #-----------------------------------------------------------------------------
98 100 # Main classes and functions
99 101 #-----------------------------------------------------------------------------
100 102
101 103 class InteractiveShellApp(Configurable):
102 104 """A Mixin for applications that start InteractiveShell instances.
103 105
104 106 Provides configurables for loading extensions and executing files
105 107 as part of configuring a Shell environment.
106 108
107 109 The following methods should be called by the :meth:`initialize` method
108 110 of the subclass:
109 111
110 112 - :meth:`init_path`
111 113 - :meth:`init_shell` (to be implemented by the subclass)
112 114 - :meth:`init_gui_pylab`
113 115 - :meth:`init_extensions`
114 116 - :meth:`init_code`
115 117 """
116 118 extensions = List(Unicode(),
117 119 help="A list of dotted module names of IPython extensions to load."
118 120 ).tag(config=True)
119 121 extra_extension = Unicode('',
120 122 help="dotted module name of an IPython extension to load."
121 123 ).tag(config=True)
122 124
123 125 reraise_ipython_extension_failures = Bool(False,
124 126 help="Reraise exceptions encountered loading IPython extensions?",
125 127 ).tag(config=True)
126 128
127 129 # Extensions that are always loaded (not configurable)
128 130 default_extensions = List(Unicode(), [u'storemagic']).tag(config=False)
129 131
130 132 hide_initial_ns = Bool(True,
131 133 help="""Should variables loaded at startup (by startup files, exec_lines, etc.)
132 134 be hidden from tools like %who?"""
133 135 ).tag(config=True)
134 136
135 137 exec_files = List(Unicode(),
136 138 help="""List of files to run at IPython startup."""
137 139 ).tag(config=True)
138 140 exec_PYTHONSTARTUP = Bool(True,
139 141 help="""Run the file referenced by the PYTHONSTARTUP environment
140 142 variable at IPython startup."""
141 143 ).tag(config=True)
142 144 file_to_run = Unicode('',
143 145 help="""A file to be run""").tag(config=True)
144 146
145 147 exec_lines = List(Unicode(),
146 148 help="""lines of code to run at IPython startup."""
147 149 ).tag(config=True)
148 150 code_to_run = Unicode('',
149 151 help="Execute the given command string."
150 152 ).tag(config=True)
151 153 module_to_run = Unicode('',
152 154 help="Run the module as a script."
153 155 ).tag(config=True)
154 156 gui = CaselessStrEnum(gui_keys, allow_none=True,
155 157 help="Enable GUI event loop integration with any of {0}.".format(gui_keys)
156 158 ).tag(config=True)
157 159 matplotlib = CaselessStrEnum(backend_keys, allow_none=True,
158 160 help="""Configure matplotlib for interactive use with
159 161 the default matplotlib backend."""
160 162 ).tag(config=True)
161 163 pylab = CaselessStrEnum(backend_keys, allow_none=True,
162 164 help="""Pre-load matplotlib and numpy for interactive use,
163 165 selecting a particular matplotlib backend and loop integration.
164 166 """
165 167 ).tag(config=True)
166 168 pylab_import_all = Bool(True,
167 169 help="""If true, IPython will populate the user namespace with numpy, pylab, etc.
168 170 and an ``import *`` is done from numpy and pylab, when using pylab mode.
169 171
170 172 When False, pylab mode should not import any names into the user namespace.
171 173 """
172 174 ).tag(config=True)
173 175 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
174 176 allow_none=True)
175 177 # whether interact-loop should start
176 178 interact = Bool(True)
177 179
178 180 user_ns = Instance(dict, args=None, allow_none=True)
179 181 @observe('user_ns')
180 182 def _user_ns_changed(self, change):
181 183 if self.shell is not None:
182 184 self.shell.user_ns = change['new']
183 185 self.shell.init_user_ns()
184 186
185 187 def init_path(self):
186 188 """Add current working directory, '', to sys.path"""
187 189 if sys.path[0] != '':
188 190 sys.path.insert(0, '')
189 191
190 192 def init_shell(self):
191 193 raise NotImplementedError("Override in subclasses")
192 194
193 195 def init_gui_pylab(self):
194 196 """Enable GUI event loop integration, taking pylab into account."""
195 197 enable = False
196 198 shell = self.shell
197 199 if self.pylab:
198 200 enable = lambda key: shell.enable_pylab(key, import_all=self.pylab_import_all)
199 201 key = self.pylab
200 202 elif self.matplotlib:
201 203 enable = shell.enable_matplotlib
202 204 key = self.matplotlib
203 205 elif self.gui:
204 206 enable = shell.enable_gui
205 207 key = self.gui
206 208
207 209 if not enable:
208 210 return
209 211
210 212 try:
211 213 r = enable(key)
212 214 except ImportError:
213 215 self.log.warning("Eventloop or matplotlib integration failed. Is matplotlib installed?")
214 216 self.shell.showtraceback()
215 217 return
216 218 except Exception:
217 219 self.log.warning("GUI event loop or pylab initialization failed")
218 220 self.shell.showtraceback()
219 221 return
220 222
221 223 if isinstance(r, tuple):
222 224 gui, backend = r[:2]
223 225 self.log.info("Enabling GUI event loop integration, "
224 226 "eventloop=%s, matplotlib=%s", gui, backend)
225 227 if key == "auto":
226 228 print("Using matplotlib backend: %s" % backend)
227 229 else:
228 230 gui = r
229 231 self.log.info("Enabling GUI event loop integration, "
230 232 "eventloop=%s", gui)
231 233
232 234 def init_extensions(self):
233 235 """Load all IPython extensions in IPythonApp.extensions.
234 236
235 237 This uses the :meth:`ExtensionManager.load_extensions` to load all
236 238 the extensions listed in ``self.extensions``.
237 239 """
238 240 try:
239 241 self.log.debug("Loading IPython extensions...")
240 242 extensions = self.default_extensions + self.extensions
241 243 if self.extra_extension:
242 244 extensions.append(self.extra_extension)
243 245 for ext in extensions:
244 246 try:
245 247 self.log.info("Loading IPython extension: %s" % ext)
246 248 self.shell.extension_manager.load_extension(ext)
247 249 except:
248 250 if self.reraise_ipython_extension_failures:
249 251 raise
250 252 msg = ("Error in loading extension: {ext}\n"
251 253 "Check your config files in {location}".format(
252 254 ext=ext,
253 255 location=self.profile_dir.location
254 256 ))
255 257 self.log.warning(msg, exc_info=True)
256 258 except:
257 259 if self.reraise_ipython_extension_failures:
258 260 raise
259 261 self.log.warning("Unknown error in loading extensions:", exc_info=True)
260 262
261 263 def init_code(self):
262 264 """run the pre-flight code, specified via exec_lines"""
263 265 self._run_startup_files()
264 266 self._run_exec_lines()
265 267 self._run_exec_files()
266 268
267 269 # Hide variables defined here from %who etc.
268 270 if self.hide_initial_ns:
269 271 self.shell.user_ns_hidden.update(self.shell.user_ns)
270 272
271 273 # command-line execution (ipython -i script.py, ipython -m module)
272 274 # should *not* be excluded from %whos
273 275 self._run_cmd_line_code()
274 276 self._run_module()
275 277
276 278 # flush output, so itwon't be attached to the first cell
277 279 sys.stdout.flush()
278 280 sys.stderr.flush()
279 281
280 282 def _run_exec_lines(self):
281 283 """Run lines of code in IPythonApp.exec_lines in the user's namespace."""
282 284 if not self.exec_lines:
283 285 return
284 286 try:
285 287 self.log.debug("Running code from IPythonApp.exec_lines...")
286 288 for line in self.exec_lines:
287 289 try:
288 290 self.log.info("Running code in user namespace: %s" %
289 291 line)
290 292 self.shell.run_cell(line, store_history=False)
291 293 except:
292 294 self.log.warning("Error in executing line in user "
293 295 "namespace: %s" % line)
294 296 self.shell.showtraceback()
295 297 except:
296 298 self.log.warning("Unknown error in handling IPythonApp.exec_lines:")
297 299 self.shell.showtraceback()
298 300
299 301 def _exec_file(self, fname, shell_futures=False):
300 302 try:
301 303 full_filename = filefind(fname, [u'.', self.ipython_dir])
302 304 except IOError:
303 305 self.log.warning("File not found: %r"%fname)
304 306 return
305 307 # Make sure that the running script gets a proper sys.argv as if it
306 308 # were run from a system shell.
307 309 save_argv = sys.argv
308 310 sys.argv = [full_filename] + self.extra_args[1:]
309 311 # protect sys.argv from potential unicode strings on Python 2:
310 312 if not py3compat.PY3:
311 313 sys.argv = [ py3compat.cast_bytes(a) for a in sys.argv ]
312 314 try:
313 315 if os.path.isfile(full_filename):
314 316 self.log.info("Running file in user namespace: %s" %
315 317 full_filename)
316 318 # Ensure that __file__ is always defined to match Python
317 319 # behavior.
318 320 with preserve_keys(self.shell.user_ns, '__file__'):
319 321 self.shell.user_ns['__file__'] = fname
320 322 if full_filename.endswith('.ipy'):
321 323 self.shell.safe_execfile_ipy(full_filename,
322 324 shell_futures=shell_futures)
323 325 else:
324 326 # default to python, even without extension
325 327 self.shell.safe_execfile(full_filename,
326 328 self.shell.user_ns,
327 329 shell_futures=shell_futures,
328 330 raise_exceptions=True)
329 331 finally:
330 332 sys.argv = save_argv
331 333
332 334 def _run_startup_files(self):
333 335 """Run files from profile startup directory"""
334 startup_dir = self.profile_dir.startup_dir
336 startup_dirs = [self.profile_dir.startup_dir] + [
337 os.path.join(p, 'startup') for p in chain(ENV_CONFIG_DIRS, SYSTEM_CONFIG_DIRS)
338 ]
335 339 startup_files = []
336 340
337 341 if self.exec_PYTHONSTARTUP and os.environ.get('PYTHONSTARTUP', False) and \
338 342 not (self.file_to_run or self.code_to_run or self.module_to_run):
339 343 python_startup = os.environ['PYTHONSTARTUP']
340 344 self.log.debug("Running PYTHONSTARTUP file %s...", python_startup)
341 345 try:
342 346 self._exec_file(python_startup)
343 347 except:
344 348 self.log.warning("Unknown error in handling PYTHONSTARTUP file %s:", python_startup)
345 349 self.shell.showtraceback()
346
347 startup_files += glob.glob(os.path.join(startup_dir, '*.py'))
348 startup_files += glob.glob(os.path.join(startup_dir, '*.ipy'))
350 for startup_dir in startup_dirs[::-1]:
351 startup_files += glob.glob(os.path.join(startup_dir, '*.py'))
352 startup_files += glob.glob(os.path.join(startup_dir, '*.ipy'))
349 353 if not startup_files:
350 354 return
351 355
352 356 self.log.debug("Running startup files from %s...", startup_dir)
353 357 try:
354 358 for fname in sorted(startup_files):
355 359 self._exec_file(fname)
356 360 except:
357 361 self.log.warning("Unknown error in handling startup files:")
358 362 self.shell.showtraceback()
359 363
360 364 def _run_exec_files(self):
361 365 """Run files from IPythonApp.exec_files"""
362 366 if not self.exec_files:
363 367 return
364 368
365 369 self.log.debug("Running files in IPythonApp.exec_files...")
366 370 try:
367 371 for fname in self.exec_files:
368 372 self._exec_file(fname)
369 373 except:
370 374 self.log.warning("Unknown error in handling IPythonApp.exec_files:")
371 375 self.shell.showtraceback()
372 376
373 377 def _run_cmd_line_code(self):
374 378 """Run code or file specified at the command-line"""
375 379 if self.code_to_run:
376 380 line = self.code_to_run
377 381 try:
378 382 self.log.info("Running code given at command line (c=): %s" %
379 383 line)
380 384 self.shell.run_cell(line, store_history=False)
381 385 except:
382 386 self.log.warning("Error in executing line in user namespace: %s" %
383 387 line)
384 388 self.shell.showtraceback()
385 389 if not self.interact:
386 390 self.exit(1)
387 391
388 392 # Like Python itself, ignore the second if the first of these is present
389 393 elif self.file_to_run:
390 394 fname = self.file_to_run
391 395 if os.path.isdir(fname):
392 396 fname = os.path.join(fname, "__main__.py")
393 397 try:
394 398 self._exec_file(fname, shell_futures=True)
395 399 except:
396 400 self.shell.showtraceback(tb_offset=4)
397 401 if not self.interact:
398 402 self.exit(1)
399 403
400 404 def _run_module(self):
401 405 """Run module specified at the command-line."""
402 406 if self.module_to_run:
403 407 # Make sure that the module gets a proper sys.argv as if it were
404 408 # run using `python -m`.
405 409 save_argv = sys.argv
406 410 sys.argv = [sys.executable] + self.extra_args
407 411 try:
408 412 self.shell.safe_run_module(self.module_to_run,
409 413 self.shell.user_ns)
410 414 finally:
411 415 sys.argv = save_argv
General Comments 0
You need to be logged in to leave comments. Login now