1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
|
""" 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.
"""
# Copyright (c) IPython Development Team.
# Distributed under the terms of the Modified BSD License.
from __future__ import print_function
import signal
import sys
from traitlets import (
Dict, Any
)
from traitlets.config import catch_config_error, boolean_flag
from jupyter_core.application import JupyterApp, base_aliases, base_flags
from jupyter_client.consoleapp import (
JupyterConsoleApp, app_aliases, app_flags,
)
from jupyter_console.ptshell import ZMQTerminalInteractiveShell
from jupyter_console import __version__
#-----------------------------------------------------------------------------
# Globals
#-----------------------------------------------------------------------------
_examples = """
jupyter console # start the ZMQ-based console
jupyter console --existing # connect to an existing ipython session
"""
#-----------------------------------------------------------------------------
# Flags and Aliases
#-----------------------------------------------------------------------------
# copy flags from mixin:
flags = dict(base_flags)
# start with mixin frontend flags:
# update full dict with frontend flags:
flags.update(app_flags)
flags.update(boolean_flag(
'simple-prompt', 'ZMQTerminalInteractiveShell.simple_prompt',
"Force simple minimal prompt using `raw_input`",
"Use a rich interactive prompt with prompt_toolkit"
))
# copy flags from mixin
aliases = dict(base_aliases)
aliases.update(app_aliases)
frontend_aliases = set(app_aliases.keys())
frontend_flags = set(app_flags.keys())
#-----------------------------------------------------------------------------
# Classes
#-----------------------------------------------------------------------------
class ZMQTerminalIPythonApp(JupyterApp, JupyterConsoleApp): # type:ignore[misc]
name = "jupyter-console"
version = __version__
"""Start a terminal frontend to the IPython zmq kernel."""
description = """
The Jupyter 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:
jupyter 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 = [ZMQTerminalInteractiveShell] + JupyterConsoleApp.classes # type:ignore[operator]
flags = Dict(flags) # type:ignore[assignment]
aliases = Dict(aliases) # type:ignore[assignment]
frontend_aliases = Any(frontend_aliases)
frontend_flags = Any(frontend_flags)
subcommands = Dict()
force_interact = True
def parse_command_line(self, argv=None):
super(ZMQTerminalIPythonApp, self).parse_command_line(argv)
self.build_kernel_argv(self.extra_args)
def init_shell(self):
JupyterConsoleApp.initialize(self)
# relay sigint to kernel
signal.signal(signal.SIGINT, self.handle_sigint)
self.shell = ZMQTerminalInteractiveShell.instance(parent=self,
manager=self.kernel_manager,
client=self.kernel_client,
confirm_exit=self.confirm_exit,
)
self.shell.own_kernel = not self.existing
def init_gui_pylab(self):
# no-op, because we don't want to import matplotlib in the frontend.
pass
def handle_sigint(self, *args):
if self.shell._executing:
if self.kernel_manager:
self.kernel_manager.interrupt_kernel()
else:
print("ERROR: Cannot interrupt kernels we didn't start.",
file = sys.stderr)
else:
# raise the KeyboardInterrupt if we aren't waiting for execution,
# so that the interact loop advances, and prompt is redrawn, etc.
raise KeyboardInterrupt
@catch_config_error
def initialize(self, argv=None):
"""Do actions after construct, but before starting the app."""
super(ZMQTerminalIPythonApp, self).initialize(argv)
if self._dispatching:
return
# create the shell
self.init_shell()
# and draw the banner
self.init_banner()
def init_banner(self):
"""optionally display the banner"""
self.shell.show_banner()
def start(self):
# JupyterApp.start dispatches on NoStart
super(ZMQTerminalIPythonApp, self).start()
self.log.debug("Starting the jupyter console mainloop...")
self.shell.mainloop()
main = launch_new_instance = ZMQTerminalIPythonApp.launch_instance
if __name__ == '__main__':
main()
|