##// END OF EJS Templates
Merge pull request #6123 from minrk/zmq-console-echo-other...
Thomas Kluyver -
r18432:5ef19765 merge
parent child Browse files
Show More
@@ -136,15 +136,23 b' class BaseFrontendMixin(object):'
136 handler = getattr(self, '_handle_' + msg_type, None)
136 handler = getattr(self, '_handle_' + msg_type, None)
137 if handler:
137 if handler:
138 handler(msg)
138 handler(msg)
139
139
140 def _is_from_this_session(self, msg):
140 def from_here(self, msg):
141 """ Returns whether a reply from the kernel originated from a request
141 """Return whether a message is from this session"""
142 from this frontend.
142 session_id = self._kernel_client.session.session
143 """
143 return msg['parent_header'].get("session", session_id) == session_id
144 session = self._kernel_client.session.session
144
145 parent = msg['parent_header']
145 def include_output(self, msg):
146 if not parent:
146 """Return whether we should include a given output message"""
147 # if the message has no parent, assume it is meant for all frontends
147 if self._hidden:
148 return False
149 from_here = self.from_here(msg)
150 if msg['msg_type'] == 'execute_input':
151 # only echo inputs not from here
152 return self.include_other_output and not from_here
153
154 if self.include_other_output:
148 return True
155 return True
149 else:
156 else:
150 return parent.get('session') == session
157 return from_here
158
@@ -519,7 +519,15 b" class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, QtGui."
519 #---------------------------------------------------------------------------
519 #---------------------------------------------------------------------------
520 # 'ConsoleWidget' public interface
520 # 'ConsoleWidget' public interface
521 #---------------------------------------------------------------------------
521 #---------------------------------------------------------------------------
522
522
523 include_other_output = Bool(False, config=True,
524 help="""Whether to include output from clients
525 other than this one sharing the same kernel.
526
527 Outputs are not displayed until enter is pressed.
528 """
529 )
530
523 def can_copy(self):
531 def can_copy(self):
524 """ Returns whether text can be copied to the clipboard.
532 """ Returns whether text can be copied to the clipboard.
525 """
533 """
@@ -348,7 +348,7 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
348 #---------------------------------------------------------------------------
348 #---------------------------------------------------------------------------
349 def _handle_clear_output(self, msg):
349 def _handle_clear_output(self, msg):
350 """Handle clear output messages."""
350 """Handle clear output messages."""
351 if not self._hidden and self._is_from_this_session(msg):
351 if include_output(msg):
352 wait = msg['content'].get('wait', True)
352 wait = msg['content'].get('wait', True)
353 if wait:
353 if wait:
354 self._pending_clearoutput = True
354 self._pending_clearoutput = True
@@ -509,7 +509,7 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
509 """ Handle display hook output.
509 """ Handle display hook output.
510 """
510 """
511 self.log.debug("execute_result: %s", msg.get('content', ''))
511 self.log.debug("execute_result: %s", msg.get('content', ''))
512 if not self._hidden and self._is_from_this_session(msg):
512 if self.include_output(msg):
513 self.flush_clearoutput()
513 self.flush_clearoutput()
514 text = msg['content']['data']
514 text = msg['content']['data']
515 self._append_plain_text(text + '\n', before_prompt=True)
515 self._append_plain_text(text + '\n', before_prompt=True)
@@ -518,7 +518,7 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
518 """ Handle stdout, stderr, and stdin.
518 """ Handle stdout, stderr, and stdin.
519 """
519 """
520 self.log.debug("stream: %s", msg.get('content', ''))
520 self.log.debug("stream: %s", msg.get('content', ''))
521 if not self._hidden and self._is_from_this_session(msg):
521 if self.include_output(msg):
522 self.flush_clearoutput()
522 self.flush_clearoutput()
523 self.append_stream(msg['content']['text'])
523 self.append_stream(msg['content']['text'])
524
524
@@ -527,7 +527,7 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
527 """
527 """
528 self.log.info("shutdown: %s", msg.get('content', ''))
528 self.log.info("shutdown: %s", msg.get('content', ''))
529 restart = msg.get('content', {}).get('restart', False)
529 restart = msg.get('content', {}).get('restart', False)
530 if not self._hidden and not self._is_from_this_session(msg):
530 if not self._hidden and not self.from_here(msg):
531 # got shutdown reply, request came from session other than ours
531 # got shutdown reply, request came from session other than ours
532 if restart:
532 if restart:
533 # someone restarted the kernel, handle it
533 # someone restarted the kernel, handle it
@@ -219,12 +219,30 b' class IPythonWidget(FrontendWidget):'
219 items.append(cell)
219 items.append(cell)
220 last_cell = cell
220 last_cell = cell
221 self._set_history(items)
221 self._set_history(items)
222
223 def _insert_other_input(self, cursor, content):
224 """Insert function for input from other frontends"""
225 cursor.beginEditBlock()
226 start = cursor.position()
227 n = content.get('execution_count', 0)
228 cursor.insertText('\n')
229 self._insert_html(cursor, self._make_in_prompt(n))
230 cursor.insertText(content['code'])
231 self._highlighter.rehighlightBlock(cursor.block())
232 cursor.endEditBlock()
233
234 def _handle_execute_input(self, msg):
235 """Handle an execute_input message"""
236 self.log.debug("execute_input: %s", msg.get('content', ''))
237 if self.include_output(msg):
238 self._append_custom(self._insert_other_input, msg['content'], before_prompt=True)
222
239
240
223 def _handle_execute_result(self, msg):
241 def _handle_execute_result(self, msg):
224 """ Reimplemented for IPython-style "display hook".
242 """ Reimplemented for IPython-style "display hook".
225 """
243 """
226 self.log.debug("execute_result: %s", msg.get('content', ''))
244 self.log.debug("execute_result: %s", msg.get('content', ''))
227 if not self._hidden and self._is_from_this_session(msg):
245 if self.include_output(msg):
228 self.flush_clearoutput()
246 self.flush_clearoutput()
229 content = msg['content']
247 content = msg['content']
230 prompt_number = content.get('execution_count', 0)
248 prompt_number = content.get('execution_count', 0)
@@ -246,7 +264,7 b' class IPythonWidget(FrontendWidget):'
246 # For now, we don't display data from other frontends, but we
264 # For now, we don't display data from other frontends, but we
247 # eventually will as this allows all frontends to monitor the display
265 # eventually will as this allows all frontends to monitor the display
248 # data. But we need to figure out how to handle this in the GUI.
266 # data. But we need to figure out how to handle this in the GUI.
249 if not self._hidden and self._is_from_this_session(msg):
267 if self.include_output(msg):
250 self.flush_clearoutput()
268 self.flush_clearoutput()
251 data = msg['content']['data']
269 data = msg['content']['data']
252 metadata = msg['content']['metadata']
270 metadata = msg['content']['metadata']
@@ -107,7 +107,7 b' class RichIPythonWidget(IPythonWidget):'
107 def _handle_execute_result(self, msg):
107 def _handle_execute_result(self, msg):
108 """ Overridden to handle rich data types, like SVG.
108 """ Overridden to handle rich data types, like SVG.
109 """
109 """
110 if not self._hidden and self._is_from_this_session(msg):
110 if self.include_output(msg):
111 self.flush_clearoutput()
111 self.flush_clearoutput()
112 content = msg['content']
112 content = msg['content']
113 prompt_number = content.get('execution_count', 0)
113 prompt_number = content.get('execution_count', 0)
@@ -146,7 +146,7 b' class RichIPythonWidget(IPythonWidget):'
146 def _handle_display_data(self, msg):
146 def _handle_display_data(self, msg):
147 """ Overridden to handle rich data types, like SVG.
147 """ Overridden to handle rich data types, like SVG.
148 """
148 """
149 if not self._hidden and self._is_from_this_session(msg):
149 if self.include_output(msg):
150 self.flush_clearoutput()
150 self.flush_clearoutput()
151 data = msg['content']['data']
151 data = msg['content']['data']
152 metadata = msg['content']['metadata']
152 metadata = msg['content']['metadata']
@@ -26,7 +26,7 b' from IPython.core import release'
26 from IPython.utils.warn import warn, error
26 from IPython.utils.warn import warn, error
27 from IPython.utils import io
27 from IPython.utils import io
28 from IPython.utils.py3compat import string_types, input
28 from IPython.utils.py3compat import string_types, input
29 from IPython.utils.traitlets import List, Enum, Any, Instance, Unicode, Float
29 from IPython.utils.traitlets import List, Enum, Any, Instance, Unicode, Float, Bool
30 from IPython.utils.tempdir import NamedFileInTemporaryDirectory
30 from IPython.utils.tempdir import NamedFileInTemporaryDirectory
31
31
32 from IPython.terminal.interactiveshell import TerminalInteractiveShell
32 from IPython.terminal.interactiveshell import TerminalInteractiveShell
@@ -212,8 +212,37 b' class ZMQTerminalInteractiveShell(TerminalInteractiveShell):'
212 print(frame, file=io.stderr)
212 print(frame, file=io.stderr)
213
213
214 self.execution_count = int(content["execution_count"] + 1)
214 self.execution_count = int(content["execution_count"] + 1)
215
215
216
216 include_other_output = Bool(False, config=True,
217 help="""Whether to include output from clients
218 other than this one sharing the same kernel.
219
220 Outputs are not displayed until enter is pressed.
221 """
222 )
223 other_output_prefix = Unicode("[remote] ", config=True,
224 help="""Prefix to add to outputs coming from clients other than this one.
225
226 Only relevant if include_other_output is True.
227 """
228 )
229
230 def from_here(self, msg):
231 """Return whether a message is from this session"""
232 return msg['parent_header'].get("session", self.session_id) == self.session_id
233
234 def include_output(self, msg):
235 """Return whether we should include a given output message"""
236 from_here = self.from_here(msg)
237 if msg['msg_type'] == 'execute_input':
238 # only echo inputs not from here
239 return self.include_other_output and not from_here
240
241 if self.include_other_output:
242 return True
243 else:
244 return from_here
245
217 def handle_iopub(self, msg_id=''):
246 def handle_iopub(self, msg_id=''):
218 """Process messages on the IOPub channel
247 """Process messages on the IOPub channel
219
248
@@ -227,7 +256,7 b' class ZMQTerminalInteractiveShell(TerminalInteractiveShell):'
227 msg_type = sub_msg['header']['msg_type']
256 msg_type = sub_msg['header']['msg_type']
228 parent = sub_msg["parent_header"]
257 parent = sub_msg["parent_header"]
229
258
230 if parent.get("session", self.session_id) == self.session_id:
259 if self.include_output(sub_msg):
231 if msg_type == 'status':
260 if msg_type == 'status':
232 self._execution_state = sub_msg["content"]["execution_state"]
261 self._execution_state = sub_msg["content"]["execution_state"]
233 elif msg_type == 'stream':
262 elif msg_type == 'stream':
@@ -249,8 +278,11 b' class ZMQTerminalInteractiveShell(TerminalInteractiveShell):'
249 print("\r", file=io.stdout, end="")
278 print("\r", file=io.stdout, end="")
250 self._pending_clearoutput = False
279 self._pending_clearoutput = False
251 self.execution_count = int(sub_msg["content"]["execution_count"])
280 self.execution_count = int(sub_msg["content"]["execution_count"])
281 if not self.from_here(sub_msg):
282 sys.stdout.write(self.other_output_prefix)
252 format_dict = sub_msg["content"]["data"]
283 format_dict = sub_msg["content"]["data"]
253 self.handle_rich_data(format_dict)
284 self.handle_rich_data(format_dict)
285
254 # taken from DisplayHook.__call__:
286 # taken from DisplayHook.__call__:
255 hook = self.displayhook
287 hook = self.displayhook
256 hook.start_displayhook()
288 hook.start_displayhook()
@@ -263,10 +295,20 b' class ZMQTerminalInteractiveShell(TerminalInteractiveShell):'
263 data = sub_msg["content"]["data"]
295 data = sub_msg["content"]["data"]
264 handled = self.handle_rich_data(data)
296 handled = self.handle_rich_data(data)
265 if not handled:
297 if not handled:
298 if not self.from_here(sub_msg):
299 sys.stdout.write(self.other_output_prefix)
266 # if it was an image, we handled it by now
300 # if it was an image, we handled it by now
267 if 'text/plain' in data:
301 if 'text/plain' in data:
268 print(data['text/plain'])
302 print(data['text/plain'])
269
303
304 elif msg_type == 'execute_input':
305 content = sub_msg['content']
306 self.execution_count = content['execution_count']
307 if not self.from_here(sub_msg):
308 sys.stdout.write(self.other_output_prefix)
309 sys.stdout.write(self.prompt_manager.render('in'))
310 sys.stdout.write(content['code'])
311
270 elif msg_type == 'clear_output':
312 elif msg_type == 'clear_output':
271 if sub_msg["content"]["wait"]:
313 if sub_msg["content"]["wait"]:
272 self._pending_clearoutput = True
314 self._pending_clearoutput = True
General Comments 0
You need to be logged in to leave comments. Login now