##// END OF EJS Templates
Continuing a massive refactor of everything.
Continuing a massive refactor of everything.

File last commit:

r2205:8ce57664
r2205:8ce57664
Show More
shell.py
274 lines | 10.2 KiB | text/x-python | PythonLexer
#!/usr/bin/env python
# encoding: utf-8
"""IPython Shell classes.
Originally, this module was horribly complicated because of the need to
use threads to integrate with GUI toolkit event loops. Now, we are using
the :mod:`IPython.lib.inputhook`, which is based on PyOS_InputHook. This
dramatically simplifies this logic and allow 3rd party packages (such as
matplotlib) to handle these things by themselves.
This new approach also allows projects like matplotlib to work interactively
in the standard python shell.
"""
#-----------------------------------------------------------------------------
# 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 sys
from IPython.core import ultratb
from IPython.core import ipapi
from IPython.utils.genutils import ask_yes_no
from IPython.core.iplib import InteractiveShell
from IPython.core.ipmaker import make_IPython
#-----------------------------------------------------------------------------
# Code
#-----------------------------------------------------------------------------
class IPShell:
"""Create an IPython instance.
This calls the factory :func:`make_IPython`, which creates a configured
:class:`InteractiveShell` object, and presents the result as a simple
class with a :meth:`mainloop` method.
"""
def __init__(self, argv=None, user_ns=None, user_global_ns=None,
debug=1, shell_class=InteractiveShell):
self.IP = make_IPython(argv, user_ns=user_ns,
user_global_ns=user_global_ns,
debug=debug, shell_class=shell_class)
def mainloop(self,sys_exit=0,banner=None):
self.IP.mainloop(banner)
if sys_exit:
sys.exit()
# This is an additional magic that is exposed in embedded shells.
def kill_embedded(self,parameter_s=''):
"""%kill_embedded : deactivate for good the current embedded IPython.
This function (after asking for confirmation) sets an internal flag so that
an embedded IPython will never activate again. This is useful to
permanently disable a shell that is being called inside a loop: once you've
figured out what you needed from it, you may then kill it and the program
will then continue to run without the interactive shell interfering again.
"""
kill = ask_yes_no("Are you sure you want to kill this embedded instance "
"(y/n)? [y/N] ",'n')
if kill:
self.shell.embedded_active = False
print "This embedded IPython will not reactivate anymore once you exit."
class IPShellEmbed:
"""Allow embedding an IPython shell into a running program.
Instances of this class are callable, with the __call__ method being an
alias to the embed() method of an InteractiveShell instance.
Usage (see also the example-embed.py file for a running example)::
ipshell = IPShellEmbed([argv,banner,exit_msg,rc_override])
* argv: list containing valid command-line options for IPython, as they
would appear in sys.argv[1:].
For example, the following command-line options::
$ ipython -prompt_in1 'Input <\\#>' -colors LightBG
would be passed in the argv list as::
['-prompt_in1','Input <\\#>','-colors','LightBG']
* banner: string which gets printed every time the interpreter starts.
* exit_msg: string which gets printed every time the interpreter exits.
* rc_override: a dict or Struct of configuration options such as those
used by IPython. These options are read from your ~/.ipython/ipythonrc
file when the Shell object is created. Passing an explicit rc_override
dict with any options you want allows you to override those values at
creation time without having to modify the file. This way you can create
embeddable instances configured in any way you want without editing any
global files (thus keeping your interactive IPython configuration
unchanged).
Then the ipshell instance can be called anywhere inside your code::
ipshell(header='') -> Opens up an IPython shell.
* header: string printed by the IPython shell upon startup. This can let
you know where in your code you are when dropping into the shell. Note
that 'banner' gets prepended to all calls, so header is used for
location-specific information.
For more details, see the __call__ method below.
When the IPython shell is exited with Ctrl-D, normal program execution
resumes.
This functionality was inspired by a posting on comp.lang.python by cmkl
<cmkleffner@gmx.de> on Dec. 06/01 concerning similar uses of pyrepl, and
by the IDL stop/continue commands.
"""
def __init__(self, argv=None, banner='', exit_msg=None,
rc_override=None, user_ns=None):
"""Note that argv here is a string, NOT a list."""
self.set_banner(banner)
self.set_exit_msg(exit_msg)
self.set_dummy_mode(0)
# sys.displayhook is a global, we need to save the user's original
# Don't rely on __displayhook__, as the user may have changed that.
self.sys_displayhook_ori = sys.displayhook
# save readline completer status
try:
#print 'Save completer',sys.ipcompleter # dbg
self.sys_ipcompleter_ori = sys.ipcompleter
except:
pass # not nested with IPython
self.IP = make_IPython(argv,rc_override=rc_override,
embedded=True,
user_ns=user_ns)
ip = self.IP
ip.define_magic("kill_embedded",kill_embedded)
# copy our own displayhook also
self.sys_displayhook_embed = sys.displayhook
# and leave the system's display hook clean
sys.displayhook = self.sys_displayhook_ori
# don't use the ipython crash handler so that user exceptions aren't
# trapped
sys.excepthook = ultratb.FormattedTB(color_scheme = self.IP.colors,
mode = self.IP.xmode,
call_pdb = self.IP.pdb)
self.restore_system_completer()
def restore_system_completer(self):
"""Restores the readline completer which was in place.
This allows embedded IPython within IPython not to disrupt the
parent's completion.
"""
try:
self.IP.readline.set_completer(self.sys_ipcompleter_ori)
sys.ipcompleter = self.sys_ipcompleter_ori
except:
pass
def __call__(self, header='', local_ns=None, global_ns=None, dummy=None):
"""Activate the interactive interpreter.
__call__(self,header='',local_ns=None,global_ns,dummy=None) -> Start
the interpreter shell with the given local and global namespaces, and
optionally print a header string at startup.
The shell can be globally activated/deactivated using the
set/get_dummy_mode methods. This allows you to turn off a shell used
for debugging globally.
However, *each* time you call the shell you can override the current
state of dummy_mode with the optional keyword parameter 'dummy'. For
example, if you set dummy mode on with IPShell.set_dummy_mode(1), you
can still have a specific call work by making it as IPShell(dummy=0).
The optional keyword parameter dummy controls whether the call
actually does anything.
"""
# If the user has turned it off, go away
if not self.IP.embedded_active:
return
# Normal exits from interactive mode set this flag, so the shell can't
# re-enter (it checks this variable at the start of interactive mode).
self.IP.exit_now = False
# Allow the dummy parameter to override the global __dummy_mode
if dummy or (dummy != 0 and self.__dummy_mode):
return
# Set global subsystems (display,completions) to our values
sys.displayhook = self.sys_displayhook_embed
if self.IP.has_readline:
self.IP.set_completer()
if self.banner and header:
format = '%s\n%s\n'
else:
format = '%s%s\n'
banner = format % (self.banner,header)
# Call the embedding code with a stack depth of 1 so it can skip over
# our call and get the original caller's namespaces.
self.IP.embed_mainloop(banner,local_ns,global_ns,stack_depth=1)
if self.exit_msg:
print self.exit_msg
# Restore global systems (display, completion)
sys.displayhook = self.sys_displayhook_ori
self.restore_system_completer()
def set_dummy_mode(self, dummy):
"""Sets the embeddable shell's dummy mode parameter.
set_dummy_mode(dummy): dummy = 0 or 1.
This parameter is persistent and makes calls to the embeddable shell
silently return without performing any action. This allows you to
globally activate or deactivate a shell you're using with a single call.
If you need to manually"""
if dummy not in [0,1,False,True]:
raise ValueError,'dummy parameter must be boolean'
self.__dummy_mode = dummy
def get_dummy_mode(self):
"""Return the current value of the dummy mode parameter.
"""
return self.__dummy_mode
def set_banner(self, banner):
"""Sets the global banner.
This banner gets prepended to every header printed when the shell
instance is called."""
self.banner = banner
def set_exit_msg(self, exit_msg):
"""Sets the global exit_msg.
This exit message gets printed upon exiting every time the embedded
shell is called. It is None by default. """
self.exit_msg = exit_msg
# This is the one which should be called by external code.
def start(user_ns = None):
"""Return a running shell instance of :class:`IPShell`."""
return IPShell(user_ns = user_ns)