7
7
import threading
8
8
import time
9
9
from concurrent .futures import Future
10
+ from contextlib import contextmanager
10
11
from datetime import datetime
12
+ from functools import partial
11
13
from threading import Event
12
14
13
15
try :
@@ -134,6 +136,49 @@ def _init_futures(self):
134
136
self ._output_future .add_done_callback (self ._resolve_output )
135
137
self .add_done_callback (self ._finalize_result )
136
138
139
+ def _iopub_streaming_output_callback (self , eid , msg ):
140
+ """Callback registered during AsyncResult.stream_output()"""
141
+ msg_type = msg ['header' ]['msg_type' ]
142
+ if msg_type == 'stream' :
143
+ msg_content = msg ['content' ]
144
+ stream_name = msg_content ['name' ]
145
+ stream = getattr (sys , stream_name , sys .stdout )
146
+ self ._display_stream (
147
+ msg_content ['text' ],
148
+ f'[{ stream_name } :{ eid } ] ' ,
149
+ file = stream ,
150
+ )
151
+
152
+ if get_ipython () is None :
153
+ return
154
+
155
+ if msg_type == 'display_data' :
156
+ msg_content = msg ['content' ]
157
+ _raw_text ('[output:%i]' % eid )
158
+ self ._republish_displaypub (msg_content , eid )
159
+
160
+ @contextmanager
161
+ def stream_output (self ):
162
+ """Stream output for this result as it arrives.
163
+
164
+ Returns a context manager, during which output is streamed.
165
+ """
166
+
167
+ # Keep a handle on the futures so we can remove the callback later
168
+ future_callbacks = {}
169
+ for eid , msg_id in zip (self ._targets , self .msg_ids ):
170
+ callback_func = partial (self ._iopub_streaming_output_callback , eid )
171
+ f = self ._client ._futures [msg_id ]
172
+ future_callbacks [f ] = callback_func
173
+ f .iopub_callbacks .append (callback_func )
174
+
175
+ try :
176
+ yield
177
+ finally :
178
+ # Remove the callback
179
+ for msg_future , callback in future_callbacks .items ():
180
+ msg_future .iopub_callbacks .remove (callback )
181
+
137
182
def __repr__ (self ):
138
183
if self ._ready :
139
184
return "<%s: %s:finished>" % (self .__class__ .__name__ , self ._fname )
@@ -558,21 +603,23 @@ def _display_stream(self, text, prefix='', file=None):
558
603
prefix = prefix + '\n '
559
604
print ("%s%s" % (prefix , text ), file = file , end = end )
560
605
561
- def _display_single_result (self ):
562
- self ._display_stream (self .stdout )
563
- self ._display_stream (self .stderr , file = sys .stderr )
606
+ def _display_single_result (self , result_only = False ):
607
+ if not result_only :
608
+ self ._display_stream (self .stdout )
609
+ self ._display_stream (self .stderr , file = sys .stderr )
564
610
if get_ipython () is None :
565
611
# displaypub is meaningless outside IPython
566
612
return
567
613
568
- for output in self .outputs :
569
- self ._republish_displaypub (output , self .engine_id )
614
+ if not result_only :
615
+ for output in self .outputs :
616
+ self ._republish_displaypub (output , self .engine_id )
570
617
571
618
if self .execute_result is not None :
572
619
display (self .get ())
573
620
574
621
@check_ready
575
- def display_outputs (self , groupby = "type" ):
622
+ def display_outputs (self , groupby = "type" , result_only = False ):
576
623
"""republish the outputs of the computation
577
624
578
625
Parameters
@@ -598,10 +645,15 @@ def display_outputs(self, groupby="type"):
598
645
outputs. This is meant for cases of each command producing
599
646
several plots, and you would like to see all of the first
600
647
plots together, then all of the second plots, and so on.
648
+
649
+ result_only: boolean [default: False]
650
+ Only display the execution result and skip stdout, stderr and
651
+ display-outputs. Usually used when using streaming output
652
+ since these outputs would have already been displayed.
601
653
"""
602
654
self .wait_for_output ()
603
655
if self ._single_result :
604
- self ._display_single_result ()
656
+ self ._display_single_result (result_only = result_only )
605
657
return
606
658
607
659
stdouts = self .stdout
@@ -616,53 +668,57 @@ def display_outputs(self, groupby="type"):
616
668
for eid , stdout , stderr , outputs , r , execute_result in zip (
617
669
targets , stdouts , stderrs , output_lists , results , execute_results
618
670
):
619
- self ._display_stream (stdout , '[stdout:%i] ' % eid )
620
- self ._display_stream (stderr , '[stderr:%i] ' % eid , file = sys .stderr )
671
+ if not result_only :
672
+ self ._display_stream (stdout , '[stdout:%i] ' % eid )
673
+ self ._display_stream (stderr , '[stderr:%i] ' % eid , file = sys .stderr )
621
674
622
675
if get_ipython () is None :
623
676
# displaypub is meaningless outside IPython
624
677
continue
625
678
626
- if outputs or execute_result is not None :
679
+ if ( outputs and not result_only ) or execute_result is not None :
627
680
_raw_text ('[output:%i]' % eid )
628
681
629
- for output in outputs :
630
- self ._republish_displaypub (output , eid )
682
+ if not result_only :
683
+ for output in outputs :
684
+ self ._republish_displaypub (output , eid )
631
685
632
686
if execute_result is not None :
633
687
display (r )
634
688
635
689
elif groupby in ('type' , 'order' ):
636
- # republish stdout:
637
- for eid , stdout in zip (targets , stdouts ):
638
- self ._display_stream (stdout , '[stdout:%i] ' % eid )
690
+ if not result_only :
691
+ # republish stdout:
692
+ for eid , stdout in zip (targets , stdouts ):
693
+ self ._display_stream (stdout , '[stdout:%i] ' % eid )
639
694
640
- # republish stderr:
641
- for eid , stderr in zip (targets , stderrs ):
642
- self ._display_stream (stderr , '[stderr:%i] ' % eid , file = sys .stderr )
695
+ # republish stderr:
696
+ for eid , stderr in zip (targets , stderrs ):
697
+ self ._display_stream (stderr , '[stderr:%i] ' % eid , file = sys .stderr )
643
698
644
699
if get_ipython () is None :
645
700
# displaypub is meaningless outside IPython
646
701
return
647
702
648
- if groupby == 'order' :
649
- output_dict = dict (
650
- (eid , outputs ) for eid , outputs in zip (targets , output_lists )
651
- )
652
- N = max (len (outputs ) for outputs in output_lists )
653
- for i in range (N ):
654
- for eid in targets :
655
- outputs = output_dict [eid ]
656
- if len (outputs ) >= N :
703
+ if not result_only :
704
+ if groupby == 'order' :
705
+ output_dict = dict (
706
+ (eid , outputs ) for eid , outputs in zip (targets , output_lists )
707
+ )
708
+ N = max (len (outputs ) for outputs in output_lists )
709
+ for i in range (N ):
710
+ for eid in targets :
711
+ outputs = output_dict [eid ]
712
+ if len (outputs ) >= N :
713
+ _raw_text ('[output:%i]' % eid )
714
+ self ._republish_displaypub (outputs [i ], eid )
715
+ else :
716
+ # republish displaypub output
717
+ for eid , outputs in zip (targets , output_lists ):
718
+ if outputs :
657
719
_raw_text ('[output:%i]' % eid )
658
- self ._republish_displaypub (outputs [i ], eid )
659
- else :
660
- # republish displaypub output
661
- for eid , outputs in zip (targets , output_lists ):
662
- if outputs :
663
- _raw_text ('[output:%i]' % eid )
664
- for output in outputs :
665
- self ._republish_displaypub (output , eid )
720
+ for output in outputs :
721
+ self ._republish_displaypub (output , eid )
666
722
667
723
# finally, add execute_result:
668
724
for eid , r , execute_result in zip (targets , results , execute_results ):
0 commit comments