##// END OF EJS Templates
don't inject unicode into sys.argv...
don't inject unicode into sys.argv Protects %run and `ipython script.py` from getting unicode sys.argv on Python 2 closes #710

File last commit:

r4986:64e90b1e
r5098:71d3d186
Show More
kernelapp.py
298 lines | 11.7 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
#-----------------------------------------------------------------------------
# Standard library imports.
MinRK
protect kernelapp/qtconsole from invalid connection files...
r4986 import json
MinRK
zmq kernels now started via newapp
r3970 import os
import sys
# System library imports.
import zmq
# IPython imports.
from IPython.core.ultratb import FormattedTB
MinRK
rename core.newapplication -> core.application
r4023 from IPython.core.application import (
MinRK
zmq kernels now started via newapp
r3970 BaseIPythonApplication, base_flags, base_aliases
)
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
Thomas Kluyver
Use DottedObjectName traits in zmq and parallel modules.
r4055 from IPython.utils.traitlets import (Any, Instance, Dict, Unicode, Int, Bool,
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):
name='pykernel'
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
Thomas Kluyver
Use DottedObjectName traits in zmq and parallel modules.
r4055 kernel_class = DottedObjectName('IPython.zmq.pykernel.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
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.")
hb_port = Int(0, config=True, help="set the heartbeat port [default: random]")
shell_port = Int(0, config=True, help="set the shell (XREP) port [default: random]")
iopub_port = Int(0, config=True, help="set the iopub (PUB) port [default: random]")
stdin_port = Int(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
parent = Int(0, config=True,
help="""kill this process if its parent dies. On Windows, the argument
specifies the HANDLE of the parent process, otherwise it is simply boolean.
""")
interrupt = Int(0, config=True,
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)
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)
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
zmq kernels now started via newapp
r3970
self.heartbeat = Heartbeat(context, (self.ip, self.hb_port))
self.hb_port = self.heartbeat.port
self.log.debug("Heartbeat REP Channel on port: %i"%self.hb_port)
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
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:
blackhole = file(os.devnull, 'w')
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)
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)
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
use connection files instead of ports to connect to kernels...
r4958 # writing connection file must be *after* init_sockets
self.write_connection_file()
MinRK
zmq kernels now started via newapp
r3970 self.init_io()
self.init_kernel()
def start(self):
self.heartbeat.start()
if self.poller is not None:
self.poller.start()
try:
self.kernel.start()
except KeyboardInterrupt:
pass
MinRK
code updates per review of PR #454
r4021