409 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			409 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| # 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.
 | |
| 
 | |
| 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.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', 'YAPInteractive.autoindent',
 | |
|         'Turn on autoindenting.', 'Turn off autoindenting.'
 | |
| )
 | |
| addflag('automagic', 'YAPInteractive.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', 'YAPInteractive.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', 'YAPInteractive.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.YAPInteractive.separate_in = ''
 | |
| nosep_config.YAPInteractive.separate_out = ''
 | |
| nosep_config.YAPInteractive.separate_out2 = ''
 | |
| 
 | |
| shell_flags['nosep']=(nosep_config, "Eliminate all spacing between prompts.")
 | |
| shell_flags['pylab'] = (
 | |
|     {'YAPInteractiveApp' : {'pylab' : 'auto'}},
 | |
|     """Pre-load matplotlib and numpy for interactive use with
 | |
|     the default matplotlib backend."""
 | |
| )
 | |
| shell_flags['matplotlib'] = (
 | |
|     {'YAPInteractiveApp' : {'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='YAPInteractive.autocall',
 | |
|     colors='YAPInteractive.colors',
 | |
|     logfile='YAPInteractive.logfile',
 | |
|     logappend='YAPInteractive.logappend',
 | |
|     c='YAPInteractiveApp.code_to_run',
 | |
|     m='YAPInteractiveApp.module_to_run',
 | |
|     ext='YAPInteractiveApp.extra_extension',
 | |
|     gui='YAPInteractiveApp.gui',
 | |
|     pylab='YAPInteractiveApp.pylab',
 | |
|     matplotlib='YAPInteractiveApp.matplotlib',
 | |
| )
 | |
| shell_aliases['cache-size'] = 'YAPInteractive.cache_size'
 | |
| 
 | |
| #-----------------------------------------------------------------------------
 | |
| # Main classes and functions
 | |
| #-----------------------------------------------------------------------------
 | |
| 
 | |
| class YAPInteractiveApp(Configurable):
 | |
|     """A Mixin for applications that start YAPInteractive 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('yap_ipython.core.interactiveshell.YAPInteractiveABC',
 | |
|                      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:]
 | |
|         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
 |