diff --git a/IPython/__init__.py b/IPython/__init__.py index 778ff05..626fb67 100644 --- a/IPython/__init__.py +++ b/IPython/__init__.py @@ -81,5 +81,5 @@ def embed_kernel(module=None, local_ns=None, **kwargs): local_ns = caller_locals # Only import .zmq when we really need it - from .zmq.ipkernel import embed_kernel as real_embed_kernel + from .zmq.embed import embed_kernel as real_embed_kernel real_embed_kernel(module=module, local_ns=local_ns, **kwargs) diff --git a/IPython/frontend/consoleapp.py b/IPython/frontend/consoleapp.py index 3163c82..2079652 100644 --- a/IPython/frontend/consoleapp.py +++ b/IPython/frontend/consoleapp.py @@ -42,9 +42,9 @@ from IPython.utils.py3compat import str_to_bytes from IPython.utils.traitlets import ( Dict, List, Unicode, CUnicode, Int, CBool, Any, CaselessStrEnum ) -from IPython.zmq.ipkernel import ( - flags as ipkernel_flags, - aliases as ipkernel_aliases, +from IPython.zmq.kernelapp import ( + kernel_flags, + kernel_aliases, IPKernelApp ) from IPython.zmq.session import Session, default_secure @@ -65,7 +65,7 @@ from IPython.utils.localinterfaces import LOCALHOST, LOCAL_IPS # Aliases and Flags #----------------------------------------------------------------------------- -flags = dict(ipkernel_flags) +flags = dict(kernel_flags) # the flags that are specific to the frontend # these must be scrubbed before being passed to the kernel, @@ -85,7 +85,7 @@ app_flags.update(boolean_flag( )) flags.update(app_flags) -aliases = dict(ipkernel_aliases) +aliases = dict(kernel_aliases) # also scrub aliases from the frontend app_aliases = dict( diff --git a/IPython/frontend/html/notebook/notebookapp.py b/IPython/frontend/html/notebook/notebookapp.py index 0b68a1f..1868103 100644 --- a/IPython/frontend/html/notebook/notebookapp.py +++ b/IPython/frontend/html/notebook/notebookapp.py @@ -63,9 +63,9 @@ from IPython.core.profiledir import ProfileDir from IPython.frontend.consoleapp import IPythonConsoleApp from IPython.zmq.session import Session, default_secure from IPython.zmq.zmqshell import ZMQInteractiveShell -from IPython.zmq.ipkernel import ( - flags as ipkernel_flags, - aliases as ipkernel_aliases, +from IPython.zmq.kernelapp import ( + kernel_flags, + kernel_aliases, IPKernelApp ) from IPython.utils.importstring import import_item @@ -195,7 +195,7 @@ class NotebookWebApplication(web.Application): # Aliases and Flags #----------------------------------------------------------------------------- -flags = dict(ipkernel_flags) +flags = dict(kernel_flags) flags['no-browser']=( {'NotebookApp' : {'open_browser' : False}}, "Don't open the notebook in a browser after startup." @@ -234,7 +234,7 @@ flags.update(boolean_flag('script', 'FileNotebookManager.save_script', # or it will raise an error on unrecognized flags notebook_flags = ['no-browser', 'no-mathjax', 'read-only', 'script', 'no-script'] -aliases = dict(ipkernel_aliases) +aliases = dict(kernel_aliases) aliases.update({ 'ip': 'NotebookApp.ip', diff --git a/IPython/frontend/qt/console/qtconsoleapp.py b/IPython/frontend/qt/console/qtconsoleapp.py index 4dbf106..f0b711b 100644 --- a/IPython/frontend/qt/console/qtconsoleapp.py +++ b/IPython/frontend/qt/console/qtconsoleapp.py @@ -71,7 +71,7 @@ from IPython.utils.py3compat import str_to_bytes from IPython.utils.traitlets import ( Dict, List, Unicode, Integer, CaselessStrEnum, CBool, Any ) -from IPython.zmq.ipkernel import IPKernelApp +from IPython.zmq.kernelapp import IPKernelApp from IPython.zmq.session import Session, default_secure from IPython.zmq.zmqshell import ZMQInteractiveShell diff --git a/IPython/frontend/terminal/console/app.py b/IPython/frontend/terminal/console/app.py index 27f1a55..f6ec15b 100644 --- a/IPython/frontend/terminal/console/app.py +++ b/IPython/frontend/terminal/console/app.py @@ -24,7 +24,7 @@ from IPython.utils.traitlets import ( ) from IPython.utils.warn import warn,error -from IPython.zmq.ipkernel import IPKernelApp +from IPython.zmq.kernelapp import IPKernelApp from IPython.zmq.session import Session, default_secure from IPython.zmq.zmqshell import ZMQInteractiveShell from IPython.frontend.consoleapp import ( diff --git a/IPython/frontend/terminal/ipapp.py b/IPython/frontend/terminal/ipapp.py index b2f540a..dc09ef5 100755 --- a/IPython/frontend/terminal/ipapp.py +++ b/IPython/frontend/terminal/ipapp.py @@ -233,7 +233,7 @@ class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp): profile = ("IPython.core.profileapp.ProfileApp", "Create and manage IPython profiles." ), - kernel = ("IPython.zmq.ipkernel.IPKernelApp", + kernel = ("IPython.zmq.kernelapp.IPKernelApp", "Start a kernel without an attached frontend." ), console=('IPython.frontend.terminal.console.app.ZMQTerminalIPythonApp', diff --git a/IPython/kernel/connect.py b/IPython/kernel/connect.py index 865bfd2..7f3045c 100644 --- a/IPython/kernel/connect.py +++ b/IPython/kernel/connect.py @@ -127,7 +127,7 @@ def get_connection_file(app=None): If unspecified, the currently running app will be used """ if app is None: - from IPython.zmq.ipkernel import IPKernelApp + from IPython.zmq.kernelapp import IPKernelApp if not IPKernelApp.initialized(): raise RuntimeError("app not specified, and not in a running Kernel") diff --git a/IPython/parallel/__init__.py b/IPython/parallel/__init__.py index ac6161f..0a58442 100644 --- a/IPython/parallel/__init__.py +++ b/IPython/parallel/__init__.py @@ -50,7 +50,7 @@ def bind_kernel(**kwargs): This function returns immediately. """ - from IPython.zmq.ipkernel import IPKernelApp + from IPython.zmq.kernelapp import IPKernelApp from IPython.parallel.apps.ipengineapp import IPEngineApp # first check for IPKernelApp, in which case this should be a no-op diff --git a/IPython/parallel/apps/ipengineapp.py b/IPython/parallel/apps/ipengineapp.py index 2fd16a3..5cf6458 100755 --- a/IPython/parallel/apps/ipengineapp.py +++ b/IPython/parallel/apps/ipengineapp.py @@ -37,7 +37,8 @@ from IPython.parallel.apps.baseapp import ( catch_config_error, ) from IPython.zmq.log import EnginePUBHandler -from IPython.zmq.ipkernel import Kernel, IPKernelApp +from IPython.zmq.ipkernel import Kernel +from IPython.zmq.kernelapp import IPKernelApp from IPython.zmq.session import ( Session, session_aliases, session_flags ) diff --git a/IPython/parallel/engine/engine.py b/IPython/parallel/engine/engine.py index f15878d..295cfcb 100644 --- a/IPython/parallel/engine/engine.py +++ b/IPython/parallel/engine/engine.py @@ -35,7 +35,8 @@ from IPython.parallel.factory import RegistrationFactory from IPython.parallel.util import disambiguate_url from IPython.zmq.session import Message -from IPython.zmq.ipkernel import Kernel, IPKernelApp +from IPython.zmq.ipkernel import Kernel +from IPython.zmq.kernelapp import IPKernelApp class EngineFactory(RegistrationFactory): """IPython engine""" diff --git a/IPython/zmq/embed.py b/IPython/zmq/embed.py new file mode 100644 index 0000000..0a3e50a --- /dev/null +++ b/IPython/zmq/embed.py @@ -0,0 +1,57 @@ +"""Simple function for embedding an IPython kernel +""" +#----------------------------------------------------------------------------- +# Imports +#----------------------------------------------------------------------------- + +import sys + +from IPython.utils.frame import extract_module_locals + +from kernelapp import IPKernelApp + +#----------------------------------------------------------------------------- +# Code +#----------------------------------------------------------------------------- + +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([]) + # Undo unnecessary sys module mangling from init_sys_modules. + # This would not be necessary if we could prevent it + # in the first place by using a different InteractiveShell + # subclass, as in the regular embed case. + main = app.kernel.shell._orig_sys_modules_main_mod + if main is not None: + sys.modules[app.kernel.shell._orig_sys_modules_main_name] = main + + # 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.shell.set_completer_frame() + app.start() diff --git a/IPython/zmq/ipkernel.py b/IPython/zmq/ipkernel.py index e422c81..afc24cb 100755 --- a/IPython/zmq/ipkernel.py +++ b/IPython/zmq/ipkernel.py @@ -17,7 +17,6 @@ from __future__ import print_function # Standard library imports import __builtin__ -import atexit import sys import time import traceback @@ -36,25 +35,18 @@ from zmq.eventloop.zmqstream import ZMQStream # Local imports from IPython.config.configurable import Configurable -from IPython.config.application import boolean_flag, catch_config_error -from IPython.core.application import ProfileDir from IPython.core.error import StdinNotImplementedError from IPython.core import release -from IPython.core.shellapp import ( - InteractiveShellApp, shell_flags, shell_aliases -) 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, List, Set, Integer, Unicode, Type ) -from kernelapp import KernelApp, kernel_flags, kernel_aliases from serialize import serialize_object, unpack_apply_message -from session import Session, Message +from session import Session from zmqshell import ZMQInteractiveShell @@ -785,139 +777,3 @@ class Kernel(Configurable): self.log.debug("%s", self._shutdown_message) [ s.flush(zmq.POLLOUT) for s in self.shell_streams ] -#----------------------------------------------------------------------------- -# Aliases and Flags for the IPKernelApp -#----------------------------------------------------------------------------- - -flags = dict(kernel_flags) -flags.update(shell_flags) - -addflag = lambda *args: flags.update(boolean_flag(*args)) - -flags['pylab'] = ( - {'IPKernelApp' : {'pylab' : 'auto'}}, - """Pre-load matplotlib and numpy for interactive use with - the default matplotlib backend.""" -) - -aliases = dict(kernel_aliases) -aliases.update(shell_aliases) - -#----------------------------------------------------------------------------- -# The IPKernelApp class -#----------------------------------------------------------------------------- - -class IPKernelApp(KernelApp, InteractiveShellApp): - name = 'ipkernel' - - aliases = Dict(aliases) - flags = Dict(flags) - classes = [Kernel, ZMQInteractiveShell, ProfileDir, Session] - - @catch_config_error - def initialize(self, argv=None): - super(IPKernelApp, self).initialize(argv) - self.init_path() - self.init_shell() - self.init_gui_pylab() - self.init_extensions() - self.init_code() - - def init_kernel(self): - - shell_stream = ZMQStream(self.shell_socket) - - kernel = Kernel(config=self.config, session=self.session, - shell_streams=[shell_stream], - iopub_socket=self.iopub_socket, - stdin_socket=self.stdin_socket, - log=self.log, - profile_dir=self.profile_dir, - ) - self.kernel = kernel - kernel.record_ports(self.ports) - shell = kernel.shell - - def init_gui_pylab(self): - """Enable GUI event loop integration, taking pylab into account.""" - - # Provide a wrapper for :meth:`InteractiveShellApp.init_gui_pylab` - # to ensure that any exception is printed straight to stderr. - # Normally _showtraceback associates the reply with an execution, - # which means frontends will never draw it, as this exception - # is not associated with any execute request. - - shell = self.shell - _showtraceback = shell._showtraceback - try: - # replace pyerr-sending traceback with stderr - def print_tb(etype, evalue, stb): - print ("GUI event loop or pylab initialization failed", - file=io.stderr) - print (shell.InteractiveTB.stb2text(stb), file=io.stderr) - shell._showtraceback = print_tb - InteractiveShellApp.init_gui_pylab(self) - finally: - shell._showtraceback = _showtraceback - - def init_shell(self): - self.shell = self.kernel.shell - self.shell.configurables.append(self) - - -#----------------------------------------------------------------------------- -# Kernel main and launch functions -#----------------------------------------------------------------------------- - - -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([]) - # Undo unnecessary sys module mangling from init_sys_modules. - # This would not be necessary if we could prevent it - # in the first place by using a different InteractiveShell - # subclass, as in the regular embed case. - main = app.kernel.shell._orig_sys_modules_main_mod - if main is not None: - sys.modules[app.kernel.shell._orig_sys_modules_main_name] = main - - # 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.shell.set_completer_frame() - app.start() - -def main(): - """Run an IPKernel as an application""" - app = IPKernelApp.instance() - app.initialize() - app.start() - - -if __name__ == '__main__': - main() diff --git a/IPython/zmq/kernelapp.py b/IPython/zmq/kernelapp.py index 2789540..f1deb7b 100644 --- a/IPython/zmq/kernelapp.py +++ b/IPython/zmq/kernelapp.py @@ -15,6 +15,8 @@ Authors # Imports #----------------------------------------------------------------------------- +from __future__ import print_function + # Standard library imports import atexit import json @@ -25,12 +27,17 @@ import signal # System library imports import zmq from zmq.eventloop import ioloop +from zmq.eventloop.zmqstream import ZMQStream # IPython imports from IPython.core.ultratb import FormattedTB from IPython.core.application import ( BaseIPythonApplication, base_flags, base_aliases, catch_config_error ) +from IPython.core.profiledir import ProfileDir +from IPython.core.shellapp import ( + InteractiveShellApp, shell_flags, shell_aliases +) from IPython.utils import io from IPython.utils.localinterfaces import LOCALHOST from IPython.utils.path import filefind @@ -41,13 +48,15 @@ from IPython.utils.traitlets import ( ) from IPython.utils.importstring import import_item from IPython.kernel import write_connection_file + # local imports -from IPython.zmq.heartbeat import Heartbeat -from IPython.zmq.parentpoller import ParentPollerUnix, ParentPollerWindows -from IPython.zmq.session import ( +from heartbeat import Heartbeat +from ipkernel import Kernel +from parentpoller import ParentPollerUnix, ParentPollerWindows +from session import ( Session, session_flags, session_aliases, default_secure, ) - +from zmqshell import ZMQInteractiveShell #----------------------------------------------------------------------------- # Flags and Aliases @@ -55,14 +64,14 @@ from IPython.zmq.session import ( kernel_aliases = dict(base_aliases) kernel_aliases.update({ - 'ip' : 'KernelApp.ip', - 'hb' : 'KernelApp.hb_port', - 'shell' : 'KernelApp.shell_port', - 'iopub' : 'KernelApp.iopub_port', - 'stdin' : 'KernelApp.stdin_port', - 'f' : 'KernelApp.connection_file', - 'parent': 'KernelApp.parent', - 'transport': 'KernelApp.transport', + 'ip' : 'IPKernelApp.ip', + 'hb' : 'IPKernelApp.hb_port', + 'shell' : 'IPKernelApp.shell_port', + 'iopub' : 'IPKernelApp.iopub_port', + 'stdin' : 'IPKernelApp.stdin_port', + 'f' : 'IPKernelApp.connection_file', + 'parent': 'IPKernelApp.parent', + 'transport': 'IPKernelApp.transport', }) if sys.platform.startswith('win'): kernel_aliases['interrupt'] = 'KernelApp.interrupt' @@ -70,28 +79,34 @@ if sys.platform.startswith('win'): kernel_flags = dict(base_flags) kernel_flags.update({ 'no-stdout' : ( - {'KernelApp' : {'no_stdout' : True}}, + {'IPKernelApp' : {'no_stdout' : True}}, "redirect stdout to the null device"), 'no-stderr' : ( - {'KernelApp' : {'no_stderr' : True}}, + {'IPKernelApp' : {'no_stderr' : True}}, "redirect stderr to the null device"), + 'pylab' : ( + {'IPKernelApp' : {'pylab' : 'auto'}}, + """Pre-load matplotlib and numpy for interactive use with + the default matplotlib backend."""), }) +# inherit flags&aliases for any IPython shell apps +kernel_aliases.update(shell_aliases) +kernel_flags.update(shell_flags) + # inherit flags&aliases for Sessions kernel_aliases.update(session_aliases) kernel_flags.update(session_flags) - - #----------------------------------------------------------------------------- -# Application class for starting a Kernel +# Application class for starting an IPython Kernel #----------------------------------------------------------------------------- -class KernelApp(BaseIPythonApplication): +class IPKernelApp(BaseIPythonApplication, InteractiveShellApp): name='ipkernel' aliases = Dict(kernel_aliases) flags = Dict(kernel_flags) - classes = [Session] + classes = [Kernel, ZMQInteractiveShell, ProfileDir, Session] # the kernel class, as an importstring kernel_class = DottedObjectName('IPython.zmq.ipkernel.Kernel') kernel = Any() @@ -332,18 +347,47 @@ class KernelApp(BaseIPythonApplication): def init_kernel(self): """Create the Kernel object itself""" - kernel_factory = import_item(str(self.kernel_class)) - self.kernel = kernel_factory(config=self.config, session=self.session, - shell_socket=self.shell_socket, + shell_stream = ZMQStream(self.shell_socket) + + kernel = Kernel(config=self.config, session=self.session, + shell_streams=[shell_stream], iopub_socket=self.iopub_socket, stdin_socket=self.stdin_socket, - log=self.log + log=self.log, + profile_dir=self.profile_dir, ) - self.kernel.record_ports(self.ports) + kernel.record_ports(self.ports) + self.kernel = kernel + + def init_gui_pylab(self): + """Enable GUI event loop integration, taking pylab into account.""" + + # Provide a wrapper for :meth:`InteractiveShellApp.init_gui_pylab` + # to ensure that any exception is printed straight to stderr. + # Normally _showtraceback associates the reply with an execution, + # which means frontends will never draw it, as this exception + # is not associated with any execute request. + + shell = self.shell + _showtraceback = shell._showtraceback + try: + # replace pyerr-sending traceback with stderr + def print_tb(etype, evalue, stb): + print ("GUI event loop or pylab initialization failed", + file=io.stderr) + print (shell.InteractiveTB.stb2text(stb), file=io.stderr) + shell._showtraceback = print_tb + InteractiveShellApp.init_gui_pylab(self) + finally: + shell._showtraceback = _showtraceback + + def init_shell(self): + self.shell = self.kernel.shell + self.shell.configurables.append(self) @catch_config_error def initialize(self, argv=None): - super(KernelApp, self).initialize(argv) + super(IPKernelApp, self).initialize(argv) self.init_blackhole() self.init_connection_file() self.init_session() @@ -356,6 +400,12 @@ class KernelApp(BaseIPythonApplication): self.init_io() self.init_signal() self.init_kernel() + # shell init steps + self.init_path() + self.init_shell() + self.init_gui_pylab() + self.init_extensions() + self.init_code() # flush stdout/stderr, so that anything written to these streams during # initialization do not get associated with the first execution request sys.stdout.flush() @@ -370,3 +420,13 @@ class KernelApp(BaseIPythonApplication): except KeyboardInterrupt: pass + +def main(): + """Run an IPKernel as an application""" + app = IPKernelApp.instance() + app.initialize() + app.start() + + +if __name__ == '__main__': + main() diff --git a/IPython/zmq/kernelmanager.py b/IPython/zmq/kernelmanager.py index 9ec75c0..013482c 100644 --- a/IPython/zmq/kernelmanager.py +++ b/IPython/zmq/kernelmanager.py @@ -903,7 +903,7 @@ class KernelManager(Configurable): cmd = self.kernel_cmd else: cmd = make_ipkernel_cmd( - 'from IPython.zmq.ipkernel import main; main()', + 'from IPython.zmq.kernelapp import main; main()', **kw ) ns = dict(connection_file=self.connection_file)