Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5ef1976

Browse files
committed
Merge pull request #6123 from minrk/zmq-console-echo-other
Support echoing output from other clients
2 parents a11126e + 0d5f7a8 commit 5ef1976

6 files changed

Lines changed: 100 additions & 24 deletions

File tree

IPython/qt/base_frontend_mixin.py

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -136,15 +136,23 @@ def _dispatch(self, msg):
136136
handler = getattr(self, '_handle_' + msg_type, None)
137137
if handler:
138138
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:
148155
return True
149156
else:
150-
return parent.get('session') == session
157+
return from_here
158+

IPython/qt/console/console_widget.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -519,7 +519,15 @@ def sizeHint(self):
519519
#---------------------------------------------------------------------------
520520
# 'ConsoleWidget' public interface
521521
#---------------------------------------------------------------------------
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+
523531
def can_copy(self):
524532
""" Returns whether text can be copied to the clipboard.
525533
"""

IPython/qt/console/frontend_widget.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ def _insert_continuation_prompt(self, cursor):
348348
#---------------------------------------------------------------------------
349349
def _handle_clear_output(self, msg):
350350
"""Handle clear output messages."""
351-
if not self._hidden and self._is_from_this_session(msg):
351+
if include_output(msg):
352352
wait = msg['content'].get('wait', True)
353353
if wait:
354354
self._pending_clearoutput = True
@@ -509,7 +509,7 @@ def _handle_execute_result(self, msg):
509509
""" Handle display hook output.
510510
"""
511511
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):
513513
self.flush_clearoutput()
514514
text = msg['content']['data']
515515
self._append_plain_text(text + '\n', before_prompt=True)
@@ -518,7 +518,7 @@ def _handle_stream(self, msg):
518518
""" Handle stdout, stderr, and stdin.
519519
"""
520520
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):
522522
self.flush_clearoutput()
523523
self.append_stream(msg['content']['text'])
524524

@@ -527,7 +527,7 @@ def _handle_shutdown_reply(self, msg):
527527
"""
528528
self.log.info("shutdown: %s", msg.get('content', ''))
529529
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):
531531
# got shutdown reply, request came from session other than ours
532532
if restart:
533533
# someone restarted the kernel, handle it

IPython/qt/console/ipython_widget.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,12 +219,30 @@ def _handle_history_reply(self, msg):
219219
items.append(cell)
220220
last_cell = cell
221221
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)
222239

240+
223241
def _handle_execute_result(self, msg):
224242
""" Reimplemented for IPython-style "display hook".
225243
"""
226244
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):
228246
self.flush_clearoutput()
229247
content = msg['content']
230248
prompt_number = content.get('execution_count', 0)
@@ -246,7 +264,7 @@ def _handle_display_data(self, msg):
246264
# For now, we don't display data from other frontends, but we
247265
# eventually will as this allows all frontends to monitor the display
248266
# 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):
250268
self.flush_clearoutput()
251269
data = msg['content']['data']
252270
metadata = msg['content']['metadata']

IPython/qt/console/rich_ipython_widget.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ def _pre_image_append(self, msg, prompt_number):
107107
def _handle_execute_result(self, msg):
108108
""" Overridden to handle rich data types, like SVG.
109109
"""
110-
if not self._hidden and self._is_from_this_session(msg):
110+
if self.include_output(msg):
111111
self.flush_clearoutput()
112112
content = msg['content']
113113
prompt_number = content.get('execution_count', 0)
@@ -146,7 +146,7 @@ def _handle_execute_result(self, msg):
146146
def _handle_display_data(self, msg):
147147
""" Overridden to handle rich data types, like SVG.
148148
"""
149-
if not self._hidden and self._is_from_this_session(msg):
149+
if self.include_output(msg):
150150
self.flush_clearoutput()
151151
data = msg['content']['data']
152152
metadata = msg['content']['metadata']

IPython/terminal/console/interactiveshell.py

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
from IPython.utils.warn import warn, error
2727
from IPython.utils import io
2828
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
3030
from IPython.utils.tempdir import NamedFileInTemporaryDirectory
3131

3232
from IPython.terminal.interactiveshell import TerminalInteractiveShell
@@ -212,8 +212,37 @@ def handle_execute_reply(self, msg_id, timeout=None):
212212
print(frame, file=io.stderr)
213213

214214
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+
217246
def handle_iopub(self, msg_id=''):
218247
"""Process messages on the IOPub channel
219248
@@ -227,7 +256,7 @@ def handle_iopub(self, msg_id=''):
227256
msg_type = sub_msg['header']['msg_type']
228257
parent = sub_msg["parent_header"]
229258

230-
if parent.get("session", self.session_id) == self.session_id:
259+
if self.include_output(sub_msg):
231260
if msg_type == 'status':
232261
self._execution_state = sub_msg["content"]["execution_state"]
233262
elif msg_type == 'stream':
@@ -249,8 +278,11 @@ def handle_iopub(self, msg_id=''):
249278
print("\r", file=io.stdout, end="")
250279
self._pending_clearoutput = False
251280
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)
252283
format_dict = sub_msg["content"]["data"]
253284
self.handle_rich_data(format_dict)
285+
254286
# taken from DisplayHook.__call__:
255287
hook = self.displayhook
256288
hook.start_displayhook()
@@ -263,10 +295,20 @@ def handle_iopub(self, msg_id=''):
263295
data = sub_msg["content"]["data"]
264296
handled = self.handle_rich_data(data)
265297
if not handled:
298+
if not self.from_here(sub_msg):
299+
sys.stdout.write(self.other_output_prefix)
266300
# if it was an image, we handled it by now
267301
if 'text/plain' in data:
268302
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+
270312
elif msg_type == 'clear_output':
271313
if sub_msg["content"]["wait"]:
272314
self._pending_clearoutput = True

0 commit comments

Comments
 (0)