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 |
|
|
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. |
|
|
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