interactiveshell.py
252 lines
| 9.9 KiB
| text/x-python
|
PythonLexer
MinRK
|
r5600 | # -*- coding: utf-8 -*- | ||
"""Frontend of ipython working with python-zmq | ||||
Ipython's frontend, is a ipython interface that send request to kernel and proccess the kernel's outputs. | ||||
For more details, see the ipython-zmq design | ||||
""" | ||||
#----------------------------------------------------------------------------- | ||||
# Copyright (C) 2011 The IPython Development Team | ||||
# | ||||
# Distributed under the terms of the BSD License. The full license is in | ||||
# the file COPYING, distributed as part of this software. | ||||
#----------------------------------------------------------------------------- | ||||
#----------------------------------------------------------------------------- | ||||
# Imports | ||||
#----------------------------------------------------------------------------- | ||||
from __future__ import print_function | ||||
import bdb | ||||
import sys | ||||
from Queue import Empty | ||||
from IPython.core.alias import AliasManager, AliasError | ||||
from IPython.utils.warn import warn, error, fatal | ||||
from IPython.utils import io | ||||
from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell | ||||
from IPython.frontend.zmqterminal.completer import ZMQCompleter | ||||
class ZMQTerminalInteractiveShell(TerminalInteractiveShell): | ||||
"""A subclass of TerminalInteractiveShell that """ | ||||
def __init__(self, *args, **kwargs): | ||||
self.km = kwargs.pop('kernel_manager') | ||||
self.session_id = self.km.session.session | ||||
super(ZMQTerminalInteractiveShell, self).__init__(*args, **kwargs) | ||||
def init_completer(self): | ||||
"""Initialize the completion machinery. | ||||
This creates completion machinery that can be used by client code, | ||||
either interactively in-process (typically triggered by the readline | ||||
library), programatically (such as in test suites) or out-of-prcess | ||||
(typically over the network by remote frontends). | ||||
""" | ||||
from IPython.core.completerlib import (module_completer, | ||||
magic_run_completer, cd_completer) | ||||
self.Completer = ZMQCompleter(self, self.km) | ||||
self.set_hook('complete_command', module_completer, str_key = 'import') | ||||
self.set_hook('complete_command', module_completer, str_key = 'from') | ||||
self.set_hook('complete_command', magic_run_completer, str_key = '%run') | ||||
self.set_hook('complete_command', cd_completer, str_key = '%cd') | ||||
# Only configure readline if we truly are using readline. IPython can | ||||
# do tab-completion over the network, in GUIs, etc, where readline | ||||
# itself may be absent | ||||
if self.has_readline: | ||||
self.set_readline_completer() | ||||
def run_cell(self, cell, store_history=True): | ||||
"""Run a complete IPython cell. | ||||
Parameters | ||||
---------- | ||||
cell : str | ||||
The code (including IPython code such as %magic functions) to run. | ||||
store_history : bool | ||||
If True, the raw and translated cell will be stored in IPython's | ||||
history. For user code calling back into IPython's machinery, this | ||||
should be set to False. | ||||
""" | ||||
if (not cell) or cell.isspace(): | ||||
return | ||||
# shell_channel.execute takes 'hidden', which is the inverse of store_hist | ||||
msg_id = self.km.shell_channel.execute(cell, not store_history) | ||||
while not self.km.shell_channel.msg_ready(): | ||||
try: | ||||
self.handle_stdin_request(timeout=0.05) | ||||
except Empty: | ||||
pass | ||||
self.handle_execute_reply(msg_id) | ||||
#----------------- | ||||
# message handlers | ||||
#----------------- | ||||
def handle_execute_reply(self, msg_id): | ||||
msg = self.km.shell_channel.get_msg() | ||||
if msg["parent_header"]["msg_id"] == msg_id: | ||||
if msg["content"]["status"] == 'ok' : | ||||
self.handle_iopub() | ||||
elif msg["content"]["status"] == 'error': | ||||
for frame in msg["content"]["traceback"]: | ||||
print(frame, file=io.stderr) | ||||
MinRK
|
r5602 | self.execution_count = int(msg["content"]["execution_count"] + 1) | ||
MinRK
|
r5600 | |||
def handle_iopub(self): | ||||
""" Method to procces subscribe channel's messages | ||||
This method reads a message and processes the content in different | ||||
outputs like stdout, stderr, pyout and status | ||||
Arguments: | ||||
sub_msg: message receive from kernel in the sub socket channel | ||||
capture by kernel manager. | ||||
""" | ||||
while self.km.sub_channel.msg_ready(): | ||||
sub_msg = self.km.sub_channel.get_msg() | ||||
msg_type = sub_msg['header']['msg_type'] | ||||
if self.session_id == sub_msg['parent_header']['session']: | ||||
if msg_type == 'status' : | ||||
if sub_msg["content"]["execution_state"] == "busy" : | ||||
pass | ||||
elif msg_type == 'stream' : | ||||
if sub_msg["content"]["name"] == "stdout": | ||||
print(sub_msg["content"]["data"], file=io.stdout, end="") | ||||
io.stdout.flush() | ||||
elif sub_msg["content"]["name"] == "stderr" : | ||||
print(sub_msg["content"]["data"], file=io.stderr, end="") | ||||
io.stderr.flush() | ||||
elif msg_type == 'pyout': | ||||
format_dict = sub_msg["content"]["data"] | ||||
# taken from DisplayHook.__call__: | ||||
hook = self.displayhook | ||||
hook.start_displayhook() | ||||
hook.write_output_prompt() | ||||
hook.write_format_data(format_dict) | ||||
hook.log_output(format_dict) | ||||
hook.finish_displayhook() | ||||
def handle_stdin_request(self, timeout=0.1): | ||||
""" Method to capture raw_input | ||||
""" | ||||
msg_rep = self.km.stdin_channel.get_msg(timeout=timeout) | ||||
if self.session_id == msg_rep["parent_header"]["session"] : | ||||
raw_data = raw_input(msg_rep["content"]["prompt"]) | ||||
self.km.stdin_channel.input(raw_data) | ||||
def mainloop(self, display_banner=False): | ||||
while True: | ||||
try: | ||||
self.interact(display_banner=display_banner) | ||||
#self.interact_with_readline() | ||||
# XXX for testing of a readline-decoupled repl loop, call | ||||
# interact_with_readline above | ||||
break | ||||
except KeyboardInterrupt: | ||||
# this should not be necessary, but KeyboardInterrupt | ||||
# handling seems rather unpredictable... | ||||
self.write("\nKeyboardInterrupt in interact()\n") | ||||
def interact(self, display_banner=None): | ||||
"""Closely emulate the interactive Python console.""" | ||||
# batch run -> do not interact | ||||
if self.exit_now: | ||||
return | ||||
if display_banner is None: | ||||
display_banner = self.display_banner | ||||
if isinstance(display_banner, basestring): | ||||
self.show_banner(display_banner) | ||||
elif display_banner: | ||||
self.show_banner() | ||||
more = False | ||||
if self.has_readline: | ||||
self.readline_startup_hook(self.pre_readline) | ||||
# exit_now is set by a call to %Exit or %Quit, through the | ||||
# ask_exit callback. | ||||
while not self.exit_now: | ||||
if not self.km.is_alive: | ||||
Paul Ivanov
|
r5601 | ans = self.raw_input("kernel died, restart ([y]/n)?") | ||
MinRK
|
r5600 | if not ans.lower().startswith('n'): | ||
self.km.restart_kernel(True) | ||||
else: | ||||
self.exit_now=True | ||||
continue | ||||
self.hooks.pre_prompt_hook() | ||||
if more: | ||||
try: | ||||
prompt = self.hooks.generate_prompt(True) | ||||
except: | ||||
self.showtraceback() | ||||
if self.autoindent: | ||||
self.rl_do_indent = True | ||||
else: | ||||
try: | ||||
prompt = self.hooks.generate_prompt(False) | ||||
except: | ||||
self.showtraceback() | ||||
try: | ||||
line = self.raw_input(prompt) | ||||
if self.exit_now: | ||||
# quick exit on sys.std[in|out] close | ||||
break | ||||
if self.autoindent: | ||||
self.rl_do_indent = False | ||||
except KeyboardInterrupt: | ||||
#double-guard against keyboardinterrupts during kbdint handling | ||||
try: | ||||
self.write('\nKeyboardInterrupt\n') | ||||
self.input_splitter.reset() | ||||
more = False | ||||
except KeyboardInterrupt: | ||||
pass | ||||
except EOFError: | ||||
if self.autoindent: | ||||
self.rl_do_indent = False | ||||
if self.has_readline: | ||||
self.readline_startup_hook(None) | ||||
self.write('\n') | ||||
self.exit() | ||||
except bdb.BdbQuit: | ||||
warn('The Python debugger has exited with a BdbQuit exception.\n' | ||||
'Because of how pdb handles the stack, it is impossible\n' | ||||
'for IPython to properly format this particular exception.\n' | ||||
'IPython will resume normal operation.') | ||||
except: | ||||
# exceptions here are VERY RARE, but they can be triggered | ||||
# asynchronously by signal handlers, for example. | ||||
self.showtraceback() | ||||
else: | ||||
self.input_splitter.push(line) | ||||
more = self.input_splitter.push_accepts_more() | ||||
if (self.SyntaxTB.last_syntax_error and | ||||
self.autoedit_syntax): | ||||
self.edit_syntax_error() | ||||
if not more: | ||||
source_raw = self.input_splitter.source_reset() | ||||
self.run_cell(source_raw) | ||||
# Turn off the exit flag, so the mainloop can be restarted if desired | ||||
self.exit_now = False | ||||