##// END OF EJS Templates
use idle status message to signal when outputs are complete
use idle status message to signal when outputs are complete

File last commit:

r6889:3fab9949
r7494:b49ad41b
Show More
kernelapp.py
333 lines | 13.0 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
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
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 )
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
add Integer traitlet...
r5344 from IPython.utils.traitlets import (Any, Instance, Dict, Unicode, Integer, Bool,
Thomas Kluyver
Use DottedObjectName traits in zmq and parallel modules.
r4055 DottedObjectName)
MinRK
zmq kernels now started via newapp
r3970 from IPython.utils.importstring import import_item
# local imports
MinRK
use connection files instead of ports to connect to kernels...
r4958 from IPython.zmq.entry_point import write_connection_file
MinRK
zmq kernels now started via newapp
r3970 from IPython.zmq.heartbeat import Heartbeat
from IPython.zmq.parentpoller import ParentPollerUnix, ParentPollerWindows
MinRK
enable HMAC message signing by default in kernels...
r4962 from IPython.zmq.session import (
Session, session_flags, session_aliases, default_secure,
)
MinRK
zmq kernels now started via newapp
r3970
#-----------------------------------------------------------------------------
# Flags and Aliases
#-----------------------------------------------------------------------------
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',
MinRK
use connection files instead of ports to connect to kernels...
r4958 'f' : 'KernelApp.connection_file',
MinRK
zmq kernels now started via newapp
r3970 'parent': 'KernelApp.parent',
})
if sys.platform.startswith('win'):
kernel_aliases['interrupt'] = 'KernelApp.interrupt'
kernel_flags = dict(base_flags)
kernel_flags.update({
'no-stdout' : (
{'KernelApp' : {'no_stdout' : True}},
"redirect stdout to the null device"),
'no-stderr' : (
{'KernelApp' : {'no_stderr' : True}},
"redirect stderr to the null device"),
})
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
#-----------------------------------------------------------------------------
# Application class for starting a Kernel
#-----------------------------------------------------------------------------
class KernelApp(BaseIPythonApplication):
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
finish plumbing config to Session objects...
r4015 classes = [Session]
MinRK
zmq kernels now started via newapp
r3970 # the kernel class, as an importstring
MinRK
remove references to removed pykernel and associated pure flag
r6806 kernel_class = DottedObjectName('IPython.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)
session = Instance('IPython.zmq.session.Session')
ports = Dict()
MinRK
kernel app cleans up connection files that it wrote
r6889 _full_connection_file = Unicode()
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:
ip = Unicode(LOCALHOST, config=True,
help="Set the IP or interface on which the kernel will listen.")
MinRK
add Integer traitlet...
r5344 hb_port = Integer(0, config=True, help="set the heartbeat port [default: random]")
shell_port = Integer(0, config=True, help="set the shell (XREP) port [default: random]")
iopub_port = Integer(0, config=True, help="set the iopub (PUB) port [default: random]")
stdin_port = Integer(0, config=True, help="set the stdin (XREQ) 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
clients to this kernel. By default, this file will be created in the security-dir
of the current profile, but can be specified by absolute path.
""")
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")
Thomas Kluyver
Use DottedObjectName traits in zmq and parallel modules.
r4055 outstream_class = DottedObjectName('IPython.zmq.iostream.OutStream',
config=True, help="The importstring for the OutStream factory")
Thomas Kluyver
Merge branch 'traitlets-str' into traitlets-str-merge...
r4073 displayhook_class = DottedObjectName('IPython.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
Interrupt this process when the parent is signalled.
""")
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):
iface = 'tcp://%s' % self.ip
if port <= 0:
port = s.bind_to_random_port(iface)
else:
s.bind(iface + ':%i'%port)
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)
if self.ip == LOCALHOST and 'ip' in cfg:
# 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"""
if os.path.basename(self.connection_file) == self.connection_file:
cf = os.path.join(self.profile_dir.security_dir, self.connection_file)
else:
cf = self.connection_file
write_connection_file(cf, ip=self.ip, key=self.session.key,
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
self._full_connection_file = cf
def cleanup_connection_file(self):
cf = self._full_connection_file
self.log.debug("cleaning up connection file: %r", cf)
try:
os.remove(cf)
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()
self.heartbeat = Heartbeat(hb_ctx, (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"""
kernel_factory = import_item(str(self.kernel_class))
self.kernel = kernel_factory(config=self.config, session=self.session,
shell_socket=self.shell_socket,
iopub_socket=self.iopub_socket,
stdin_socket=self.stdin_socket,
MinRK
use logging instead of `print >>` in pykernel
r3981 log=self.log
MinRK
zmq kernels now started via newapp
r3970 )
self.kernel.record_ports(self.ports)
MinRK
catch_config -> catch_config_error
r5214 @catch_config_error
MinRK
zmq kernels now started via newapp
r3970 def initialize(self, argv=None):
super(KernelApp, 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
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