embed.py
325 lines
| 12.1 KiB
| text/x-python
|
PythonLexer
Brian Granger
|
r2206 | # encoding: utf-8 | ||
""" | ||||
An embedded IPython shell. | ||||
""" | ||||
Paul Ivanov
|
r17134 | # Copyright (c) IPython Development Team. | ||
# Distributed under the terms of the Modified BSD License. | ||||
Brian Granger
|
r2206 | |||
Brian Granger
|
r2227 | from __future__ import with_statement | ||
Thomas Kluyver
|
r13348 | from __future__ import print_function | ||
Brian Granger
|
r2227 | |||
Brian Granger
|
r2206 | import sys | ||
Thomas Kluyver
|
r5675 | import warnings | ||
Brian Granger
|
r2206 | |||
Bradley M. Froehle
|
r7894 | from IPython.core import ultratb, compilerop | ||
Fernando Perez
|
r6973 | from IPython.core.magic import Magics, magics_class, line_magic | ||
Min RK
|
r22549 | from IPython.core.interactiveshell import DummyMod, InteractiveShell | ||
from IPython.terminal.interactiveshell import TerminalInteractiveShell | ||||
Fernando Perez
|
r11020 | from IPython.terminal.ipapp import load_default_config | ||
Brian Granger
|
r2206 | |||
Min RK
|
r21253 | from traitlets import Bool, CBool, Unicode | ||
Brian Granger
|
r2498 | from IPython.utils.io import ask_yes_no | ||
Brian Granger
|
r2206 | |||
Matthias Bussonnier
|
r21960 | class KillEmbeded(Exception):pass | ||
Brian Granger
|
r2245 | |||
Brian Granger
|
r2206 | # 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. | ||||
""" | ||||
Matthias Bussonnier
|
r22294 | kill = ask_yes_no("Are you sure you want to kill this embedded instance? [y/N] ",'n') | ||
Fernando Perez
|
r6941 | if kill: | ||
self.shell.embedded_active = False | ||||
print ("This embedded IPython will not reactivate anymore " | ||||
"once you exit.") | ||||
Brian Granger
|
r2206 | |||
Matthias Bussonnier
|
r21987 | |||
@line_magic | ||||
def exit_raise(self, parameter_s=''): | ||||
"""%exit_raise Make the current embedded kernel exit and raise and exception. | ||||
Matthias Bussonnier
|
r21998 | This function sets an internal flag so that an embedded IPython will | ||
raise a `IPython.terminal.embed.KillEmbeded` Exception on exit, and then exit the current I. This is | ||||
useful to permanently exit a loop that create IPython embed instance. | ||||
Matthias Bussonnier
|
r21987 | """ | ||
self.shell.should_raise = True | ||||
self.shell.ask_exit() | ||||
Matthias Bussonnier
|
r21960 | |||
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) | ||
Matthias Bussonnier
|
r21960 | should_raise = CBool(False) | ||
Brian Granger
|
r2252 | # Like the base class display_banner is not configurable, but here it | ||
# is True by default. | ||||
display_banner = CBool(True) | ||||
MinRK
|
r16581 | exit_msg = Unicode() | ||
Matthias Bussonnier
|
r22294 | |||
_inactive_locations = set() | ||||
@property | ||||
def embedded_active(self): | ||||
return self._call_location_id not in InteractiveShellEmbed._inactive_locations | ||||
@embedded_active.setter | ||||
def embedded_active(self, value): | ||||
if value : | ||||
if self._call_location_id in InteractiveShellEmbed._inactive_locations: | ||||
InteractiveShellEmbed._inactive_locations.remove(self._call_location_id) | ||||
else: | ||||
InteractiveShellEmbed._inactive_locations.add(self._call_location_id) | ||||
Brian Granger
|
r2206 | |||
MinRK
|
r16581 | def __init__(self, **kw): | ||
Thomas Kluyver
|
r5676 | |||
MinRK
|
r16581 | if kw.get('user_global_ns', None) is not None: | ||
Matthias Bussonnier
|
r22404 | raise DeprecationWarning("Key word argument `user_global_ns` has been replaced by `user_module` since IPython 4.0.") | ||
Brian Granger
|
r2206 | |||
Matthias Bussonnier
|
r22294 | self._call_location_id = kw.pop('_call_location_id', None) | ||
MinRK
|
r16581 | super(InteractiveShellEmbed,self).__init__(**kw) | ||
Brian Granger
|
r2206 | |||
Matthias Bussonnier
|
r22294 | if not self._call_location_id: | ||
frame = sys._getframe(1) | ||||
self._call_location_id = '%s:%s' % (frame.f_code.co_filename, frame.f_lineno) | ||||
Brian Granger
|
r2206 | # 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, | ||
Bradley M. Froehle
|
r7895 | stack_depth=1, global_ns=None, compile_flags=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 | |||
Thomas Kluyver
|
r22229 | if self.display_banner: | ||
self.show_banner() | ||||
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. | ||||
Bradley M. Froehle
|
r7895 | self.mainloop(local_ns, module, stack_depth=stack_depth, | ||
global_ns=global_ns, compile_flags=compile_flags) | ||||
Brian Granger
|
r2252 | |||
self.banner2 = self.old_banner2 | ||||
Brian Granger
|
r2206 | |||
Brian Granger
|
r2226 | if self.exit_msg is not None: | ||
Thomas Kluyver
|
r13348 | print(self.exit_msg) | ||
Brian Granger
|
r2231 | |||
Matthias Bussonnier
|
r21960 | if self.should_raise: | ||
Matthias Bussonnier
|
r21998 | raise KillEmbeded('Embedded IPython raising error, as user requested.') | ||
Matthias Bussonnier
|
r21960 | |||
Thomas Kluyver
|
r5459 | def mainloop(self, local_ns=None, module=None, stack_depth=0, | ||
Bradley M. Froehle
|
r7894 | display_banner=None, global_ns=None, compile_flags=None): | ||
Brian Granger
|
r2227 | """Embeds IPython into a running python program. | ||
Thomas Kluyver
|
r13587 | Parameters | ||
---------- | ||||
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. | ||||
stack_depth : int | ||||
How many levels in the stack to go to looking for namespaces (when | ||||
local_ns or module is None). This 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. | ||||
compile_flags | ||||
A bit field identifying the __future__ features | ||||
that are enabled, as passed to the builtin :func:`compile` function. | ||||
If given as None, they are automatically taken from the scope where | ||||
the shell was called. | ||||
""" | ||||
Thomas Kluyver
|
r5675 | |||
if (global_ns is not None) and (module is None): | ||||
Matthias Bussonnier
|
r22405 | raise DeprecationWarning("'global_ns' keyword argument is deprecated, and has been removed in IPython 5.0 use `module` keyword argument instead.") | ||
Brian Granger
|
r2227 | |||
Thomas Kluyver
|
r22229 | if (display_banner is not None): | ||
Matthias Bussonnier
|
r22405 | warnings.warn("The display_banner parameter is deprecated since IPython 4.0", DeprecationWarning) | ||
Thomas Kluyver
|
r22229 | |||
Brian Granger
|
r2227 | # Get locals and globals from caller | ||
Bradley M. Froehle
|
r8130 | if ((local_ns is None or module is None or compile_flags 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 | ||
Min RK
|
r22235 | try: | ||
module = sys.modules[global_ns['__name__']] | ||||
except KeyError: | ||||
warnings.warn("Failed to get module %s" % \ | ||||
global_ns.get('__name__', 'unknown module') | ||||
) | ||||
module = DummyMod() | ||||
module.__dict__ = global_ns | ||||
Bradley M. Froehle
|
r7894 | if compile_flags is None: | ||
compile_flags = (call_frame.f_code.co_flags & | ||||
compilerop.PyCF_MASK) | ||||
Thomas Kluyver
|
r5459 | |||
# 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 | ||||
Bradley M. Froehle
|
r7894 | orig_compile_flags = self.compile.flags | ||
Thomas Kluyver
|
r5459 | |||
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: | ||
Jason Newton
|
r18762 | reentrant_local_ns = {k: v for (k, v) in local_ns.items() if k not in self.user_ns_hidden.keys()} | ||
self.user_ns = reentrant_local_ns | ||||
Thomas Kluyver
|
r5667 | self.init_user_ns() | ||
Brian Granger
|
r2227 | |||
Bradley M. Froehle
|
r7894 | # Compiler flags | ||
Bradley M. Froehle
|
r8130 | if compile_flags is not None: | ||
self.compile.flags = compile_flags | ||||
Bradley M. Froehle
|
r7894 | |||
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() | ||||
Mike McKerns
|
r12471 | with self.builtin_trap, self.display_trap: | ||
Thomas Kluyver
|
r22229 | self.interact() | ||
Thomas Kluyver
|
r5459 | |||
# now, purge out the local namespace of IPython's hidden variables. | ||||
Thomas Kluyver
|
r5667 | if local_ns is not None: | ||
Jason Newton
|
r18762 | local_ns.update({k: v for (k, v) in self.user_ns.items() if k not in self.user_ns_hidden.keys()}) | ||
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 | ||||
Bradley M. Froehle
|
r7894 | self.compile.flags = orig_compile_flags | ||
Brian Granger
|
r2226 | |||
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. | ||||
MinRK
|
r11174 | If you don't want the kernel to initialize the namespace | ||
from the scope of the surrounding function, | ||||
and/or you want to load full IPython configuration, | ||||
you probably want `IPython.start_ipython()` instead. | ||||
Brian Granger
|
r2226 | Here is a simple example:: | ||
from IPython import embed | ||||
a = 10 | ||||
b = 20 | ||||
Paul Ivanov
|
r17134 | embed(header='First time') | ||
Brian Granger
|
r2226 | c = 30 | ||
d = 40 | ||||
Paul Ivanov
|
r17134 | embed() | ||
Brian Granger
|
r2226 | |||
MinRK
|
r8385 | Full customization can be done by passing a :class:`Config` in as the | ||
Brian Granger
|
r2226 | config argument. | ||
""" | ||||
Brian Granger
|
r2761 | config = kwargs.get('config') | ||
header = kwargs.pop('header', u'') | ||||
Bradley M. Froehle
|
r7895 | compile_flags = kwargs.pop('compile_flags', None) | ||
Brian Granger
|
r2245 | if config is None: | ||
config = load_default_config() | ||||
Brian Granger
|
r2761 | config.InteractiveShellEmbed = config.TerminalInteractiveShell | ||
Matthias Bussonnier
|
r22081 | config.InteractiveShellEmbed.colors='nocolor' | ||
muzuiget
|
r3914 | kwargs['config'] = config | ||
Jason Newton
|
r18763 | #save ps1/ps2 if defined | ||
ps1 = None | ||||
ps2 = None | ||||
try: | ||||
ps1 = sys.ps1 | ||||
ps2 = sys.ps2 | ||||
except AttributeError: | ||||
pass | ||||
Jason Newton
|
r18762 | #save previous instance | ||
saved_shell_instance = InteractiveShell._instance | ||||
if saved_shell_instance is not None: | ||||
cls = type(saved_shell_instance) | ||||
cls.clear_instance() | ||||
Matthias Bussonnier
|
r22294 | frame = sys._getframe(1) | ||
shell = InteractiveShellEmbed.instance(_call_location_id='%s:%s' % (frame.f_code.co_filename, frame.f_lineno), **kwargs) | ||||
MinRK
|
r8385 | shell(header=header, stack_depth=2, compile_flags=compile_flags) | ||
Jason Newton
|
r18762 | InteractiveShellEmbed.clear_instance() | ||
#restore previous instance | ||||
if saved_shell_instance is not None: | ||||
cls = type(saved_shell_instance) | ||||
cls.clear_instance() | ||||
for subclass in cls._walk_mro(): | ||||
subclass._instance = saved_shell_instance | ||||
Jason Newton
|
r18763 | if ps1 is not None: | ||
sys.ps1 = ps1 | ||||
sys.ps2 = ps2 | ||||