2626from IPython .utils .warn import warn , error
2727from IPython .utils import io
2828from 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
3030from IPython .utils .tempdir import NamedFileInTemporaryDirectory
3131
3232from 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