##// END OF EJS Templates
Cleaner error message in crash handler.
Cleaner error message in crash handler.

File last commit:

r2392:80df84f7
r2402:ccaad9a2
Show More
ipapp.py
582 lines | 23.1 KiB | text/x-python | PythonLexer
#!/usr/bin/env python
# encoding: utf-8
"""
The :class:`~IPython.core.application.Application` object for the command
line :command:`ipython` program.
Authors:
* Brian Granger
* Fernando Perez
Notes
-----
"""
#-----------------------------------------------------------------------------
# Copyright (C) 2008-2009 The IPython Development Team
#
# Distributed under the terms of the BSD License. The full license is in
# the file COPYING, distributed as part of this software.
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
import logging
import os
import sys
from IPython.core import release
from IPython.core.application import Application, BaseAppArgParseConfigLoader
from IPython.core.error import UsageError
from IPython.core.iplib import InteractiveShell
from IPython.core.pylabtools import pylab_activate
from IPython.config.loader import (
NoConfigDefault,
Config,
PyFileConfigLoader
)
from IPython.lib import inputhook
from IPython.utils.genutils import filefind, get_ipython_dir
#-----------------------------------------------------------------------------
# Utilities and helpers
#-----------------------------------------------------------------------------
ipython_desc = """
A Python shell with automatic history (input and output), dynamic object
introspection, easier configuration, command completion, access to the system
shell and more.
"""
#-----------------------------------------------------------------------------
# Main classes and functions
#-----------------------------------------------------------------------------
cl_args = (
(('--autocall',), dict(
type=int, dest='InteractiveShell.autocall', default=NoConfigDefault,
help='Set the autocall value (0,1,2).',
metavar='InteractiveShell.autocall')
),
(('--autoindent',), dict(
action='store_true', dest='InteractiveShell.autoindent', default=NoConfigDefault,
help='Turn on autoindenting.')
),
(('--no-autoindent',), dict(
action='store_false', dest='InteractiveShell.autoindent', default=NoConfigDefault,
help='Turn off autoindenting.')
),
(('--automagic',), dict(
action='store_true', dest='InteractiveShell.automagic', default=NoConfigDefault,
help='Turn on the auto calling of magic commands.')
),
(('--no-automagic',), dict(
action='store_false', dest='InteractiveShell.automagic', default=NoConfigDefault,
help='Turn off the auto calling of magic commands.')
),
(('--autoedit-syntax',), dict(
action='store_true', dest='InteractiveShell.autoedit_syntax', default=NoConfigDefault,
help='Turn on auto editing of files with syntax errors.')
),
(('--no-autoedit-syntax',), dict(
action='store_false', dest='InteractiveShell.autoedit_syntax', default=NoConfigDefault,
help='Turn off auto editing of files with syntax errors.')
),
(('--banner',), dict(
action='store_true', dest='Global.display_banner', default=NoConfigDefault,
help='Display a banner upon starting IPython.')
),
(('--no-banner',), dict(
action='store_false', dest='Global.display_banner', default=NoConfigDefault,
help="Don't display a banner upon starting IPython.")
),
(('--cache-size',), dict(
type=int, dest='InteractiveShell.cache_size', default=NoConfigDefault,
help="Set the size of the output cache.",
metavar='InteractiveShell.cache_size')
),
(('--classic',), dict(
action='store_true', dest='Global.classic', default=NoConfigDefault,
help="Gives IPython a similar feel to the classic Python prompt.")
),
(('--colors',), dict(
type=str, dest='InteractiveShell.colors', default=NoConfigDefault,
help="Set the color scheme (NoColor, Linux, and LightBG).",
metavar='InteractiveShell.colors')
),
(('--color-info',), dict(
action='store_true', dest='InteractiveShell.color_info', default=NoConfigDefault,
help="Enable using colors for info related things.")
),
(('--no-color-info',), dict(
action='store_false', dest='InteractiveShell.color_info', default=NoConfigDefault,
help="Disable using colors for info related things.")
),
(('--confirm-exit',), dict(
action='store_true', dest='InteractiveShell.confirm_exit', default=NoConfigDefault,
help="Prompt the user when existing.")
),
(('--no-confirm-exit',), dict(
action='store_false', dest='InteractiveShell.confirm_exit', default=NoConfigDefault,
help="Don't prompt the user when existing.")
),
(('--deep-reload',), dict(
action='store_true', dest='InteractiveShell.deep_reload', default=NoConfigDefault,
help="Enable deep (recursive) reloading by default.")
),
(('--no-deep-reload',), dict(
action='store_false', dest='InteractiveShell.deep_reload', default=NoConfigDefault,
help="Disable deep (recursive) reloading by default.")
),
(('--editor',), dict(
type=str, dest='InteractiveShell.editor', default=NoConfigDefault,
help="Set the editor used by IPython (default to $EDITOR/vi/notepad).",
metavar='InteractiveShell.editor')
),
(('--log','-l'), dict(
action='store_true', dest='InteractiveShell.logstart', default=NoConfigDefault,
help="Start logging to the default file (./ipython_log.py).")
),
(('--logfile','-lf'), dict(
type=unicode, dest='InteractiveShell.logfile', default=NoConfigDefault,
help="Start logging to logfile.",
metavar='InteractiveShell.logfile')
),
(('--log-append','-la'), dict(
type=unicode, dest='InteractiveShell.logappend', default=NoConfigDefault,
help="Start logging to the give file in append mode.",
metavar='InteractiveShell.logfile')
),
(('--pdb',), dict(
action='store_true', dest='InteractiveShell.pdb', default=NoConfigDefault,
help="Enable auto calling the pdb debugger after every exception.")
),
(('--no-pdb',), dict(
action='store_false', dest='InteractiveShell.pdb', default=NoConfigDefault,
help="Disable auto calling the pdb debugger after every exception.")
),
(('--pprint',), dict(
action='store_true', dest='InteractiveShell.pprint', default=NoConfigDefault,
help="Enable auto pretty printing of results.")
),
(('--no-pprint',), dict(
action='store_false', dest='InteractiveShell.pprint', default=NoConfigDefault,
help="Disable auto auto pretty printing of results.")
),
(('--prompt-in1','-pi1'), dict(
type=str, dest='InteractiveShell.prompt_in1', default=NoConfigDefault,
help="Set the main input prompt ('In [\#]: ')",
metavar='InteractiveShell.prompt_in1')
),
(('--prompt-in2','-pi2'), dict(
type=str, dest='InteractiveShell.prompt_in2', default=NoConfigDefault,
help="Set the secondary input prompt (' .\D.: ')",
metavar='InteractiveShell.prompt_in2')
),
(('--prompt-out','-po'), dict(
type=str, dest='InteractiveShell.prompt_out', default=NoConfigDefault,
help="Set the output prompt ('Out[\#]:')",
metavar='InteractiveShell.prompt_out')
),
(('--quick',), dict(
action='store_true', dest='Global.quick', default=NoConfigDefault,
help="Enable quick startup with no config files.")
),
(('--readline',), dict(
action='store_true', dest='InteractiveShell.readline_use', default=NoConfigDefault,
help="Enable readline for command line usage.")
),
(('--no-readline',), dict(
action='store_false', dest='InteractiveShell.readline_use', default=NoConfigDefault,
help="Disable readline for command line usage.")
),
(('--screen-length','-sl'), dict(
type=int, dest='InteractiveShell.screen_length', default=NoConfigDefault,
help='Number of lines on screen, used to control printing of long strings.',
metavar='InteractiveShell.screen_length')
),
(('--separate-in','-si'), dict(
type=str, dest='InteractiveShell.separate_in', default=NoConfigDefault,
help="Separator before input prompts. Default '\n'.",
metavar='InteractiveShell.separate_in')
),
(('--separate-out','-so'), dict(
type=str, dest='InteractiveShell.separate_out', default=NoConfigDefault,
help="Separator before output prompts. Default 0 (nothing).",
metavar='InteractiveShell.separate_out')
),
(('--separate-out2','-so2'), dict(
type=str, dest='InteractiveShell.separate_out2', default=NoConfigDefault,
help="Separator after output prompts. Default 0 (nonight).",
metavar='InteractiveShell.separate_out2')
),
(('-no-sep',), dict(
action='store_true', dest='Global.nosep', default=NoConfigDefault,
help="Eliminate all spacing between prompts.")
),
(('--term-title',), dict(
action='store_true', dest='InteractiveShell.term_title', default=NoConfigDefault,
help="Enable auto setting the terminal title.")
),
(('--no-term-title',), dict(
action='store_false', dest='InteractiveShell.term_title', default=NoConfigDefault,
help="Disable auto setting the terminal title.")
),
(('--xmode',), dict(
type=str, dest='InteractiveShell.xmode', default=NoConfigDefault,
help="Exception mode ('Plain','Context','Verbose')",
metavar='InteractiveShell.xmode')
),
(('--ext',), dict(
type=str, dest='Global.extra_extension', default=NoConfigDefault,
help="The dotted module name of an IPython extension to load.",
metavar='Global.extra_extension')
),
(('-c',), dict(
type=str, dest='Global.code_to_run', default=NoConfigDefault,
help="Execute the given command string.",
metavar='Global.code_to_run')
),
(('-i',), dict(
action='store_true', dest='Global.force_interact', default=NoConfigDefault,
help="If running code from the command line, become interactive afterwards.")
),
# Options to start with GUI control enabled from the beginning
(('--gui',), dict(
type=str, dest='Global.gui', default=NoConfigDefault,
help="Enable GUI event loop integration ('qt', 'wx', 'gtk').",
metavar='gui-mode')
),
(('--pylab','-pylab'), dict(
type=str, dest='Global.pylab', default=NoConfigDefault,
nargs='?', const='auto', metavar='gui-mode',
help="Pre-load matplotlib and numpy for interactive use. "+
"If no value is given, the gui backend is matplotlib's, else use "+
"one of: ['tk', 'qt', 'wx', 'gtk'].")
),
# Legacy GUI options. Leave them in for backwards compatibility, but the
# 'thread' names are really a misnomer now.
(('--wthread','-wthread'), dict(
action='store_true', dest='Global.wthread', default=NoConfigDefault,
help="Enable wxPython event loop integration "+
"(DEPRECATED, use --gui wx)")
),
(('--q4thread','--qthread','-q4thread','-qthread'), dict(
action='store_true', dest='Global.q4thread', default=NoConfigDefault,
help="Enable Qt4 event loop integration. Qt3 is no longer supported. "+
"(DEPRECATED, use --gui qt)")
),
(('--gthread','-gthread'), dict(
action='store_true', dest='Global.gthread', default=NoConfigDefault,
help="Enable GTK event loop integration. "+
"(DEPRECATED, use --gui gtk)")
),
)
class IPythonAppCLConfigLoader(BaseAppArgParseConfigLoader):
arguments = cl_args
default_config_file_name = u'ipython_config.py'
class IPythonApp(Application):
name = u'ipython'
description = 'IPython: an enhanced interactive Python shell.'
config_file_name = default_config_file_name
def __init__(self, argv=None, **shell_params):
"""Create a new IPythonApp.
Parameters
----------
argv : optional, list
If given, used as the command-line argv environment to read arguments
from.
shell_params : optional, dict
All other keywords are passed to the :class:`iplib.InteractiveShell`
constructor.
"""
super(IPythonApp, self).__init__(argv)
self.shell_params = shell_params
def create_default_config(self):
super(IPythonApp, self).create_default_config()
# Eliminate multiple lookups
Global = self.default_config.Global
# Set all default values
Global.display_banner = True
# If the -c flag is given or a file is given to run at the cmd line
# like "ipython foo.py", normally we exit without starting the main
# loop. The force_interact config variable allows a user to override
# this and interact. It is also set by the -i cmd line flag, just
# like Python.
Global.force_interact = False
# By default always interact by starting the IPython mainloop.
Global.interact = True
# No GUI integration by default
Global.gui = False
# Pylab off by default
Global.pylab = False
# Deprecated versions of gui support that used threading, we support
# them just for bacwards compatibility as an alternate spelling for
# '--gui X'
Global.qthread = False
Global.q4thread = False
Global.wthread = False
Global.gthread = False
def create_command_line_config(self):
"""Create and return a command line config loader."""
return IPythonAppCLConfigLoader(self.argv,
description=self.description,
version=release.version
)
def load_file_config(self):
if hasattr(self.command_line_config.Global, 'quick'):
if self.command_line_config.Global.quick:
self.file_config = Config()
return
super(IPythonApp, self).load_file_config()
def post_load_file_config(self):
if hasattr(self.command_line_config.Global, 'extra_extension'):
if not hasattr(self.file_config.Global, 'extensions'):
self.file_config.Global.extensions = []
self.file_config.Global.extensions.append(
self.command_line_config.Global.extra_extension)
del self.command_line_config.Global.extra_extension
def pre_construct(self):
config = self.master_config
if hasattr(config.Global, 'classic'):
if config.Global.classic:
config.InteractiveShell.cache_size = 0
config.InteractiveShell.pprint = 0
config.InteractiveShell.prompt_in1 = '>>> '
config.InteractiveShell.prompt_in2 = '... '
config.InteractiveShell.prompt_out = ''
config.InteractiveShell.separate_in = \
config.InteractiveShell.separate_out = \
config.InteractiveShell.separate_out2 = ''
config.InteractiveShell.colors = 'NoColor'
config.InteractiveShell.xmode = 'Plain'
if hasattr(config.Global, 'nosep'):
if config.Global.nosep:
config.InteractiveShell.separate_in = \
config.InteractiveShell.separate_out = \
config.InteractiveShell.separate_out2 = ''
# if there is code of files to run from the cmd line, don't interact
# unless the -i flag (Global.force_interact) is true.
code_to_run = config.Global.get('code_to_run','')
file_to_run = False
if len(self.extra_args)>=1:
if self.extra_args[0]:
file_to_run = True
if file_to_run or code_to_run:
if not config.Global.force_interact:
config.Global.interact = False
def construct(self):
# I am a little hesitant to put these into InteractiveShell itself.
# But that might be the place for them
sys.path.insert(0, '')
# Create an InteractiveShell instance
self.shell = InteractiveShell(None, self.master_config,
**self.shell_params )
def post_construct(self):
"""Do actions after construct, but before starting the app."""
config = self.master_config
# shell.display_banner should always be False for the terminal
# based app, because we call shell.show_banner() by hand below
# so the banner shows *before* all extension loading stuff.
self.shell.display_banner = False
if config.Global.display_banner and \
config.Global.interact:
self.shell.show_banner()
# Make sure there is a space below the banner.
if self.log_level <= logging.INFO: print
# Now a variety of things that happen after the banner is printed.
self._enable_gui_pylab()
self._load_extensions()
self._run_exec_lines()
self._run_exec_files()
self._run_cmd_line_code()
self._configure_xmode()
def _enable_gui_pylab(self):
"""Enable GUI event loop integration, taking pylab into account."""
Global = self.master_config.Global
# Select which gui to use
if Global.gui:
gui = Global.gui
# The following are deprecated, but there's likely to be a lot of use
# of this form out there, so we might as well support it for now. But
# the --gui option above takes precedence.
elif Global.wthread:
gui = inputhook.GUI_WX
elif Global.qthread:
gui = inputhook.GUI_QT
elif Global.gthread:
gui = inputhook.GUI_GTK
else:
gui = None
# Using --pylab will also require gui activation, though which toolkit
# to use may be chosen automatically based on mpl configuration.
if Global.pylab:
activate = self.shell.enable_pylab
if Global.pylab == 'auto':
gui = None
else:
gui = Global.pylab
else:
# Enable only GUI integration, no pylab
activate = inputhook.enable_gui
if gui or Global.pylab:
try:
self.log.info("Enabling GUI event loop integration, "
"toolkit=%s, pylab=%s" % (gui, Global.pylab) )
activate(gui)
except:
self.log.warn("Error in enabling GUI event loop integration:")
self.shell.showtraceback()
def _load_extensions(self):
"""Load all IPython extensions in Global.extensions.
This uses the :meth:`InteractiveShell.load_extensions` to load all
the extensions listed in ``self.master_config.Global.extensions``.
"""
try:
if hasattr(self.master_config.Global, 'extensions'):
self.log.debug("Loading IPython extensions...")
extensions = self.master_config.Global.extensions
for ext in extensions:
try:
self.log.info("Loading IPython extension: %s" % ext)
self.shell.load_extension(ext)
except:
self.log.warn("Error in loading extension: %s" % ext)
self.shell.showtraceback()
except:
self.log.warn("Unknown error in loading extensions:")
self.shell.showtraceback()
def _run_exec_lines(self):
"""Run lines of code in Global.exec_lines in the user's namespace."""
try:
if hasattr(self.master_config.Global, 'exec_lines'):
self.log.debug("Running code from Global.exec_lines...")
exec_lines = self.master_config.Global.exec_lines
for line in exec_lines:
try:
self.log.info("Running code in user namespace: %s" % line)
self.shell.runlines(line)
except:
self.log.warn("Error in executing line in user namespace: %s" % line)
self.shell.showtraceback()
except:
self.log.warn("Unknown error in handling Global.exec_lines:")
self.shell.showtraceback()
def _exec_file(self, fname):
full_filename = filefind(fname, [u'.', self.ipython_dir])
if os.path.isfile(full_filename):
if full_filename.endswith(u'.py'):
self.log.info("Running file in user namespace: %s" % full_filename)
self.shell.safe_execfile(full_filename, self.shell.user_ns)
elif full_filename.endswith('.ipy'):
self.log.info("Running file in user namespace: %s" % full_filename)
self.shell.safe_execfile_ipy(full_filename)
else:
self.log.warn("File does not have a .py or .ipy extension: <%s>" % full_filename)
def _run_exec_files(self):
try:
if hasattr(self.master_config.Global, 'exec_files'):
self.log.debug("Running files in Global.exec_files...")
exec_files = self.master_config.Global.exec_files
for fname in exec_files:
self._exec_file(fname)
except:
self.log.warn("Unknown error in handling Global.exec_files:")
self.shell.showtraceback()
def _run_cmd_line_code(self):
if hasattr(self.master_config.Global, 'code_to_run'):
line = self.master_config.Global.code_to_run
try:
self.log.info("Running code given at command line (-c): %s" % line)
self.shell.runlines(line)
except:
self.log.warn("Error in executing line in user namespace: %s" % line)
self.shell.showtraceback()
return
# Like Python itself, ignore the second if the first of these is present
try:
fname = self.extra_args[0]
except:
pass
else:
try:
self._exec_file(fname)
except:
self.log.warn("Error in executing file in user namespace: %s" % fname)
self.shell.showtraceback()
def _configure_xmode(self):
# XXX - shouldn't this be read from the config? I'm still a little
# lost with all the details of handling the new config guys...
self.shell.InteractiveTB.set_mode(mode=self.shell.xmode)
def start_app(self):
if self.master_config.Global.interact:
self.log.debug("Starting IPython's mainloop...")
self.shell.mainloop()
else:
self.log.debug("IPython not interactive, start_app is no-op...")
def load_default_config(ipython_dir=None):
"""Load the default config file from the default ipython_dir.
This is useful for embedded shells.
"""
if ipython_dir is None:
ipython_dir = get_ipython_dir()
cl = PyFileConfigLoader(default_config_file_name, ipython_dir)
config = cl.load_config()
return config
def launch_new_instance():
"""Create and run a full blown IPython instance"""
app = IPythonApp()
app.start()