123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415 |
- # encoding: utf-8
- """
- A mixin for :class:`~IPython.core.application.Application` classes that
- launch InteractiveShell instances, load extensions, etc.
- """
- # Copyright (c) IPython Development Team.
- # Distributed under the terms of the Modified BSD License.
- from __future__ import absolute_import
- from __future__ import print_function
- import glob
- from itertools import chain
- import os
- import sys
- from traitlets.config.application import boolean_flag
- from traitlets.config.configurable import Configurable
- from traitlets.config.loader import Config
- from IPython.core.application import SYSTEM_CONFIG_DIRS, ENV_CONFIG_DIRS
- from IPython.core import pylabtools
- from IPython.utils import py3compat
- from IPython.utils.contexts import preserve_keys
- from IPython.utils.path import filefind
- from traitlets import (
- Unicode, Instance, List, Bool, CaselessStrEnum, observe,
- )
- from IPython.terminal import pt_inputhooks
- #-----------------------------------------------------------------------------
- # Aliases and Flags
- #-----------------------------------------------------------------------------
- gui_keys = tuple(sorted(pt_inputhooks.backends) + sorted(pt_inputhooks.aliases))
- backend_keys = sorted(pylabtools.backends.keys())
- backend_keys.insert(0, 'auto')
- shell_flags = {}
- addflag = lambda *args: shell_flags.update(boolean_flag(*args))
- addflag('autoindent', 'InteractiveShell.autoindent',
- 'Turn on autoindenting.', 'Turn off autoindenting.'
- )
- addflag('automagic', 'InteractiveShell.automagic',
- """Turn on the auto calling of magic commands. Type %%magic at the
- IPython prompt for more information.""",
- 'Turn off the auto calling of magic commands.'
- )
- addflag('pdb', 'InteractiveShell.pdb',
- "Enable auto calling the pdb debugger after every exception.",
- "Disable auto calling the pdb debugger after every exception."
- )
- addflag('pprint', 'PlainTextFormatter.pprint',
- "Enable auto pretty printing of results.",
- "Disable auto pretty printing of results."
- )
- addflag('color-info', 'InteractiveShell.color_info',
- """IPython can display information about objects via a set of functions,
- and optionally can use colors for this, syntax highlighting
- source code and various other elements. This is on by default, but can cause
- problems with some pagers. If you see such problems, you can disable the
- colours.""",
- "Disable using colors for info related things."
- )
- nosep_config = Config()
- nosep_config.InteractiveShell.separate_in = ''
- nosep_config.InteractiveShell.separate_out = ''
- nosep_config.InteractiveShell.separate_out2 = ''
- shell_flags['nosep']=(nosep_config, "Eliminate all spacing between prompts.")
- shell_flags['pylab'] = (
- {'InteractiveShellApp' : {'pylab' : 'auto'}},
- """Pre-load matplotlib and numpy for interactive use with
- the default matplotlib backend."""
- )
- shell_flags['matplotlib'] = (
- {'InteractiveShellApp' : {'matplotlib' : 'auto'}},
- """Configure matplotlib for interactive use with
- the default matplotlib backend."""
- )
- # it's possible we don't want short aliases for *all* of these:
- shell_aliases = dict(
- autocall='InteractiveShell.autocall',
- colors='InteractiveShell.colors',
- logfile='InteractiveShell.logfile',
- logappend='InteractiveShell.logappend',
- c='InteractiveShellApp.code_to_run',
- m='InteractiveShellApp.module_to_run',
- ext='InteractiveShellApp.extra_extension',
- gui='InteractiveShellApp.gui',
- pylab='InteractiveShellApp.pylab',
- matplotlib='InteractiveShellApp.matplotlib',
- )
- shell_aliases['cache-size'] = 'InteractiveShell.cache_size'
- #-----------------------------------------------------------------------------
- # Main classes and functions
- #-----------------------------------------------------------------------------
- class InteractiveShellApp(Configurable):
- """A Mixin for applications that start InteractiveShell instances.
- Provides configurables for loading extensions and executing files
- as part of configuring a Shell environment.
- The following methods should be called by the :meth:`initialize` method
- of the subclass:
- - :meth:`init_path`
- - :meth:`init_shell` (to be implemented by the subclass)
- - :meth:`init_gui_pylab`
- - :meth:`init_extensions`
- - :meth:`init_code`
- """
- extensions = List(Unicode(),
- help="A list of dotted module names of IPython extensions to load."
- ).tag(config=True)
- extra_extension = Unicode('',
- help="dotted module name of an IPython extension to load."
- ).tag(config=True)
- reraise_ipython_extension_failures = Bool(False,
- help="Reraise exceptions encountered loading IPython extensions?",
- ).tag(config=True)
- # Extensions that are always loaded (not configurable)
- default_extensions = List(Unicode(), [u'storemagic']).tag(config=False)
- hide_initial_ns = Bool(True,
- help="""Should variables loaded at startup (by startup files, exec_lines, etc.)
- be hidden from tools like %who?"""
- ).tag(config=True)
- exec_files = List(Unicode(),
- help="""List of files to run at IPython startup."""
- ).tag(config=True)
- exec_PYTHONSTARTUP = Bool(True,
- help="""Run the file referenced by the PYTHONSTARTUP environment
- variable at IPython startup."""
- ).tag(config=True)
- file_to_run = Unicode('',
- help="""A file to be run""").tag(config=True)
- exec_lines = List(Unicode(),
- help="""lines of code to run at IPython startup."""
- ).tag(config=True)
- code_to_run = Unicode('',
- help="Execute the given command string."
- ).tag(config=True)
- module_to_run = Unicode('',
- help="Run the module as a script."
- ).tag(config=True)
- gui = CaselessStrEnum(gui_keys, allow_none=True,
- help="Enable GUI event loop integration with any of {0}.".format(gui_keys)
- ).tag(config=True)
- matplotlib = CaselessStrEnum(backend_keys, allow_none=True,
- help="""Configure matplotlib for interactive use with
- the default matplotlib backend."""
- ).tag(config=True)
- pylab = CaselessStrEnum(backend_keys, allow_none=True,
- help="""Pre-load matplotlib and numpy for interactive use,
- selecting a particular matplotlib backend and loop integration.
- """
- ).tag(config=True)
- pylab_import_all = Bool(True,
- help="""If true, IPython will populate the user namespace with numpy, pylab, etc.
- and an ``import *`` is done from numpy and pylab, when using pylab mode.
- When False, pylab mode should not import any names into the user namespace.
- """
- ).tag(config=True)
- shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
- allow_none=True)
- # whether interact-loop should start
- interact = Bool(True)
- user_ns = Instance(dict, args=None, allow_none=True)
- @observe('user_ns')
- def _user_ns_changed(self, change):
- if self.shell is not None:
- self.shell.user_ns = change['new']
- self.shell.init_user_ns()
- def init_path(self):
- """Add current working directory, '', to sys.path"""
- if sys.path[0] != '':
- sys.path.insert(0, '')
- def init_shell(self):
- raise NotImplementedError("Override in subclasses")
- def init_gui_pylab(self):
- """Enable GUI event loop integration, taking pylab into account."""
- enable = False
- shell = self.shell
- if self.pylab:
- enable = lambda key: shell.enable_pylab(key, import_all=self.pylab_import_all)
- key = self.pylab
- elif self.matplotlib:
- enable = shell.enable_matplotlib
- key = self.matplotlib
- elif self.gui:
- enable = shell.enable_gui
- key = self.gui
- if not enable:
- return
- try:
- r = enable(key)
- except ImportError:
- self.log.warning("Eventloop or matplotlib integration failed. Is matplotlib installed?")
- self.shell.showtraceback()
- return
- except Exception:
- self.log.warning("GUI event loop or pylab initialization failed")
- self.shell.showtraceback()
- return
- if isinstance(r, tuple):
- gui, backend = r[:2]
- self.log.info("Enabling GUI event loop integration, "
- "eventloop=%s, matplotlib=%s", gui, backend)
- if key == "auto":
- print("Using matplotlib backend: %s" % backend)
- else:
- gui = r
- self.log.info("Enabling GUI event loop integration, "
- "eventloop=%s", gui)
- def init_extensions(self):
- """Load all IPython extensions in IPythonApp.extensions.
- This uses the :meth:`ExtensionManager.load_extensions` to load all
- the extensions listed in ``self.extensions``.
- """
- try:
- self.log.debug("Loading IPython extensions...")
- extensions = self.default_extensions + self.extensions
- if self.extra_extension:
- extensions.append(self.extra_extension)
- for ext in extensions:
- try:
- self.log.info("Loading IPython extension: %s" % ext)
- self.shell.extension_manager.load_extension(ext)
- except:
- if self.reraise_ipython_extension_failures:
- raise
- msg = ("Error in loading extension: {ext}\n"
- "Check your config files in {location}".format(
- ext=ext,
- location=self.profile_dir.location
- ))
- self.log.warning(msg, exc_info=True)
- except:
- if self.reraise_ipython_extension_failures:
- raise
- self.log.warning("Unknown error in loading extensions:", exc_info=True)
- def init_code(self):
- """run the pre-flight code, specified via exec_lines"""
- self._run_startup_files()
- self._run_exec_lines()
- self._run_exec_files()
- # Hide variables defined here from %who etc.
- if self.hide_initial_ns:
- self.shell.user_ns_hidden.update(self.shell.user_ns)
- # command-line execution (ipython -i script.py, ipython -m module)
- # should *not* be excluded from %whos
- self._run_cmd_line_code()
- self._run_module()
- # flush output, so itwon't be attached to the first cell
- sys.stdout.flush()
- sys.stderr.flush()
- def _run_exec_lines(self):
- """Run lines of code in IPythonApp.exec_lines in the user's namespace."""
- if not self.exec_lines:
- return
- try:
- self.log.debug("Running code from IPythonApp.exec_lines...")
- for line in self.exec_lines:
- try:
- self.log.info("Running code in user namespace: %s" %
- line)
- self.shell.run_cell(line, store_history=False)
- except:
- self.log.warning("Error in executing line in user "
- "namespace: %s" % line)
- self.shell.showtraceback()
- except:
- self.log.warning("Unknown error in handling IPythonApp.exec_lines:")
- self.shell.showtraceback()
- def _exec_file(self, fname, shell_futures=False):
- try:
- full_filename = filefind(fname, [u'.', self.ipython_dir])
- except IOError:
- self.log.warning("File not found: %r"%fname)
- return
- # Make sure that the running script gets a proper sys.argv as if it
- # were run from a system shell.
- save_argv = sys.argv
- sys.argv = [full_filename] + self.extra_args[1:]
- # protect sys.argv from potential unicode strings on Python 2:
- if not py3compat.PY3:
- sys.argv = [ py3compat.cast_bytes(a) for a in sys.argv ]
- try:
- if os.path.isfile(full_filename):
- self.log.info("Running file in user namespace: %s" %
- full_filename)
- # Ensure that __file__ is always defined to match Python
- # behavior.
- with preserve_keys(self.shell.user_ns, '__file__'):
- self.shell.user_ns['__file__'] = fname
- if full_filename.endswith('.ipy'):
- self.shell.safe_execfile_ipy(full_filename,
- shell_futures=shell_futures)
- else:
- # default to python, even without extension
- self.shell.safe_execfile(full_filename,
- self.shell.user_ns,
- shell_futures=shell_futures,
- raise_exceptions=True)
- finally:
- sys.argv = save_argv
- def _run_startup_files(self):
- """Run files from profile startup directory"""
- startup_dirs = [self.profile_dir.startup_dir] + [
- os.path.join(p, 'startup') for p in chain(ENV_CONFIG_DIRS, SYSTEM_CONFIG_DIRS)
- ]
- startup_files = []
- if self.exec_PYTHONSTARTUP and os.environ.get('PYTHONSTARTUP', False) and \
- not (self.file_to_run or self.code_to_run or self.module_to_run):
- python_startup = os.environ['PYTHONSTARTUP']
- self.log.debug("Running PYTHONSTARTUP file %s...", python_startup)
- try:
- self._exec_file(python_startup)
- except:
- self.log.warning("Unknown error in handling PYTHONSTARTUP file %s:", python_startup)
- self.shell.showtraceback()
- for startup_dir in startup_dirs[::-1]:
- startup_files += glob.glob(os.path.join(startup_dir, '*.py'))
- startup_files += glob.glob(os.path.join(startup_dir, '*.ipy'))
- if not startup_files:
- return
- self.log.debug("Running startup files from %s...", startup_dir)
- try:
- for fname in sorted(startup_files):
- self._exec_file(fname)
- except:
- self.log.warning("Unknown error in handling startup files:")
- self.shell.showtraceback()
- def _run_exec_files(self):
- """Run files from IPythonApp.exec_files"""
- if not self.exec_files:
- return
- self.log.debug("Running files in IPythonApp.exec_files...")
- try:
- for fname in self.exec_files:
- self._exec_file(fname)
- except:
- self.log.warning("Unknown error in handling IPythonApp.exec_files:")
- self.shell.showtraceback()
- def _run_cmd_line_code(self):
- """Run code or file specified at the command-line"""
- if self.code_to_run:
- line = self.code_to_run
- try:
- self.log.info("Running code given at command line (c=): %s" %
- line)
- self.shell.run_cell(line, store_history=False)
- except:
- self.log.warning("Error in executing line in user namespace: %s" %
- line)
- self.shell.showtraceback()
- if not self.interact:
- self.exit(1)
- # Like Python itself, ignore the second if the first of these is present
- elif self.file_to_run:
- fname = self.file_to_run
- if os.path.isdir(fname):
- fname = os.path.join(fname, "__main__.py")
- try:
- self._exec_file(fname, shell_futures=True)
- except:
- self.shell.showtraceback(tb_offset=4)
- if not self.interact:
- self.exit(1)
- def _run_module(self):
- """Run module specified at the command-line."""
- if self.module_to_run:
- # Make sure that the module gets a proper sys.argv as if it were
- # run using `python -m`.
- save_argv = sys.argv
- sys.argv = [sys.executable] + self.extra_args
- try:
- self.shell.safe_run_module(self.module_to_run,
- self.shell.user_ns)
- finally:
- sys.argv = save_argv
|