##// END OF EJS Templates
zmqterminal subclasses TerminalInteractiveShell/IPApp...
zmqterminal subclasses TerminalInteractiveShell/IPApp this does a lot of the boiler plate for us, so Omar's communication code is used in place of run_cell / complete. Now colors, prompts, indentation, cl-args, etc. are all inherited from regular existing code. keyboard interrupts don't work yet, the kernel just dies...

File last commit:

r5600:8360d3a9
r5600:8360d3a9
Show More
app.py
161 lines | 5.6 KiB | text/x-python | PythonLexer
from __future__ import print_function
import signal
import sys
import time
from IPython.frontend.terminal.ipapp import TerminalIPythonApp
from IPython.utils.traitlets import (
Dict, List, Unicode, Int, CaselessStrEnum, CBool, Any
)
from IPython.zmq.ipkernel import (
flags as ipkernel_flags,
aliases as ipkernel_aliases,
IPKernelApp
)
from IPython.zmq.session import Session
from IPython.zmq.zmqshell import ZMQInteractiveShell
from IPython.zmq.blockingkernelmanager import BlockingKernelManager
from IPython.zmq.ipkernel import (
flags as ipkernel_flags,
aliases as ipkernel_aliases,
IPKernelApp
)
from IPython.frontend.zmqterminal.interactiveshell import ZMQTerminalInteractiveShell
#-----------------------------------------------------------------------------
# Network Constants
#-----------------------------------------------------------------------------
from IPython.utils.localinterfaces import LOCALHOST, LOCAL_IPS
#-----------------------------------------------------------------------------
# Flags and Aliases
#-----------------------------------------------------------------------------
flags = dict(ipkernel_flags)
frontend_flags = {
'existing' : ({'ZMQTerminalIPythonApp' : {'existing' : True}},
"Connect to an existing kernel."),
}
flags.update(frontend_flags)
# the flags that are specific to the frontend
# these must be scrubbed before being passed to the kernel,
# or it will raise an error on unrecognized flags
frontend_flags = frontend_flags.keys()
aliases = dict(ipkernel_aliases)
frontend_aliases = dict(
hb = 'ZMQTerminalIPythonApp.hb_port',
shell = 'ZMQTerminalIPythonApp.shell_port',
iopub = 'ZMQTerminalIPythonApp.iopub_port',
stdin = 'ZMQTerminalIPythonApp.stdin_port',
ip = 'ZMQTerminalIPythonApp.ip',
)
aliases.update(frontend_aliases)
# also scrub aliases from the frontend
frontend_flags.extend(frontend_aliases.keys())
#-----------------------------------------------------------------------------
# Classes
#-----------------------------------------------------------------------------
class ZMQTerminalIPythonApp(TerminalIPythonApp):
"""Start a terminal frontend to the IPython zmq kernel."""
kernel_argv = List(Unicode)
flags = Dict(flags)
aliases = Dict(aliases)
classes = List([IPKernelApp, ZMQTerminalInteractiveShell])
# connection info:
ip = Unicode(LOCALHOST, config=True,
help="""Set the kernel\'s IP address [default localhost].
If the IP address is something other than localhost, then
Consoles on other machines will be able to connect
to the Kernel, so be careful!"""
)
pure = False
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]")
existing = CBool(False, config=True,
help="Whether to connect to an already running Kernel.")
# from qtconsoleapp:
def parse_command_line(self, argv=None):
super(ZMQTerminalIPythonApp, self).parse_command_line(argv)
if argv is None:
argv = sys.argv[1:]
self.kernel_argv = list(argv) # copy
# kernel should inherit default config file from frontend
self.kernel_argv.append("--KernelApp.parent_appname='%s'"%self.name)
# scrub frontend-specific flags
for a in argv:
if a.startswith('-'):
key = a.lstrip('-').split('=')[0]
if key in frontend_flags:
self.kernel_argv.remove(a)
def init_kernel_manager(self):
"""init kernel manager (from qtconsole)"""
# Don't let Qt or ZMQ swallow KeyboardInterupts.
# signal.signal(signal.SIGINT, signal.SIG_DFL)
# Create a KernelManager and start a kernel.
self.kernel_manager = BlockingKernelManager(
shell_address=(self.ip, self.shell_port),
sub_address=(self.ip, self.iopub_port),
stdin_address=(self.ip, self.stdin_port),
hb_address=(self.ip, self.hb_port),
config=self.config
)
# start the kernel
if not self.existing:
kwargs = dict(ip=self.ip, ipython=not self.pure)
kwargs['extra_arguments'] = self.kernel_argv
self.kernel_manager.start_kernel(**kwargs)
# wait for kernel to start
time.sleep(0.5)
self.kernel_manager.start_channels()
# relay sigint to kernel
signal.signal(signal.SIGINT, self.handle_sigint)
def init_shell(self):
self.init_kernel_manager()
self.shell = ZMQTerminalInteractiveShell.instance(config=self.config,
display_banner=False, profile_dir=self.profile_dir,
ipython_dir=self.ipython_dir, kernel_manager=self.kernel_manager)
def handle_sigint(self, *args):
# FIXME: this doesn't work, the kernel just dies every time
self.shell.write('KeyboardInterrupt\n')
self.kernel_manager.interrupt_kernel()
def init_code(self):
# no-op in the frontend, code gets run in the backend
pass
def launch_new_instance():
"""Create and run a full blown IPython instance"""
app = ZMQTerminalIPythonApp.instance()
app.initialize()
app.start()
if __name__ == '__main__':
launch_new_instance()