shellapp.py
441 lines
| 17.2 KiB
| text/x-python
|
PythonLexer
MinRK
|
r3968 | # encoding: utf-8 | ||
""" | ||||
MinRK
|
r4023 | A mixin for :class:`~IPython.core.application.Application` classes that | ||
MinRK
|
r3968 | launch InteractiveShell instances, load extensions, etc. | ||
""" | ||||
Min RK
|
r20628 | # Copyright (c) IPython Development Team. | ||
# Distributed under the terms of the Modified BSD License. | ||||
MinRK
|
r3968 | |||
MinRK
|
r5246 | import glob | ||
Min RK
|
r23760 | from itertools import chain | ||
MinRK
|
r3968 | import os | ||
import sys | ||||
Min RK
|
r21253 | from traitlets.config.application import boolean_flag | ||
from traitlets.config.configurable import Configurable | ||||
from traitlets.config.loader import Config | ||||
Min RK
|
r23760 | from IPython.core.application import SYSTEM_CONFIG_DIRS, ENV_CONFIG_DIRS | ||
Bradley M. Froehle
|
r7096 | from IPython.core import pylabtools | ||
Bradley M. Froehle
|
r8529 | from IPython.utils.contexts import preserve_keys | ||
MinRK
|
r3968 | from IPython.utils.path import filefind | ||
Min RK
|
r21253 | from traitlets import ( | ||
Matthias Bussonnier
|
r22359 | Unicode, Instance, List, Bool, CaselessStrEnum, observe, | ||
Bradley M. Froehle
|
r7096 | ) | ||
Min RK
|
r22742 | from IPython.terminal import pt_inputhooks | ||
MinRK
|
r3968 | |||
#----------------------------------------------------------------------------- | ||||
# Aliases and Flags | ||||
#----------------------------------------------------------------------------- | ||||
Min RK
|
r22742 | gui_keys = tuple(sorted(pt_inputhooks.backends) + sorted(pt_inputhooks.aliases)) | ||
MinRK
|
r12363 | |||
MinRK
|
r11541 | backend_keys = sorted(pylabtools.backends.keys()) | ||
backend_keys.insert(0, 'auto') | ||||
MinRK
|
r3968 | 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.", | ||||
Kyle Kelley
|
r11884 | "Disable auto pretty printing of results." | ||
MinRK
|
r3968 | ) | ||
addflag('color-info', 'InteractiveShell.color_info', | ||||
Thomas Kluyver
|
r20347 | """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.""", | ||||
MinRK
|
r3968 | "Disable using colors for info related things." | ||
) | ||||
Nathan Goldbaum
|
r25495 | addflag('ignore-cwd', 'InteractiveShellApp.ignore_cwd', | ||
"Exclude the current working directory from sys.path", | ||||
"Include the current working directory in sys.path", | ||||
) | ||||
MinRK
|
r4021 | 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.") | ||||
Bradley M. Froehle
|
r7096 | shell_flags['pylab'] = ( | ||
{'InteractiveShellApp' : {'pylab' : 'auto'}}, | ||||
"""Pre-load matplotlib and numpy for interactive use with | ||||
the default matplotlib backend.""" | ||||
) | ||||
MinRK
|
r11534 | shell_flags['matplotlib'] = ( | ||
{'InteractiveShellApp' : {'matplotlib' : 'auto'}}, | ||||
"""Configure matplotlib for interactive use with | ||||
the default matplotlib backend.""" | ||||
) | ||||
MinRK
|
r3968 | |||
# 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', | ||||
MinRK
|
r4189 | logappend='InteractiveShell.logappend', | ||
MinRK
|
r3968 | c='InteractiveShellApp.code_to_run', | ||
Bradley M. Froehle
|
r6029 | m='InteractiveShellApp.module_to_run', | ||
MinRK
|
r3968 | ext='InteractiveShellApp.extra_extension', | ||
Bradley M. Froehle
|
r7096 | gui='InteractiveShellApp.gui', | ||
pylab='InteractiveShellApp.pylab', | ||||
MinRK
|
r11534 | matplotlib='InteractiveShellApp.matplotlib', | ||
MinRK
|
r3968 | ) | ||
MinRK
|
r4214 | shell_aliases['cache-size'] = 'InteractiveShell.cache_size' | ||
MinRK
|
r3968 | |||
#----------------------------------------------------------------------------- | ||||
# Main classes and functions | ||||
#----------------------------------------------------------------------------- | ||||
class InteractiveShellApp(Configurable): | ||||
"""A Mixin for applications that start InteractiveShell instances. | ||||
The-Penultimate-Defenestrator
|
r22733 | |||
MinRK
|
r3968 | Provides configurables for loading extensions and executing files | ||
as part of configuring a Shell environment. | ||||
Bradley M. Froehle
|
r6695 | |||
Bradley M. Froehle
|
r7096 | 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` | ||||
MinRK
|
r3968 | """ | ||
Min RK
|
r22340 | extensions = List(Unicode(), | ||
MinRK
|
r3968 | help="A list of dotted module names of IPython extensions to load." | ||
Min RK
|
r22340 | ).tag(config=True) | ||
extra_extension = Unicode('', | ||||
MinRK
|
r3968 | help="dotted module name of an IPython extension to load." | ||
Min RK
|
r22340 | ).tag(config=True) | ||
Scott Sanderson
|
r20642 | |||
Min RK
|
r22340 | reraise_ipython_extension_failures = Bool(False, | ||
Scott Sanderson
|
r20643 | help="Reraise exceptions encountered loading IPython extensions?", | ||
Min RK
|
r22340 | ).tag(config=True) | ||
Scott Sanderson
|
r20642 | |||
Thomas Kluyver
|
r5542 | # Extensions that are always loaded (not configurable) | ||
Min RK
|
r22340 | default_extensions = List(Unicode(), [u'storemagic']).tag(config=False) | ||
The-Penultimate-Defenestrator
|
r22733 | |||
Min RK
|
r22340 | hide_initial_ns = Bool(True, | ||
MinRK
|
r13616 | help="""Should variables loaded at startup (by startup files, exec_lines, etc.) | ||
be hidden from tools like %who?""" | ||||
Min RK
|
r22340 | ).tag(config=True) | ||
MinRK
|
r3968 | |||
Min RK
|
r22340 | exec_files = List(Unicode(), | ||
MinRK
|
r3968 | help="""List of files to run at IPython startup.""" | ||
Min RK
|
r22340 | ).tag(config=True) | ||
exec_PYTHONSTARTUP = Bool(True, | ||||
Thomas Kluyver
|
r13713 | help="""Run the file referenced by the PYTHONSTARTUP environment | ||
variable at IPython startup.""" | ||||
Min RK
|
r22340 | ).tag(config=True) | ||
file_to_run = Unicode('', | ||||
help="""A file to be run""").tag(config=True) | ||||
MinRK
|
r3968 | |||
Min RK
|
r22340 | exec_lines = List(Unicode(), | ||
MinRK
|
r3968 | help="""lines of code to run at IPython startup.""" | ||
Min RK
|
r22340 | ).tag(config=True) | ||
code_to_run = Unicode('', | ||||
MinRK
|
r3968 | help="Execute the given command string." | ||
Min RK
|
r22340 | ).tag(config=True) | ||
module_to_run = Unicode('', | ||||
Bradley M. Froehle
|
r6029 | help="Run the module as a script." | ||
Min RK
|
r22340 | ).tag(config=True) | ||
gui = CaselessStrEnum(gui_keys, allow_none=True, | ||||
MinRK
|
r12363 | help="Enable GUI event loop integration with any of {0}.".format(gui_keys) | ||
Min RK
|
r22340 | ).tag(config=True) | ||
Sylvain Corlay
|
r20480 | matplotlib = CaselessStrEnum(backend_keys, allow_none=True, | ||
MinRK
|
r11534 | help="""Configure matplotlib for interactive use with | ||
the default matplotlib backend.""" | ||||
Min RK
|
r22340 | ).tag(config=True) | ||
Sylvain Corlay
|
r20480 | pylab = CaselessStrEnum(backend_keys, allow_none=True, | ||
Bradley M. Froehle
|
r7096 | help="""Pre-load matplotlib and numpy for interactive use, | ||
selecting a particular matplotlib backend and loop integration. | ||||
""" | ||||
Min RK
|
r22340 | ).tag(config=True) | ||
pylab_import_all = Bool(True, | ||||
MinRK
|
r11327 | help="""If true, IPython will populate the user namespace with numpy, pylab, etc. | ||
Thomas Kluyver
|
r13504 | and an ``import *`` is done from numpy and pylab, when using pylab mode. | ||
The-Penultimate-Defenestrator
|
r22733 | |||
MinRK
|
r11327 | When False, pylab mode should not import any names into the user namespace. | ||
""" | ||||
Min RK
|
r22340 | ).tag(config=True) | ||
Nathan Goldbaum
|
r25495 | ignore_cwd = Bool( | ||
False, | ||||
help="""If True, IPython will not add the current working directory to sys.path. | ||||
When False, the current working directory is added to sys.path, allowing imports | ||||
of modules defined in the current directory.""" | ||||
).tag(config=True) | ||||
Sylvain Corlay
|
r20940 | shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', | ||
allow_none=True) | ||||
Min RK
|
r22069 | # whether interact-loop should start | ||
interact = Bool(True) | ||||
The-Penultimate-Defenestrator
|
r22733 | |||
Thomas Kluyver
|
r12476 | user_ns = Instance(dict, args=None, allow_none=True) | ||
Min RK
|
r22340 | @observe('user_ns') | ||
def _user_ns_changed(self, change): | ||||
Thomas Kluyver
|
r12163 | if self.shell is not None: | ||
Min RK
|
r22340 | self.shell.user_ns = change['new'] | ||
Thomas Kluyver
|
r12163 | self.shell.init_user_ns() | ||
MinRK
|
r3968 | |||
Bradley M. Froehle
|
r6695 | def init_path(self): | ||
Min RK
|
r24840 | """Add current working directory, '', to sys.path | ||
Unlike Python's default, we insert before the first `site-packages` | ||||
or `dist-packages` directory, | ||||
so that it is after the standard library. | ||||
.. versionchanged:: 7.2 | ||||
Try to insert after the standard library, instead of first. | ||||
Nathan Goldbaum
|
r25495 | .. versionchanged:: 8.0 | ||
Allow optionally not including the current directory in sys.path | ||||
Min RK
|
r24840 | """ | ||
Nathan Goldbaum
|
r25495 | if '' in sys.path or self.ignore_cwd: | ||
Min RK
|
r24840 | return | ||
for idx, path in enumerate(sys.path): | ||||
parent, last_part = os.path.split(path) | ||||
if last_part in {'site-packages', 'dist-packages'}: | ||||
break | ||||
else: | ||||
# no site-packages or dist-packages found (?!) | ||||
# back to original behavior of inserting at the front | ||||
idx = 0 | ||||
sys.path.insert(idx, '') | ||||
Bradley M. Froehle
|
r6695 | |||
MinRK
|
r3968 | def init_shell(self): | ||
raise NotImplementedError("Override in subclasses") | ||||
Bradley M. Froehle
|
r7096 | |||
def init_gui_pylab(self): | ||||
"""Enable GUI event loop integration, taking pylab into account.""" | ||||
MinRK
|
r11534 | enable = False | ||
shell = self.shell | ||||
if self.pylab: | ||||
MinRK
|
r12230 | enable = lambda key: shell.enable_pylab(key, import_all=self.pylab_import_all) | ||
MinRK
|
r11534 | key = self.pylab | ||
elif self.matplotlib: | ||||
enable = shell.enable_matplotlib | ||||
key = self.matplotlib | ||||
elif self.gui: | ||||
enable = shell.enable_gui | ||||
key = self.gui | ||||
The-Penultimate-Defenestrator
|
r22733 | |||
MinRK
|
r11534 | if not enable: | ||
return | ||||
The-Penultimate-Defenestrator
|
r22733 | |||
MinRK
|
r11534 | try: | ||
r = enable(key) | ||||
except ImportError: | ||||
Pierre Gerold
|
r21888 | self.log.warning("Eventloop or matplotlib integration failed. Is matplotlib installed?") | ||
MinRK
|
r11534 | self.shell.showtraceback() | ||
return | ||||
except Exception: | ||||
Pierre Gerold
|
r21888 | self.log.warning("GUI event loop or pylab initialization failed") | ||
MinRK
|
r11534 | self.shell.showtraceback() | ||
return | ||||
The-Penultimate-Defenestrator
|
r22733 | |||
MinRK
|
r11534 | 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": | ||||
Thomas Kluyver
|
r13386 | print("Using matplotlib backend: %s" % backend) | ||
MinRK
|
r11534 | else: | ||
gui = r | ||||
self.log.info("Enabling GUI event loop integration, " | ||||
"eventloop=%s", gui) | ||||
Bradley M. Froehle
|
r7096 | |||
MinRK
|
r3968 | 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...") | ||||
Thomas Kluyver
|
r5542 | extensions = self.default_extensions + self.extensions | ||
Min RK
|
r20628 | if self.extra_extension: | ||
extensions.append(self.extra_extension) | ||||
MinRK
|
r3968 | for ext in extensions: | ||
try: | ||||
self.log.info("Loading IPython extension: %s" % ext) | ||||
self.shell.extension_manager.load_extension(ext) | ||||
except: | ||||
Scott Sanderson
|
r20643 | if self.reraise_ipython_extension_failures: | ||
Scott Sanderson
|
r20642 | raise | ||
Scott Sanderson
|
r19418 | msg = ("Error in loading extension: {ext}\n" | ||
"Check your config files in {location}".format( | ||||
ext=ext, | ||||
location=self.profile_dir.location | ||||
)) | ||||
Pierre Gerold
|
r21888 | self.log.warning(msg, exc_info=True) | ||
MinRK
|
r3968 | except: | ||
Scott Sanderson
|
r20643 | if self.reraise_ipython_extension_failures: | ||
Scott Sanderson
|
r20642 | raise | ||
Pierre Gerold
|
r21888 | self.log.warning("Unknown error in loading extensions:", exc_info=True) | ||
MinRK
|
r3968 | |||
def init_code(self): | ||||
"""run the pre-flight code, specified via exec_lines""" | ||||
MinRK
|
r5246 | self._run_startup_files() | ||
MinRK
|
r3968 | self._run_exec_lines() | ||
self._run_exec_files() | ||||
The-Penultimate-Defenestrator
|
r22733 | |||
MinRK
|
r13623 | # Hide variables defined here from %who etc. | ||
if self.hide_initial_ns: | ||||
self.shell.user_ns_hidden.update(self.shell.user_ns) | ||||
The-Penultimate-Defenestrator
|
r22733 | |||
MinRK
|
r13623 | # command-line execution (ipython -i script.py, ipython -m module) | ||
# should *not* be excluded from %whos | ||||
MinRK
|
r3968 | self._run_cmd_line_code() | ||
Bradley M. Froehle
|
r6029 | self._run_module() | ||
The-Penultimate-Defenestrator
|
r22733 | |||
MinRK
|
r5802 | # flush output, so itwon't be attached to the first cell | ||
sys.stdout.flush() | ||||
sys.stderr.flush() | ||||
MinRK
|
r3968 | |||
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: | ||||
Pierre Gerold
|
r21888 | self.log.warning("Error in executing line in user " | ||
MinRK
|
r3968 | "namespace: %s" % line) | ||
self.shell.showtraceback() | ||||
except: | ||||
Pierre Gerold
|
r21888 | self.log.warning("Unknown error in handling IPythonApp.exec_lines:") | ||
MinRK
|
r3968 | self.shell.showtraceback() | ||
Thomas Ballinger
|
r18526 | def _exec_file(self, fname, shell_futures=False): | ||
MinRK
|
r4203 | try: | ||
full_filename = filefind(fname, [u'.', self.ipython_dir]) | ||||
Matthias Bussonnier
|
r22359 | except IOError: | ||
Pierre Gerold
|
r21888 | self.log.warning("File not found: %r"%fname) | ||
MinRK
|
r4203 | return | ||
MinRK
|
r4189 | # Make sure that the running script gets a proper sys.argv as if it | ||
# were run from a system shell. | ||||
save_argv = sys.argv | ||||
MinRK
|
r4203 | sys.argv = [full_filename] + self.extra_args[1:] | ||
MinRK
|
r4189 | try: | ||
if os.path.isfile(full_filename): | ||||
Bradley M. Froehle
|
r8529 | 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__'): | ||||
Bradley M. Froehle
|
r8483 | self.shell.user_ns['__file__'] = fname | ||
Tony Fast
|
r24890 | if full_filename.endswith('.ipy') or full_filename.endswith('.ipynb'): | ||
Thomas Ballinger
|
r18526 | self.shell.safe_execfile_ipy(full_filename, | ||
shell_futures=shell_futures) | ||||
Bradley M. Froehle
|
r8529 | else: | ||
# default to python, even without extension | ||||
self.shell.safe_execfile(full_filename, | ||||
Thomas Ballinger
|
r18526 | self.shell.user_ns, | ||
Fairly
|
r21758 | shell_futures=shell_futures, | ||
raise_exceptions=True) | ||||
MinRK
|
r4189 | finally: | ||
sys.argv = save_argv | ||||
MinRK
|
r3968 | |||
MinRK
|
r5246 | def _run_startup_files(self): | ||
"""Run files from profile startup directory""" | ||||
Min RK
|
r23760 | startup_dirs = [self.profile_dir.startup_dir] + [ | ||
os.path.join(p, 'startup') for p in chain(ENV_CONFIG_DIRS, SYSTEM_CONFIG_DIRS) | ||||
] | ||||
MinRK
|
r11231 | startup_files = [] | ||
The-Penultimate-Defenestrator
|
r22733 | |||
MinRK
|
r16252 | 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: | ||||
Pierre Gerold
|
r21888 | self.log.warning("Unknown error in handling PYTHONSTARTUP file %s:", python_startup) | ||
MinRK
|
r16252 | self.shell.showtraceback() | ||
Min RK
|
r23760 | 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')) | ||||
MinRK
|
r5246 | if not startup_files: | ||
return | ||||
The-Penultimate-Defenestrator
|
r22733 | |||
MinRK
|
r5246 | self.log.debug("Running startup files from %s...", startup_dir) | ||
try: | ||||
for fname in sorted(startup_files): | ||||
self._exec_file(fname) | ||||
except: | ||||
Pierre Gerold
|
r21888 | self.log.warning("Unknown error in handling startup files:") | ||
MinRK
|
r5246 | self.shell.showtraceback() | ||
MinRK
|
r3968 | 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: | ||||
Pierre Gerold
|
r21888 | self.log.warning("Unknown error in handling IPythonApp.exec_files:") | ||
MinRK
|
r3968 | 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: | ||||
Pierre Gerold
|
r21888 | self.log.warning("Error in executing line in user namespace: %s" % | ||
MinRK
|
r3968 | line) | ||
self.shell.showtraceback() | ||||
Min RK
|
r22070 | if not self.interact: | ||
self.exit(1) | ||||
MinRK
|
r3968 | |||
# Like Python itself, ignore the second if the first of these is present | ||||
elif self.file_to_run: | ||||
fname = self.file_to_run | ||||
The-Penultimate-Defenestrator
|
r22733 | if os.path.isdir(fname): | ||
fname = os.path.join(fname, "__main__.py") | ||||
Jeff Potter
|
r25414 | if not os.path.exists(fname): | ||
self.log.warning("File '%s' doesn't exist", fname) | ||||
Quentin Peter
|
r25664 | if not self.interact: | ||
self.exit(2) | ||||
MinRK
|
r3968 | try: | ||
Thomas Ballinger
|
r18526 | self._exec_file(fname, shell_futures=True) | ||
MinRK
|
r3968 | except: | ||
Fairly
|
r21758 | self.shell.showtraceback(tb_offset=4) | ||
Min RK
|
r22070 | if not self.interact: | ||
self.exit(1) | ||||
MinRK
|
r3968 | |||
Bradley M. Froehle
|
r6029 | def _run_module(self): | ||
"""Run module specified at the command-line.""" | ||||
if self.module_to_run: | ||||
Bradley M. Froehle
|
r6034 | # 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 | ||||