##// 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 136 handler = getattr(self, '_handle_' + msg_type, None)
137 137 if handler:
138 138 handler(msg)
139
140 def _is_from_this_session(self, msg):
141 """ Returns whether a reply from the kernel originated from a request
142 from this frontend.
143 """
144 session = self._kernel_client.session.session
145 parent = msg['parent_header']
146 if not parent:
147 # if the message has no parent, assume it is meant for all frontends
139
140 def from_here(self, msg):
141 """Return whether a message is from this session"""
142 session_id = self._kernel_client.session.session
143 return msg['parent_header'].get("session", session_id) == session_id
144
145 def include_output(self, msg):
146 """Return whether we should include a given output message"""
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 155 return True
149 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 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 531 def can_copy(self):
524 532 """ Returns whether text can be copied to the clipboard.
525 533 """
@@ -348,7 +348,7 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
348 348 #---------------------------------------------------------------------------
349 349 def _handle_clear_output(self, msg):
350 350 """Handle clear output messages."""
351 if not self._hidden and self._is_from_this_session(msg):
351 if include_output(msg):
352 352 wait = msg['content'].get('wait', True)
353 353 if wait:
354 354 self._pending_clearoutput = True
@@ -509,7 +509,7 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
509 509 """ Handle display hook output.
510 510 """
511 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 513 self.flush_clearoutput()
514 514 text = msg['content']['data']
515 515 self._append_plain_text(text + '\n', before_prompt=True)
@@ -518,7 +518,7 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
518 518 """ Handle stdout, stderr, and stdin.
519 519 """
520 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 522 self.flush_clearoutput()
523 523 self.append_stream(msg['content']['text'])
524 524
@@ -527,7 +527,7 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
527 527 """
528 528 self.log.info("shutdown: %s", msg.get('content', ''))
529 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 531 # got shutdown reply, request came from session other than ours
532 532 if restart:
533 533 # someone restarted the kernel, handle it
@@ -219,12 +219,30 b' class IPythonWidget(FrontendWidget):'
219 219 items.append(cell)
220 220 last_cell = cell
221 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 241 def _handle_execute_result(self, msg):
224 242 """ Reimplemented for IPython-style "display hook".
225 243 """
226 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 246 self.flush_clearoutput()
229 247 content = msg['content']
230 248 prompt_number = content.get('execution_count', 0)
@@ -246,7 +264,7 b' class IPythonWidget(FrontendWidget):'
246 264 # For now, we don't display data from other frontends, but we
247 265 # eventually will as this allows all frontends to monitor the display
248 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 268 self.flush_clearoutput()
251 269 data = msg['content']['data']
252 270 metadata = msg['content']['metadata']
@@ -107,7 +107,7 b' class RichIPythonWidget(IPythonWidget):'
107 107 def _handle_execute_result(self, msg):
108 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 111 self.flush_clearoutput()
112 112 content = msg['content']
113 113 prompt_number = content.get('execution_count', 0)
@@ -146,7 +146,7 b' class RichIPythonWidget(IPythonWidget):'
146 146 def _handle_display_data(self, msg):
147 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 150 self.flush_clearoutput()
151 151 data = msg['content']['data']
152 152 metadata = msg['content']['metadata']
@@ -26,7 +26,7 b' from IPython.core import release'
26 26 from IPython.utils.warn import warn, error
27 27 from IPython.utils import io
28 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 30 from IPython.utils.tempdir import NamedFileInTemporaryDirectory
31 31
32 32 from IPython.terminal.interactiveshell import TerminalInteractiveShell
@@ -212,8 +212,37 b' class ZMQTerminalInteractiveShell(TerminalInteractiveShell):'
212 212 print(frame, file=io.stderr)
213 213
214 214 self.execution_count = int(content["execution_count"] + 1)
215
216
215
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 246 def handle_iopub(self, msg_id=''):
218 247 """Process messages on the IOPub channel
219 248
@@ -227,7 +256,7 b' class ZMQTerminalInteractiveShell(TerminalInteractiveShell):'
227 256 msg_type = sub_msg['header']['msg_type']
228 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 260 if msg_type == 'status':
232 261 self._execution_state = sub_msg["content"]["execution_state"]
233 262 elif msg_type == 'stream':
@@ -249,8 +278,11 b' class ZMQTerminalInteractiveShell(TerminalInteractiveShell):'
249 278 print("\r", file=io.stdout, end="")
250 279 self._pending_clearoutput = False
251 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 283 format_dict = sub_msg["content"]["data"]
253 284 self.handle_rich_data(format_dict)
285
254 286 # taken from DisplayHook.__call__:
255 287 hook = self.displayhook
256 288 hook.start_displayhook()
@@ -263,10 +295,20 b' class ZMQTerminalInteractiveShell(TerminalInteractiveShell):'
263 295 data = sub_msg["content"]["data"]
264 296 handled = self.handle_rich_data(data)
265 297 if not handled:
298 if not self.from_here(sub_msg):
299 sys.stdout.write(self.other_output_prefix)
266 300 # if it was an image, we handled it by now
267 301 if 'text/plain' in data:
268 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 312 elif msg_type == 'clear_output':
271 313 if sub_msg["content"]["wait"]:
272 314 self._pending_clearoutput = True
General Comments 0
You need to be logged in to leave comments. Login now