diff --git a/IPython/__init__.py b/IPython/__init__.py index d2c3345..1d7698e 100644 --- a/IPython/__init__.py +++ b/IPython/__init__.py @@ -58,13 +58,29 @@ for author, email in release.authors.itervalues(): __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. """ +def embed_kernel(module=None, local_ns=None, **kwargs): + """Embed and start an IPython kernel in a given scope. + + Parameters + ---------- + module : ModuleType, optional + The module to load into IPython globals (default: caller) + local_ns : dict, optional + The namespace to load into IPython user namespace (default: caller) + + kwargs : various, optional + Further keyword args are relayed to the KernelApp constructor, + allowing configuration of the Kernel. Will only have an effect + on the first embed_kernel call for a given process. + + """ + (caller_module, caller_locals) = extract_module_locals(1) 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) + real_embed_kernel(module=module, local_ns=local_ns, **kwargs) diff --git a/IPython/zmq/ipkernel.py b/IPython/zmq/ipkernel.py index 968ca3f..ba0e205 100755 --- a/IPython/zmq/ipkernel.py +++ b/IPython/zmq/ipkernel.py @@ -39,6 +39,7 @@ from IPython.core.shellapp import ( ) from IPython.utils import io from IPython.utils import py3compat +from IPython.utils.frame import extract_module_locals from IPython.utils.jsonutil import json_clean from IPython.utils.traitlets import ( Any, Instance, Float, Dict, CaselessStrEnum @@ -70,8 +71,17 @@ 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) + def _user_module_changed(self, name, old, new): + if self.shell is not None: + self.shell.user_module = new + + user_ns = Dict(default_value=None) + def _user_ns_changed(self, name, old, new): + if self.shell is not None: + self.shell.user_ns = new + self.shell.init_user_ns() # Private interface @@ -566,6 +576,7 @@ class IPKernelApp(KernelApp, InteractiveShellApp): aliases = Dict(aliases) flags = Dict(flags) classes = [Kernel, ZMQInteractiveShell, ProfileDir, Session] + # configurables pylab = CaselessStrEnum(['tk', 'qt', 'wx', 'gtk', 'osx', 'inline', 'auto'], config=True, @@ -589,8 +600,6 @@ class IPKernelApp(KernelApp, InteractiveShellApp): 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) @@ -645,9 +654,39 @@ 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([]) + +def embed_kernel(module=None, local_ns=None, **kwargs): + """Embed and start an IPython kernel in a given scope. + + Parameters + ---------- + module : ModuleType, optional + The module to load into IPython globals (default: caller) + local_ns : dict, optional + The namespace to load into IPython user namespace (default: caller) + + kwargs : various, optional + Further keyword args are relayed to the KernelApp constructor, + allowing configuration of the Kernel. Will only have an effect + on the first embed_kernel call for a given process. + + """ + # get the app if it exists, or set it up if it doesn't + if IPKernelApp.initialized(): + app = IPKernelApp.instance() + else: + app = IPKernelApp.instance(**kwargs) + app.initialize([]) + + # load the calling scope if not given + (caller_module, caller_locals) = extract_module_locals(1) + if module is None: + module = caller_module + if local_ns is None: + local_ns = caller_locals + + app.kernel.user_module = module + app.kernel.user_ns = local_ns app.start() def main():