embed.py
283 lines
| 10.7 KiB
| text/x-python
|
PythonLexer
Brian Granger
|
r2206 | # encoding: utf-8 | ||
""" | ||||
An embedded IPython shell. | ||||
Authors: | ||||
* Brian Granger | ||||
* Fernando Perez | ||||
Notes | ||||
----- | ||||
""" | ||||
#----------------------------------------------------------------------------- | ||||
Matthias BUSSONNIER
|
r5390 | # Copyright (C) 2008-2011 The IPython Development Team | ||
Brian Granger
|
r2206 | # | ||
# Distributed under the terms of the BSD License. The full license is in | ||||
# the file COPYING, distributed as part of this software. | ||||
#----------------------------------------------------------------------------- | ||||
#----------------------------------------------------------------------------- | ||||
# Imports | ||||
#----------------------------------------------------------------------------- | ||||
Brian Granger
|
r2227 | from __future__ import with_statement | ||
Brian Granger
|
r2206 | import sys | ||
Thomas Kluyver
|
r5675 | import warnings | ||
Brian Granger
|
r2206 | |||
Fernando Perez
|
r6987 | # We need to use nested to support python 2.6, once we move to >=2.7, we can | ||
# use the with keyword's new builtin support for nested managers | ||||
try: | ||||
from contextlib import nested | ||||
except: | ||||
from IPython.utils.nested_context import nested | ||||
Brian Granger
|
r2206 | from IPython.core import ultratb | ||
Fernando Perez
|
r6973 | from IPython.core.magic import Magics, magics_class, line_magic | ||
Brian Granger
|
r2761 | from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell | ||
Brian Granger
|
r2760 | from IPython.frontend.terminal.ipapp import load_default_config | ||
Brian Granger
|
r2206 | |||
Thomas Kluyver
|
r4046 | from IPython.utils.traitlets import Bool, CBool, Unicode | ||
Brian Granger
|
r2498 | from IPython.utils.io import ask_yes_no | ||
Brian Granger
|
r2206 | |||
Brian Granger
|
r2245 | |||
Brian Granger
|
r2206 | #----------------------------------------------------------------------------- | ||
# Classes and functions | ||||
#----------------------------------------------------------------------------- | ||||
# This is an additional magic that is exposed in embedded shells. | ||||
Fernando Perez
|
r6973 | @magics_class | ||
Fernando Perez
|
r6941 | class EmbeddedMagics(Magics): | ||
Brian Granger
|
r2206 | |||
Fernando Perez
|
r6941 | @line_magic | ||
def kill_embedded(self, parameter_s=''): | ||||
"""%kill_embedded : deactivate for good the current embedded IPython. | ||||
Bernardo B. Marques
|
r4872 | |||
Fernando Perez
|
r6941 | 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.") | ||||
Brian Granger
|
r2206 | |||
Brian Granger
|
r2761 | class InteractiveShellEmbed(TerminalInteractiveShell): | ||
Brian Granger
|
r2206 | |||
dummy_mode = Bool(False) | ||||
MinRK
|
r3464 | exit_msg = Unicode('') | ||
Brian Granger
|
r2226 | embedded = CBool(True) | ||
embedded_active = CBool(True) | ||||
Brian Granger
|
r2252 | # Like the base class display_banner is not configurable, but here it | ||
# is True by default. | ||||
display_banner = CBool(True) | ||||
Brian Granger
|
r2206 | |||
Brian Granger
|
r2761 | def __init__(self, config=None, ipython_dir=None, user_ns=None, | ||
Thomas Kluyver
|
r5459 | user_module=None, custom_exceptions=((),None), | ||
Brian Granger
|
r2761 | usage=None, banner1=None, banner2=None, | ||
Thomas Kluyver
|
r5676 | display_banner=None, exit_msg=u'', user_global_ns=None): | ||
if user_global_ns is not None: | ||||
warnings.warn("user_global_ns has been replaced by user_module. The\ | ||||
parameter will be ignored.", DeprecationWarning) | ||||
Brian Granger
|
r2206 | |||
super(InteractiveShellEmbed,self).__init__( | ||||
Brian Granger
|
r2761 | config=config, ipython_dir=ipython_dir, user_ns=user_ns, | ||
Thomas Kluyver
|
r5459 | user_module=user_module, custom_exceptions=custom_exceptions, | ||
Brian Granger
|
r2761 | usage=usage, banner1=banner1, banner2=banner2, | ||
display_banner=display_banner | ||||
) | ||||
Brian Granger
|
r2206 | |||
self.exit_msg = exit_msg | ||||
# don't use the ipython crash handler so that user exceptions aren't | ||||
# trapped | ||||
Brian Granger
|
r2226 | sys.excepthook = ultratb.FormattedTB(color_scheme=self.colors, | ||
mode=self.xmode, | ||||
call_pdb=self.pdb) | ||||
Brian Granger
|
r2206 | |||
Brian Granger
|
r2226 | def init_sys_modules(self): | ||
pass | ||||
Fernando Perez
|
r6941 | def init_magics(self): | ||
super(InteractiveShellEmbed, self).init_magics() | ||||
self.register_magics(EmbeddedMagics) | ||||
Thomas Kluyver
|
r5459 | def __call__(self, header='', local_ns=None, module=None, dummy=None, | ||
Thomas Kluyver
|
r5675 | stack_depth=1, global_ns=None): | ||
Brian Granger
|
r2206 | """Activate the interactive interpreter. | ||
Thomas Kluyver
|
r5684 | __call__(self,header='',local_ns=None,module=None,dummy=None) -> Start | ||
Brian Granger
|
r2206 | 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 | ||||
Thomas Kluyver
|
r5684 | dummy_mode attribute. This allows you to turn off a shell used | ||
Brian Granger
|
r2206 | 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 | ||||
Thomas Kluyver
|
r5684 | example, if you set dummy mode on with IPShell.dummy_mode = True, you | ||
can still have a specific call work by making it as IPShell(dummy=False). | ||||
Brian Granger
|
r2206 | """ | ||
# If the user has turned it off, go away | ||||
if not self.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.exit_now = False | ||||
# Allow the dummy parameter to override the global __dummy_mode | ||||
if dummy or (dummy != 0 and self.dummy_mode): | ||||
return | ||||
if self.has_readline: | ||||
Thomas Kluyver
|
r3483 | self.set_readline_completer() | ||
Brian Granger
|
r2206 | |||
Brian Granger
|
r2252 | # self.banner is auto computed | ||
if header: | ||||
self.old_banner2 = self.banner2 | ||||
self.banner2 = self.banner2 + '\n' + header + '\n' | ||||
Fernando Perez
|
r2583 | else: | ||
self.old_banner2 = '' | ||||
Brian Granger
|
r2206 | |||
# Call the embedding code with a stack depth of 1 so it can skip over | ||||
# our call and get the original caller's namespaces. | ||||
Thomas Kluyver
|
r5675 | self.mainloop(local_ns, module, stack_depth=stack_depth, global_ns=global_ns) | ||
Brian Granger
|
r2252 | |||
self.banner2 = self.old_banner2 | ||||
Brian Granger
|
r2206 | |||
Brian Granger
|
r2226 | if self.exit_msg is not None: | ||
Brian Granger
|
r2206 | print self.exit_msg | ||
Brian Granger
|
r2231 | |||
Thomas Kluyver
|
r5459 | def mainloop(self, local_ns=None, module=None, stack_depth=0, | ||
Thomas Kluyver
|
r5675 | display_banner=None, global_ns=None): | ||
Brian Granger
|
r2227 | """Embeds IPython into a running python program. | ||
Input: | ||||
- header: An optional header message can be specified. | ||||
Thomas Kluyver
|
r5684 | - local_ns, module: working local namespace (a dict) and module (a | ||
module or similar object). If given as None, they are automatically | ||||
taken from the scope where the shell was called, so that | ||||
program variables become visible. | ||||
Brian Granger
|
r2227 | |||
- stack_depth: specifies how many levels in the stack to go to | ||||
Thomas Kluyver
|
r5684 | looking for namespaces (when local_ns or module is None). This | ||
Brian Granger
|
r2227 | allows an intermediate caller to make sure that this function gets | ||
the namespace from the intended level in the stack. By default (0) | ||||
it will get its locals and globals from the immediate caller. | ||||
Warning: it's possible to use this in a program which is being run by | ||||
IPython itself (via %run), but some funny things will happen (a few | ||||
globals get overwritten). In the future this will be cleaned up, as | ||||
there is no fundamental reason why it can't work perfectly.""" | ||||
Thomas Kluyver
|
r5675 | |||
if (global_ns is not None) and (module is None): | ||||
class DummyMod(object): | ||||
"""A dummy module object for embedded IPython.""" | ||||
pass | ||||
warnings.warn("global_ns is deprecated, use module instead.", DeprecationWarning) | ||||
module = DummyMod() | ||||
module.__dict__ = global_ns | ||||
Brian Granger
|
r2227 | |||
# Get locals and globals from caller | ||||
Thomas Kluyver
|
r5669 | if (local_ns is None or module is None) and self.default_user_namespaces: | ||
Brian Granger
|
r2227 | call_frame = sys._getframe(stack_depth).f_back | ||
Thomas Kluyver
|
r5669 | if local_ns is None: | ||
Brian Granger
|
r2227 | local_ns = call_frame.f_locals | ||
Thomas Kluyver
|
r5669 | if module is None: | ||
Brian Granger
|
r2227 | global_ns = call_frame.f_globals | ||
Thomas Kluyver
|
r5459 | module = sys.modules[global_ns['__name__']] | ||
# Save original namespace and module so we can restore them after | ||||
# embedding; otherwise the shell doesn't shut down correctly. | ||||
orig_user_module = self.user_module | ||||
orig_user_ns = self.user_ns | ||||
Brian Granger
|
r2227 | # Update namespaces and fire up interpreter | ||
Thomas Kluyver
|
r5459 | |||
Brian Granger
|
r2227 | # The global one is easy, we can just throw it in | ||
Thomas Kluyver
|
r5667 | if module is not None: | ||
self.user_module = module | ||||
Brian Granger
|
r2227 | |||
Thomas Kluyver
|
r5459 | # But the user/local one is tricky: ipython needs it to store internal | ||
# data, but we also need the locals. We'll throw our hidden variables | ||||
# like _ih and get_ipython() into the local namespace, but delete them | ||||
# later. | ||||
Thomas Kluyver
|
r5667 | if local_ns is not None: | ||
self.user_ns = local_ns | ||||
self.init_user_ns() | ||||
Brian Granger
|
r2227 | |||
# Patch for global embedding to make sure that things don't overwrite | ||||
# user globals accidentally. Thanks to Richard <rxe@renre-europe.com> | ||||
# FIXME. Test this a bit more carefully (the if.. is new) | ||||
Thomas Kluyver
|
r5459 | # N.B. This can't now ever be called. Not sure what it was for. | ||
Thomas Kluyver
|
r5667 | # And now, since it wasn't called in the previous version, I'm | ||
# commenting out these lines so they can't be called with my new changes | ||||
# --TK, 2011-12-10 | ||||
#if local_ns is None and module is None: | ||||
# self.user_global_ns.update(__main__.__dict__) | ||||
Brian Granger
|
r2227 | |||
# make sure the tab-completer has the correct frame information, so it | ||||
# actually completes using the frame's locals/globals | ||||
self.set_completer_frame() | ||||
Brian Granger
|
r2231 | with nested(self.builtin_trap, self.display_trap): | ||
Brian Granger
|
r2252 | self.interact(display_banner=display_banner) | ||
Thomas Kluyver
|
r5459 | |||
# now, purge out the local namespace of IPython's hidden variables. | ||||
Thomas Kluyver
|
r5667 | if local_ns is not None: | ||
for name in self.user_ns_hidden: | ||||
local_ns.pop(name, None) | ||||
Thomas Kluyver
|
r5459 | |||
# Restore original namespace so shell can shut down when we exit. | ||||
self.user_module = orig_user_module | ||||
self.user_ns = orig_user_ns | ||||
Brian Granger
|
r2226 | |||
_embedded_shell = None | ||||
Brian Granger
|
r2761 | def embed(**kwargs): | ||
Brian Granger
|
r2226 | """Call this to embed IPython at the current point in your program. | ||
The first invocation of this will create an :class:`InteractiveShellEmbed` | ||||
instance and then call it. Consecutive calls just call the already | ||||
created instance. | ||||
Here is a simple example:: | ||||
from IPython import embed | ||||
a = 10 | ||||
b = 20 | ||||
embed('First time') | ||||
c = 30 | ||||
d = 40 | ||||
embed | ||||
Bernardo B. Marques
|
r4872 | Full customization can be done by passing a :class:`Struct` in as the | ||
Brian Granger
|
r2226 | config argument. | ||
""" | ||||
Brian Granger
|
r2761 | config = kwargs.get('config') | ||
header = kwargs.pop('header', u'') | ||||
Brian Granger
|
r2245 | if config is None: | ||
config = load_default_config() | ||||
Brian Granger
|
r2761 | config.InteractiveShellEmbed = config.TerminalInteractiveShell | ||
muzuiget
|
r3914 | kwargs['config'] = config | ||
Brian Granger
|
r2226 | global _embedded_shell | ||
if _embedded_shell is None: | ||||
Brian Granger
|
r2761 | _embedded_shell = InteractiveShellEmbed(**kwargs) | ||
Brian Granger
|
r2226 | _embedded_shell(header=header, stack_depth=2) | ||