PageRenderTime 42ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/IPython/frontend/terminal/console/interactiveshell.py

http://github.com/ipython/ipython
Python | 342 lines | 315 code | 9 blank | 18 comment | 33 complexity | 2cc4dc3d78ad03a7c0316e2302dd5f11 MD5 | raw file
Possible License(s): BSD-3-Clause, MIT, Apache-2.0
  1. # -*- coding: utf-8 -*-
  2. """Frontend of ipython working with python-zmq
  3. Ipython's frontend, is a ipython interface that send request to kernel and proccess the kernel's outputs.
  4. For more details, see the ipython-zmq design
  5. """
  6. #-----------------------------------------------------------------------------
  7. # Copyright (C) 2011 The IPython Development Team
  8. #
  9. # Distributed under the terms of the BSD License. The full license is in
  10. # the file COPYING, distributed as part of this software.
  11. #-----------------------------------------------------------------------------
  12. #-----------------------------------------------------------------------------
  13. # Imports
  14. #-----------------------------------------------------------------------------
  15. from __future__ import print_function
  16. import bdb
  17. import signal
  18. import sys
  19. import time
  20. from Queue import Empty
  21. from IPython.core.alias import AliasManager, AliasError
  22. from IPython.core import page
  23. from IPython.utils.warn import warn, error, fatal
  24. from IPython.utils import io
  25. from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
  26. from IPython.frontend.terminal.console.completer import ZMQCompleter
  27. class ZMQTerminalInteractiveShell(TerminalInteractiveShell):
  28. """A subclass of TerminalInteractiveShell that uses the 0MQ kernel"""
  29. _executing = False
  30. def __init__(self, *args, **kwargs):
  31. self.km = kwargs.pop('kernel_manager')
  32. self.session_id = self.km.session.session
  33. super(ZMQTerminalInteractiveShell, self).__init__(*args, **kwargs)
  34. def init_completer(self):
  35. """Initialize the completion machinery.
  36. This creates completion machinery that can be used by client code,
  37. either interactively in-process (typically triggered by the readline
  38. library), programatically (such as in test suites) or out-of-prcess
  39. (typically over the network by remote frontends).
  40. """
  41. from IPython.core.completerlib import (module_completer,
  42. magic_run_completer, cd_completer)
  43. self.Completer = ZMQCompleter(self, self.km)
  44. self.set_hook('complete_command', module_completer, str_key = 'import')
  45. self.set_hook('complete_command', module_completer, str_key = 'from')
  46. self.set_hook('complete_command', magic_run_completer, str_key = '%run')
  47. self.set_hook('complete_command', cd_completer, str_key = '%cd')
  48. # Only configure readline if we truly are using readline. IPython can
  49. # do tab-completion over the network, in GUIs, etc, where readline
  50. # itself may be absent
  51. if self.has_readline:
  52. self.set_readline_completer()
  53. def run_cell(self, cell, store_history=True):
  54. """Run a complete IPython cell.
  55. Parameters
  56. ----------
  57. cell : str
  58. The code (including IPython code such as %magic functions) to run.
  59. store_history : bool
  60. If True, the raw and translated cell will be stored in IPython's
  61. history. For user code calling back into IPython's machinery, this
  62. should be set to False.
  63. """
  64. if (not cell) or cell.isspace():
  65. return
  66. if cell.strip() == 'exit':
  67. # explicitly handle 'exit' command
  68. return self.ask_exit()
  69. self._executing = True
  70. # flush stale replies, which could have been ignored, due to missed heartbeats
  71. while self.km.shell_channel.msg_ready():
  72. self.km.shell_channel.get_msg()
  73. # shell_channel.execute takes 'hidden', which is the inverse of store_hist
  74. msg_id = self.km.shell_channel.execute(cell, not store_history)
  75. while not self.km.shell_channel.msg_ready() and self.km.is_alive:
  76. try:
  77. self.handle_stdin_request(timeout=0.05)
  78. except Empty:
  79. # display intermediate print statements, etc.
  80. self.handle_iopub()
  81. pass
  82. if self.km.shell_channel.msg_ready():
  83. self.handle_execute_reply(msg_id)
  84. self._executing = False
  85. #-----------------
  86. # message handlers
  87. #-----------------
  88. def handle_execute_reply(self, msg_id):
  89. msg = self.km.shell_channel.get_msg()
  90. if msg["parent_header"].get("msg_id", None) == msg_id:
  91. self.handle_iopub()
  92. content = msg["content"]
  93. status = content['status']
  94. if status == 'aborted':
  95. self.write('Aborted\n')
  96. return
  97. elif status == 'ok':
  98. # print execution payloads as well:
  99. for item in content["payload"]:
  100. text = item.get('text', None)
  101. if text:
  102. page.page(text)
  103. elif status == 'error':
  104. for frame in content["traceback"]:
  105. print(frame, file=io.stderr)
  106. self.execution_count = int(content["execution_count"] + 1)
  107. def handle_iopub(self):
  108. """ Method to procces subscribe channel's messages
  109. This method reads a message and processes the content in different
  110. outputs like stdout, stderr, pyout and status
  111. Arguments:
  112. sub_msg: message receive from kernel in the sub socket channel
  113. capture by kernel manager.
  114. """
  115. while self.km.sub_channel.msg_ready():
  116. sub_msg = self.km.sub_channel.get_msg()
  117. msg_type = sub_msg['header']['msg_type']
  118. parent = sub_msg["parent_header"]
  119. if (not parent) or self.session_id == parent['session']:
  120. if msg_type == 'status' :
  121. if sub_msg["content"]["execution_state"] == "busy" :
  122. pass
  123. elif msg_type == 'stream' :
  124. if sub_msg["content"]["name"] == "stdout":
  125. print(sub_msg["content"]["data"], file=io.stdout, end="")
  126. io.stdout.flush()
  127. elif sub_msg["content"]["name"] == "stderr" :
  128. print(sub_msg["content"]["data"], file=io.stderr, end="")
  129. io.stderr.flush()
  130. elif msg_type == 'pyout':
  131. self.execution_count = int(sub_msg["content"]["execution_count"])
  132. format_dict = sub_msg["content"]["data"]
  133. # taken from DisplayHook.__call__:
  134. hook = self.displayhook
  135. hook.start_displayhook()
  136. hook.write_output_prompt()
  137. hook.write_format_data(format_dict)
  138. hook.log_output(format_dict)
  139. hook.finish_displayhook()
  140. def handle_stdin_request(self, timeout=0.1):
  141. """ Method to capture raw_input
  142. """
  143. msg_rep = self.km.stdin_channel.get_msg(timeout=timeout)
  144. # in case any iopub came while we were waiting:
  145. self.handle_iopub()
  146. if self.session_id == msg_rep["parent_header"].get("session"):
  147. # wrap SIGINT handler
  148. real_handler = signal.getsignal(signal.SIGINT)
  149. def double_int(sig,frame):
  150. # call real handler (forwards sigint to kernel),
  151. # then raise local interrupt, stopping local raw_input
  152. real_handler(sig,frame)
  153. raise KeyboardInterrupt
  154. signal.signal(signal.SIGINT, double_int)
  155. try:
  156. raw_data = raw_input(msg_rep["content"]["prompt"])
  157. except EOFError:
  158. # turn EOFError into EOF character
  159. raw_data = '\x04'
  160. except KeyboardInterrupt:
  161. sys.stdout.write('\n')
  162. return
  163. finally:
  164. # restore SIGINT handler
  165. signal.signal(signal.SIGINT, real_handler)
  166. # only send stdin reply if there *was not* another request
  167. # or execution finished while we were reading.
  168. if not (self.km.stdin_channel.msg_ready() or self.km.shell_channel.msg_ready()):
  169. self.km.stdin_channel.input(raw_data)
  170. def mainloop(self, display_banner=False):
  171. while True:
  172. try:
  173. self.interact(display_banner=display_banner)
  174. #self.interact_with_readline()
  175. # XXX for testing of a readline-decoupled repl loop, call
  176. # interact_with_readline above
  177. break
  178. except KeyboardInterrupt:
  179. # this should not be necessary, but KeyboardInterrupt
  180. # handling seems rather unpredictable...
  181. self.write("\nKeyboardInterrupt in interact()\n")
  182. def wait_for_kernel(self, timeout=None):
  183. """method to wait for a kernel to be ready"""
  184. tic = time.time()
  185. self.km.hb_channel.unpause()
  186. while True:
  187. self.run_cell('1', False)
  188. if self.km.hb_channel.is_beating():
  189. # heart failure was not the reason this returned
  190. break
  191. else:
  192. # heart failed
  193. if timeout is not None and (time.time() - tic) > timeout:
  194. return False
  195. return True
  196. def interact(self, display_banner=None):
  197. """Closely emulate the interactive Python console."""
  198. # batch run -> do not interact
  199. if self.exit_now:
  200. return
  201. if display_banner is None:
  202. display_banner = self.display_banner
  203. if isinstance(display_banner, basestring):
  204. self.show_banner(display_banner)
  205. elif display_banner:
  206. self.show_banner()
  207. more = False
  208. # run a non-empty no-op, so that we don't get a prompt until
  209. # we know the kernel is ready. This keeps the connection
  210. # message above the first prompt.
  211. if not self.wait_for_kernel(3):
  212. error("Kernel did not respond\n")
  213. return
  214. if self.has_readline:
  215. self.readline_startup_hook(self.pre_readline)
  216. hlen_b4_cell = self.readline.get_current_history_length()
  217. else:
  218. hlen_b4_cell = 0
  219. # exit_now is set by a call to %Exit or %Quit, through the
  220. # ask_exit callback.
  221. while not self.exit_now:
  222. if not self.km.is_alive:
  223. # kernel died, prompt for action or exit
  224. action = "restart" if self.km.has_kernel else "wait for restart"
  225. ans = self.ask_yes_no("kernel died, %s ([y]/n)?" % action, default='y')
  226. if ans:
  227. if self.km.has_kernel:
  228. self.km.restart_kernel(True)
  229. self.wait_for_kernel(3)
  230. else:
  231. self.exit_now = True
  232. continue
  233. try:
  234. # protect prompt block from KeyboardInterrupt
  235. # when sitting on ctrl-C
  236. self.hooks.pre_prompt_hook()
  237. if more:
  238. try:
  239. prompt = self.prompt_manager.render('in2')
  240. except Exception:
  241. self.showtraceback()
  242. if self.autoindent:
  243. self.rl_do_indent = True
  244. else:
  245. try:
  246. prompt = self.separate_in + self.prompt_manager.render('in')
  247. except Exception:
  248. self.showtraceback()
  249. line = self.raw_input(prompt)
  250. if self.exit_now:
  251. # quick exit on sys.std[in|out] close
  252. break
  253. if self.autoindent:
  254. self.rl_do_indent = False
  255. except KeyboardInterrupt:
  256. #double-guard against keyboardinterrupts during kbdint handling
  257. try:
  258. self.write('\nKeyboardInterrupt\n')
  259. source_raw = self.input_splitter.source_raw_reset()[1]
  260. hlen_b4_cell = self._replace_rlhist_multiline(source_raw, hlen_b4_cell)
  261. more = False
  262. except KeyboardInterrupt:
  263. pass
  264. except EOFError:
  265. if self.autoindent:
  266. self.rl_do_indent = False
  267. if self.has_readline:
  268. self.readline_startup_hook(None)
  269. self.write('\n')
  270. self.exit()
  271. except bdb.BdbQuit:
  272. warn('The Python debugger has exited with a BdbQuit exception.\n'
  273. 'Because of how pdb handles the stack, it is impossible\n'
  274. 'for IPython to properly format this particular exception.\n'
  275. 'IPython will resume normal operation.')
  276. except:
  277. # exceptions here are VERY RARE, but they can be triggered
  278. # asynchronously by signal handlers, for example.
  279. self.showtraceback()
  280. else:
  281. self.input_splitter.push(line)
  282. more = self.input_splitter.push_accepts_more()
  283. if (self.SyntaxTB.last_syntax_error and
  284. self.autoedit_syntax):
  285. self.edit_syntax_error()
  286. if not more:
  287. source_raw = self.input_splitter.source_raw_reset()[1]
  288. hlen_b4_cell = self._replace_rlhist_multiline(source_raw, hlen_b4_cell)
  289. self.run_cell(source_raw)
  290. # Turn off the exit flag, so the mainloop can be restarted if desired
  291. self.exit_now = False