##// END OF EJS Templates
Adjustment to console signal-handling...
Adjustment to console signal-handling Do not explicitly interrupt the kernel, because the subprocess already gets the interrupt. Once we properly prevent this, then the interrupt can be restored. Also, the KeyboardInterrupt is still raised if not executing, in order to restore the prompt. In ipkernel, the interrupt is ignored during poll, and restored after the loop exits, to prevent it being swallowed in future code that expects normal sigint behavior.

File last commit:

r5615:9a0989a4
r5615:9a0989a4
Show More
app.py
149 lines | 5.0 KiB | text/x-python | PythonLexer
""" A minimal application using the ZMQ-based terminal IPython frontend.
This is not a complete console app, as subprocess will not be able to receive
input, there is no real readline support, among other limitations.
Authors:
* Min RK
* Paul Ivanov
"""
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
import signal
import sys
import time
from IPython.frontend.terminal.ipapp import TerminalIPythonApp, frontend_flags as term_flags
from IPython.utils.traitlets import (
Dict, List, Unicode, Int, CaselessStrEnum, CBool, Any
)
from IPython.utils.warn import warn,error
from IPython.zmq.ipkernel import IPKernelApp
from IPython.zmq.session import Session, default_secure
from IPython.zmq.zmqshell import ZMQInteractiveShell
from IPython.frontend.kernelmixinapp import (
IPythonMixinConsoleApp, app_aliases, app_flags, aliases, app_aliases, flags
)
from IPython.frontend.terminal.console.interactiveshell import ZMQTerminalInteractiveShell
#-----------------------------------------------------------------------------
# Globals
#-----------------------------------------------------------------------------
_examples = """
ipython console # start the ZMQ-based console
ipython console --existing # connect to an existing ipython session
"""
#-----------------------------------------------------------------------------
# Flags and Aliases
#-----------------------------------------------------------------------------
# copy flags from mixin:
flags = dict(flags)
# start with mixin frontend flags:
frontend_flags = dict(app_flags)
# add TerminalIPApp flags:
frontend_flags.update(term_flags)
# pylab is not frontend-specific in two-process IPython
frontend_flags.pop('pylab')
# disable quick startup, as it won't propagate to the kernel anyway
frontend_flags.pop('quick')
# update full dict with frontend flags:
flags.update(frontend_flags)
# copy flags from mixin
aliases = dict(aliases)
# start with mixin frontend flags
frontend_aliases = dict(app_aliases)
# load updated frontend flags into full dict
aliases.update(frontend_aliases)
# get flags&aliases into sets, and remove a couple that
# shouldn't be scrubbed from backend flags:
frontend_aliases = set(frontend_aliases.keys())
frontend_flags = set(frontend_flags.keys())
#-----------------------------------------------------------------------------
# Classes
#-----------------------------------------------------------------------------
class ZMQTerminalIPythonApp(TerminalIPythonApp, IPythonMixinConsoleApp):
name = "ipython-console"
"""Start a terminal frontend to the IPython zmq kernel."""
description = """
The IPython terminal-based Console.
This launches a Console application inside a terminal.
The Console supports various extra features beyond the traditional
single-process Terminal IPython shell, such as connecting to an
existing ipython session, via:
ipython console --existing
where the previous session could have been created by another ipython
console, an ipython qtconsole, or by opening an ipython notebook.
"""
examples = _examples
classes = List([IPKernelApp, ZMQTerminalInteractiveShell, Session])
flags = Dict(flags)
aliases = Dict(aliases)
subcommands = Dict()
def parse_command_line(self, argv=None):
super(ZMQTerminalIPythonApp, self).parse_command_line(argv)
self.swallow_args(frontend_aliases,frontend_flags,argv=argv)
def init_shell(self):
IPythonMixinConsoleApp.initialize(self)
# relay sigint to kernel
signal.signal(signal.SIGINT, self.handle_sigint)
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):
if self.shell._executing:
if self.kernel_manager.has_kernel:
# interrupt already gets passed to subprocess by signal handler.
# Only if we prevent that should we need to explicitly call
# interrupt_kernel, until which time, this would result in a
# double-interrupt:
# self.kernel_manager.interrupt_kernel()
pass
else:
self.shell.write_err('\n')
error("Cannot interrupt kernels we didn't start.\n")
else:
# raise the KeyboardInterrupt if we aren't waiting for execution,
# so that the interact loop advances, and prompt is redrawn, etc.
raise KeyboardInterrupt
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()