##// END OF EJS Templates
Merge pull request #2900 from takluyver/i2899...
Merge pull request #2900 from takluyver/i2899 Don't assume test case for %time will finish in 0 time Closes gh-2899

File last commit:

r9372:37f32253
r9506:32413b9e merge
Show More
kernelapp.py
432 lines | 16.5 KiB | text/x-python | PythonLexer
MinRK
zmq kernels now started via newapp
r3970 """An Application for launching a kernel
Authors
-------
* MinRK
"""
#-----------------------------------------------------------------------------
# Copyright (C) 2011 The IPython Development Team
#
# Distributed under the terms of the BSD License. The full license is in
# the file COPYING.txt, distributed as part of this software.
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
MinRK
move IPKernelApp from zmq.ipkernel to zmq.kernelapp...
r9357 from __future__ import print_function
MinRK
use IOLoop in ipkernel...
r6790 # Standard library imports
MinRK
kernel app cleans up connection files that it wrote
r6889 import atexit
MinRK
protect kernelapp/qtconsole from invalid connection files...
r4986 import json
MinRK
zmq kernels now started via newapp
r3970 import os
import sys
MinRK
use IOLoop in ipkernel...
r6790 import signal
MinRK
zmq kernels now started via newapp
r3970
MinRK
use IOLoop in ipkernel...
r6790 # System library imports
MinRK
zmq kernels now started via newapp
r3970 import zmq
MinRK
use IOLoop in ipkernel...
r6790 from zmq.eventloop import ioloop
MinRK
move IPKernelApp from zmq.ipkernel to zmq.kernelapp...
r9357 from zmq.eventloop.zmqstream import ZMQStream
MinRK
zmq kernels now started via newapp
r3970
MinRK
use IOLoop in ipkernel...
r6790 # IPython imports
MinRK
zmq kernels now started via newapp
r3970 from IPython.core.ultratb import FormattedTB
MinRK
rename core.newapplication -> core.application
r4023 from IPython.core.application import (
MinRK
catch_config -> catch_config_error
r5214 BaseIPythonApplication, base_flags, base_aliases, catch_config_error
MinRK
zmq kernels now started via newapp
r3970 )
MinRK
move IPKernelApp from zmq.ipkernel to zmq.kernelapp...
r9357 from IPython.core.profiledir import ProfileDir
from IPython.core.shellapp import (
InteractiveShellApp, shell_flags, shell_aliases
)
MinRK
zmq kernels now started via newapp
r3970 from IPython.utils import io
from IPython.utils.localinterfaces import LOCALHOST
MinRK
use connection files instead of ports to connect to kernels...
r4958 from IPython.utils.path import filefind
MinRK
py3compat pass on Session.key...
r4967 from IPython.utils.py3compat import str_to_bytes
MinRK
enable IPC transport for kernels...
r7321 from IPython.utils.traitlets import (
Any, Instance, Dict, Unicode, Integer, Bool, CaselessStrEnum,
DottedObjectName,
)
MinRK
zmq kernels now started via newapp
r3970 from IPython.utils.importstring import import_item
MinRK
move utils.kernel (formerly entry_point and lib.kernel) to kernel.util
r9353 from IPython.kernel import write_connection_file
MinRK
move IPKernelApp from zmq.ipkernel to zmq.kernelapp...
r9357
MinRK
zmq kernels now started via newapp
r3970 # local imports
MinRK
move IPKernelApp from zmq.ipkernel to zmq.kernelapp...
r9357 from heartbeat import Heartbeat
from ipkernel import Kernel
from parentpoller import ParentPollerUnix, ParentPollerWindows
from session import (
MinRK
enable HMAC message signing by default in kernels...
r4962 Session, session_flags, session_aliases, default_secure,
)
MinRK
move IPKernelApp from zmq.ipkernel to zmq.kernelapp...
r9357 from zmqshell import ZMQInteractiveShell
MinRK
zmq kernels now started via newapp
r3970
#-----------------------------------------------------------------------------
# Flags and Aliases
#-----------------------------------------------------------------------------
kernel_aliases = dict(base_aliases)
kernel_aliases.update({
MinRK
move IPKernelApp from zmq.ipkernel to zmq.kernelapp...
r9357 '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',
MinRK
zmq kernels now started via newapp
r3970 })
if sys.platform.startswith('win'):
kernel_aliases['interrupt'] = 'KernelApp.interrupt'
kernel_flags = dict(base_flags)
kernel_flags.update({
'no-stdout' : (
MinRK
move IPKernelApp from zmq.ipkernel to zmq.kernelapp...
r9357 {'IPKernelApp' : {'no_stdout' : True}},
MinRK
zmq kernels now started via newapp
r3970 "redirect stdout to the null device"),
'no-stderr' : (
MinRK
move IPKernelApp from zmq.ipkernel to zmq.kernelapp...
r9357 {'IPKernelApp' : {'no_stderr' : True}},
MinRK
zmq kernels now started via newapp
r3970 "redirect stderr to the null device"),
MinRK
move IPKernelApp from zmq.ipkernel to zmq.kernelapp...
r9357 'pylab' : (
{'IPKernelApp' : {'pylab' : 'auto'}},
"""Pre-load matplotlib and numpy for interactive use with
the default matplotlib backend."""),
MinRK
zmq kernels now started via newapp
r3970 })
MinRK
move IPKernelApp from zmq.ipkernel to zmq.kernelapp...
r9357 # inherit flags&aliases for any IPython shell apps
kernel_aliases.update(shell_aliases)
kernel_flags.update(shell_flags)
MinRK
enable HMAC message signing by default in kernels...
r4962 # inherit flags&aliases for Sessions
kernel_aliases.update(session_aliases)
kernel_flags.update(session_flags)
MinRK
zmq kernels now started via newapp
r3970 #-----------------------------------------------------------------------------
MinRK
move IPKernelApp from zmq.ipkernel to zmq.kernelapp...
r9357 # Application class for starting an IPython Kernel
MinRK
zmq kernels now started via newapp
r3970 #-----------------------------------------------------------------------------
MinRK
move IPKernelApp from zmq.ipkernel to zmq.kernelapp...
r9357 class IPKernelApp(BaseIPythonApplication, InteractiveShellApp):
MinRK
remove references to removed pykernel and associated pure flag
r6806 name='ipkernel'
MinRK
zmq kernels now started via newapp
r3970 aliases = Dict(kernel_aliases)
flags = Dict(kernel_flags)
MinRK
move IPKernelApp from zmq.ipkernel to zmq.kernelapp...
r9357 classes = [Kernel, ZMQInteractiveShell, ProfileDir, Session]
MinRK
zmq kernels now started via newapp
r3970 # the kernel class, as an importstring
MinRK
mv IPython.zmq to IPython.kernel.zmq
r9372 kernel_class = DottedObjectName('IPython.kernel.zmq.ipkernel.Kernel')
MinRK
zmq kernels now started via newapp
r3970 kernel = Any()
poller = Any() # don't restrict this even though current pollers are all Threads
heartbeat = Instance(Heartbeat)
MinRK
mv IPython.zmq to IPython.kernel.zmq
r9372 session = Instance('IPython.kernel.zmq.session.Session')
MinRK
zmq kernels now started via newapp
r3970 ports = Dict()
MinRK
add config file inheritance to kernelapp...
r4118
# inherit config file name from parent:
parent_appname = Unicode(config=True)
def _parent_appname_changed(self, name, old, new):
if self.config_file_specified:
# it was manually specified, ignore
return
self.config_file_name = new.replace('-','_') + u'_config.py'
# don't let this count as specifying the config file
self.config_file_specified = False
MinRK
zmq kernels now started via newapp
r3970 # connection info:
MinRK
enable IPC transport for kernels...
r7321 transport = CaselessStrEnum(['tcp', 'ipc'], default_value='tcp', config=True)
MinRK
improve default ipc file locations...
r9175 ip = Unicode(config=True,
MinRK
zmq kernels now started via newapp
r3970 help="Set the IP or interface on which the kernel will listen.")
MinRK
improve default ipc file locations...
r9175 def _ip_default(self):
if self.transport == 'ipc':
if self.connection_file:
return os.path.splitext(self.abs_connection_file)[0] + '-ipc'
else:
return 'kernel-ipc'
else:
return LOCALHOST
MinRK
add Integer traitlet...
r5344 hb_port = Integer(0, config=True, help="set the heartbeat port [default: random]")
MinRK
remove remaining references to deprecated XREP/XREQ names...
r7538 shell_port = Integer(0, config=True, help="set the shell (ROUTER) port [default: random]")
MinRK
add Integer traitlet...
r5344 iopub_port = Integer(0, config=True, help="set the iopub (PUB) port [default: random]")
MinRK
remove remaining references to deprecated XREP/XREQ names...
r7538 stdin_port = Integer(0, config=True, help="set the stdin (DEALER) port [default: random]")
MinRK
use connection files instead of ports to connect to kernels...
r4958 connection_file = Unicode('', config=True,
help="""JSON file in which to store connection info [default: kernel-<pid>.json]
This file will contain the IP, ports, and authentication key needed to connect
MinRK
improve default ipc file locations...
r9175 clients to this kernel. By default, this file will be created in the security dir
MinRK
use connection files instead of ports to connect to kernels...
r4958 of the current profile, but can be specified by absolute path.
""")
MinRK
improve default ipc file locations...
r9175 @property
def abs_connection_file(self):
if os.path.basename(self.connection_file) == self.connection_file:
return os.path.join(self.profile_dir.security_dir, self.connection_file)
else:
return self.connection_file
MinRK
zmq kernels now started via newapp
r3970
# streams, etc.
no_stdout = Bool(False, config=True, help="redirect stdout to the null device")
no_stderr = Bool(False, config=True, help="redirect stderr to the null device")
MinRK
mv IPython.zmq to IPython.kernel.zmq
r9372 outstream_class = DottedObjectName('IPython.kernel.zmq.iostream.OutStream',
Thomas Kluyver
Use DottedObjectName traits in zmq and parallel modules.
r4055 config=True, help="The importstring for the OutStream factory")
MinRK
mv IPython.zmq to IPython.kernel.zmq
r9372 displayhook_class = DottedObjectName('IPython.kernel.zmq.displayhook.ZMQDisplayHook',
Thomas Kluyver
Use DottedObjectName traits in zmq and parallel modules.
r4055 config=True, help="The importstring for the DisplayHook factory")
MinRK
zmq kernels now started via newapp
r3970
# polling
MinRK
add Integer traitlet...
r5344 parent = Integer(0, config=True,
MinRK
zmq kernels now started via newapp
r3970 help="""kill this process if its parent dies. On Windows, the argument
specifies the HANDLE of the parent process, otherwise it is simply boolean.
""")
MinRK
add Integer traitlet...
r5344 interrupt = Integer(0, config=True,
MinRK
zmq kernels now started via newapp
r3970 help="""ONLY USED ON WINDOWS
MinRK
improve default ipc file locations...
r9175 Interrupt this process when the parent is signaled.
MinRK
zmq kernels now started via newapp
r3970 """)
def init_crash_handler(self):
# Install minimal exception handling
sys.excepthook = FormattedTB(mode='Verbose', color_scheme='NoColor',
ostream=sys.__stdout__)
def init_poller(self):
if sys.platform == 'win32':
if self.interrupt or self.parent:
self.poller = ParentPollerWindows(self.interrupt, self.parent)
elif self.parent:
self.poller = ParentPollerUnix()
def _bind_socket(self, s, port):
MinRK
enable IPC transport for kernels...
r7321 iface = '%s://%s' % (self.transport, self.ip)
MinRK
improve default ipc file locations...
r9175 if self.transport == 'tcp':
if port <= 0:
port = s.bind_to_random_port(iface)
else:
s.bind("tcp://%s:%i" % (self.ip, port))
elif self.transport == 'ipc':
if port <= 0:
MinRK
don't limit ports to 1024
r9243 port = 1
path = "%s-%i" % (self.ip, port)
while os.path.exists(path):
port = port + 1
MinRK
improve default ipc file locations...
r9175 path = "%s-%i" % (self.ip, port)
else:
path = "%s-%i" % (self.ip, port)
s.bind("ipc://%s" % path)
MinRK
zmq kernels now started via newapp
r3970 return port
MinRK
use connection files instead of ports to connect to kernels...
r4958 def load_connection_file(self):
"""load ip/port/hmac config from JSON connection file"""
try:
fname = filefind(self.connection_file, ['.', self.profile_dir.security_dir])
except IOError:
self.log.debug("Connection file not found: %s", self.connection_file)
MinRK
kernel app cleans up connection files that it wrote
r6889 # This means I own it, so I will clean it up:
atexit.register(self.cleanup_connection_file)
MinRK
use connection files instead of ports to connect to kernels...
r4958 return
self.log.debug(u"Loading connection file %s", fname)
with open(fname) as f:
s = f.read()
cfg = json.loads(s)
MinRK
enable IPC transport for kernels...
r7321 self.transport = cfg.get('transport', self.transport)
MinRK
improve default ipc file locations...
r9175 if self.ip == self._ip_default() and 'ip' in cfg:
MinRK
use connection files instead of ports to connect to kernels...
r4958 # not overridden by config or cl_args
self.ip = cfg['ip']
for channel in ('hb', 'shell', 'iopub', 'stdin'):
name = channel + '_port'
if getattr(self, name) == 0 and name in cfg:
# not overridden by config or cl_args
setattr(self, name, cfg[name])
if 'key' in cfg:
MinRK
py3compat pass on Session.key...
r4967 self.config.Session.key = str_to_bytes(cfg['key'])
MinRK
use connection files instead of ports to connect to kernels...
r4958
def write_connection_file(self):
"""write connection info to JSON file"""
MinRK
improve default ipc file locations...
r9175 cf = self.abs_connection_file
self.log.debug("Writing connection file: %s", cf)
MinRK
enable IPC transport for kernels...
r7321 write_connection_file(cf, ip=self.ip, key=self.session.key, transport=self.transport,
MinRK
use connection files instead of ports to connect to kernels...
r4958 shell_port=self.shell_port, stdin_port=self.stdin_port, hb_port=self.hb_port,
iopub_port=self.iopub_port)
MinRK
kernel app cleans up connection files that it wrote
r6889
def cleanup_connection_file(self):
MinRK
improve default ipc file locations...
r9175 cf = self.abs_connection_file
self.log.debug("Cleaning up connection file: %s", cf)
MinRK
kernel app cleans up connection files that it wrote
r6889 try:
os.remove(cf)
except (IOError, OSError):
pass
MinRK
enable IPC transport for kernels...
r7321
Brian Granger
Fixing bug in cleanup of ipc files and adding new to shutdown....
r9119 self.cleanup_ipc_files()
MinRK
enable IPC transport for kernels...
r7321
Brian Granger
Fixing bug in cleanup of ipc files and adding new to shutdown....
r9119 def cleanup_ipc_files(self):
MinRK
enable IPC transport for kernels...
r7321 """cleanup ipc files if we wrote them"""
if self.transport != 'ipc':
return
for port in (self.shell_port, self.iopub_port, self.stdin_port, self.hb_port):
ipcfile = "%s-%i" % (self.ip, port)
try:
os.remove(ipcfile)
except (IOError, OSError):
pass
MinRK
use connection files instead of ports to connect to kernels...
r4958
def init_connection_file(self):
if not self.connection_file:
self.connection_file = "kernel-%s.json"%os.getpid()
MinRK
protect kernelapp/qtconsole from invalid connection files...
r4986 try:
self.load_connection_file()
except Exception:
self.log.error("Failed to load connection file: %r", self.connection_file, exc_info=True)
self.exit(1)
MinRK
enable HMAC message signing by default in kernels...
r4962
MinRK
zmq kernels now started via newapp
r3970 def init_sockets(self):
# Create a context, a session, and the kernel sockets.
MinRK
fix typo in log message format in zmq.kernelapp
r4240 self.log.info("Starting the kernel at pid: %i", os.getpid())
MinRK
zmq kernels now started via newapp
r3970 context = zmq.Context.instance()
# Uncomment this to try closing the context.
# atexit.register(context.term)
MinRK
use ROUTER/DEALER socket names instead of XREP/XREQ...
r4725 self.shell_socket = context.socket(zmq.ROUTER)
MinRK
zmq kernels now started via newapp
r3970 self.shell_port = self._bind_socket(self.shell_socket, self.shell_port)
MinRK
use ROUTER/DEALER socket names instead of XREP/XREQ...
r4725 self.log.debug("shell ROUTER Channel on port: %i"%self.shell_port)
MinRK
zmq kernels now started via newapp
r3970
self.iopub_socket = context.socket(zmq.PUB)
self.iopub_port = self._bind_socket(self.iopub_socket, self.iopub_port)
self.log.debug("iopub PUB Channel on port: %i"%self.iopub_port)
MinRK
use ROUTER/DEALER sockets for stdin...
r4952 self.stdin_socket = context.socket(zmq.ROUTER)
MinRK
zmq kernels now started via newapp
r3970 self.stdin_port = self._bind_socket(self.stdin_socket, self.stdin_port)
MinRK
use ROUTER/DEALER sockets for stdin...
r4952 self.log.debug("stdin ROUTER Channel on port: %i"%self.stdin_port)
MinRK
split init_sockets into a few steps, so they can be better reused
r6885
def init_heartbeat(self):
"""start the heart beating"""
MinRK
kernel heartbeat does not share zmq context with rest of the app...
r5883 # heartbeat doesn't share context, because it mustn't be blocked
# by the GIL, which is accessed by libzmq when freeing zero-copy messages
hb_ctx = zmq.Context()
MinRK
enable IPC transport for kernels...
r7321 self.heartbeat = Heartbeat(hb_ctx, (self.transport, self.ip, self.hb_port))
MinRK
zmq kernels now started via newapp
r3970 self.hb_port = self.heartbeat.port
self.log.debug("Heartbeat REP Channel on port: %i"%self.hb_port)
MinRK
minor fixes to allow kernel to be re-entrant...
r6826 self.heartbeat.start()
MinRK
zmq kernels now started via newapp
r3970
MinRK
use connection files instead of ports to connect to kernels...
r4958 # Helper to make it easier to connect to an existing kernel.
MinRK
make sure connection info gets printed when starting a kernel...
r4121 # set log-level to critical, to make sure it is output
self.log.critical("To connect another client to this kernel, use:")
MinRK
split init_sockets into a few steps, so they can be better reused
r6885
def log_connection_info(self):
"""display connection info, and store ports"""
MinRK
fix kernel connection messsage with non-default profile...
r4980 basename = os.path.basename(self.connection_file)
if basename == self.connection_file or \
os.path.dirname(self.connection_file) == self.profile_dir.security_dir:
MinRK
use connection files instead of ports to connect to kernels...
r4958 # use shortname
MinRK
fix kernel connection messsage with non-default profile...
r4980 tail = basename
MinRK
use connection files instead of ports to connect to kernels...
r4958 if self.profile != 'default':
MinRK
fix kernel connection messsage with non-default profile...
r4980 tail += " --profile %s" % self.profile
MinRK
use connection files instead of ports to connect to kernels...
r4958 else:
tail = self.connection_file
self.log.critical("--existing %s", tail)
MinRK
zmq kernels now started via newapp
r3970
self.ports = dict(shell=self.shell_port, iopub=self.iopub_port,
stdin=self.stdin_port, hb=self.hb_port)
def init_session(self):
"""create our session object"""
MinRK
enable HMAC message signing by default in kernels...
r4962 default_secure(self.config)
MinRK
finish plumbing config to Session objects...
r4015 self.session = Session(config=self.config, username=u'kernel')
MinRK
zmq kernels now started via newapp
r3970
Min RK
fix ipython-qtconsole when run as a GUI script
r4112 def init_blackhole(self):
"""redirects stdout/stderr to devnull if necessary"""
MinRK
zmq kernels now started via newapp
r3970 if self.no_stdout or self.no_stderr:
Brandon Parsons
substitute open(...) for file(...)...
r6650 blackhole = open(os.devnull, 'w')
MinRK
zmq kernels now started via newapp
r3970 if self.no_stdout:
sys.stdout = sys.__stdout__ = blackhole
if self.no_stderr:
sys.stderr = sys.__stderr__ = blackhole
Min RK
fix ipython-qtconsole when run as a GUI script
r4112
def init_io(self):
"""Redirect input streams and set a display hook."""
MinRK
zmq kernels now started via newapp
r3970 if self.outstream_class:
outstream_factory = import_item(str(self.outstream_class))
sys.stdout = outstream_factory(self.session, self.iopub_socket, u'stdout')
sys.stderr = outstream_factory(self.session, self.iopub_socket, u'stderr')
if self.displayhook_class:
displayhook_factory = import_item(str(self.displayhook_class))
sys.displayhook = displayhook_factory(self.session, self.iopub_socket)
MinRK
use IOLoop in ipkernel...
r6790 def init_signal(self):
signal.signal(signal.SIGINT, signal.SIG_IGN)
MinRK
zmq kernels now started via newapp
r3970 def init_kernel(self):
"""Create the Kernel object itself"""
MinRK
move IPKernelApp from zmq.ipkernel to zmq.kernelapp...
r9357 shell_stream = ZMQStream(self.shell_socket)
kernel = Kernel(config=self.config, session=self.session,
shell_streams=[shell_stream],
MinRK
zmq kernels now started via newapp
r3970 iopub_socket=self.iopub_socket,
stdin_socket=self.stdin_socket,
MinRK
move IPKernelApp from zmq.ipkernel to zmq.kernelapp...
r9357 log=self.log,
profile_dir=self.profile_dir,
MinRK
zmq kernels now started via newapp
r3970 )
MinRK
move IPKernelApp from zmq.ipkernel to zmq.kernelapp...
r9357 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)
MinRK
zmq kernels now started via newapp
r3970
MinRK
catch_config -> catch_config_error
r5214 @catch_config_error
MinRK
zmq kernels now started via newapp
r3970 def initialize(self, argv=None):
MinRK
move IPKernelApp from zmq.ipkernel to zmq.kernelapp...
r9357 super(IPKernelApp, self).initialize(argv)
Min RK
fix ipython-qtconsole when run as a GUI script
r4112 self.init_blackhole()
MinRK
use connection files instead of ports to connect to kernels...
r4958 self.init_connection_file()
MinRK
zmq kernels now started via newapp
r3970 self.init_session()
self.init_poller()
self.init_sockets()
MinRK
split init_sockets into a few steps, so they can be better reused
r6885 self.init_heartbeat()
# writing/displaying connection info must be *after* init_sockets/heartbeat
self.log_connection_info()
MinRK
use connection files instead of ports to connect to kernels...
r4958 self.write_connection_file()
MinRK
zmq kernels now started via newapp
r3970 self.init_io()
MinRK
use IOLoop in ipkernel...
r6790 self.init_signal()
MinRK
zmq kernels now started via newapp
r3970 self.init_kernel()
MinRK
move IPKernelApp from zmq.ipkernel to zmq.kernelapp...
r9357 # shell init steps
self.init_path()
self.init_shell()
self.init_gui_pylab()
self.init_extensions()
self.init_code()
MinRK
flush messages printed during startup...
r5361 # flush stdout/stderr, so that anything written to these streams during
# initialization do not get associated with the first execution request
sys.stdout.flush()
sys.stderr.flush()
MinRK
zmq kernels now started via newapp
r3970
def start(self):
if self.poller is not None:
self.poller.start()
MinRK
use IOLoop in ipkernel...
r6790 self.kernel.start()
MinRK
zmq kernels now started via newapp
r3970 try:
MinRK
use IOLoop in ipkernel...
r6790 ioloop.IOLoop.instance().start()
MinRK
zmq kernels now started via newapp
r3970 except KeyboardInterrupt:
pass
MinRK
code updates per review of PR #454
r4021
MinRK
move IPKernelApp from zmq.ipkernel to zmq.kernelapp...
r9357
def main():
"""Run an IPKernel as an application"""
app = IPKernelApp.instance()
app.initialize()
app.start()
if __name__ == '__main__':
main()