diff --git a/IPython/__init__.py b/IPython/__init__.py index 0252940c746..df5434645ea 100644 --- a/IPython/__init__.py +++ b/IPython/__init__.py @@ -44,10 +44,12 @@ from .core import release from .core.application import Application from .frontend.terminal.embed import embed + from .core.error import TryNext from .core.interactiveshell import InteractiveShell from .testing import test from .utils.sysinfo import sys_info +from .utils.frame import extract_module_locals_above # Release data __author__ = '' @@ -55,3 +57,14 @@ __author__ += author + ' <' + email + '>\n' __license__ = release.license __version__ = release.version + +def embed_kernel(module=None, local_ns=None): + """Call this to embed an IPython kernel at the current point in your program. """ + (caller_module, caller_locals) = extract_module_locals_above() + if module is None: + module = caller_module + if local_ns is None: + local_ns = caller_locals + # Only import .zmq when we really need it + from .zmq.ipkernel import embed_kernel as real_embed_kernel + real_embed_kernel(module, local_ns) diff --git a/IPython/utils/frame.py b/IPython/utils/frame.py index 2fb61421a50..cd3563ac22e 100644 --- a/IPython/utils/frame.py +++ b/IPython/utils/frame.py @@ -85,3 +85,16 @@ def debugx(expr,pre_msg=''): # deactivate it by uncommenting the following line, which makes it a no-op #def debugx(expr,pre_msg=''): pass +def extract_module_locals(depth=0): + """Returns (module, locals) of the funciton `depth` frames away from the caller""" + f = sys._getframe(depth + 1) + global_ns = f.f_globals + module = sys.modules[global_ns['__name__']] + return (module, f.f_locals) + +def extract_module_locals_above(): + """Returns (module, locals) of the funciton calling the caller. + Like extract_module_locals() with a specified depth of 1.""" + # we're one frame away from the target, the function we call would be two frames away + return extract_module_locals(1 + 1) + diff --git a/IPython/zmq/ipkernel.py b/IPython/zmq/ipkernel.py index edc5c9ac330..968ca3f95df 100755 --- a/IPython/zmq/ipkernel.py +++ b/IPython/zmq/ipkernel.py @@ -70,6 +70,8 @@ class Kernel(Configurable): iopub_socket = Instance('zmq.Socket') stdin_socket = Instance('zmq.Socket') log = Instance(logging.Logger) + user_module = Instance('types.ModuleType') + user_ns = Dict(default_value=None) # Private interface @@ -110,6 +112,8 @@ def __init__(self, **kwargs): # Initialize the InteractiveShell subclass self.shell = ZMQInteractiveShell.instance(config=self.config, profile_dir = self.profile_dir, + user_module = self.user_module, + user_ns = self.user_ns, ) self.shell.displayhook.session = self.session self.shell.displayhook.pub_socket = self.iopub_socket @@ -585,6 +589,8 @@ def init_kernel(self): stdin_socket=self.stdin_socket, log=self.log, profile_dir=self.profile_dir, + user_module=self.user_module, + user_ns=self.user_ns, ) self.kernel = kernel kernel.record_ports(self.ports) @@ -639,6 +645,10 @@ def launch_kernel(*args, **kwargs): return base_launch_kernel('from IPython.zmq.ipkernel import main; main()', *args, **kwargs) +def embed_kernel(module, local_ns): + app = IPKernelApp.instance(user_module=module, user_ns=local_ns) + app.initialize([]) + app.start() def main(): """Run an IPKernel as an application"""