9
9
from concurrent .futures import Future
10
10
from contextlib import contextmanager
11
11
from datetime import datetime
12
+ from functools import partial
12
13
from threading import Event
13
14
14
15
try :
@@ -135,17 +136,18 @@ def _init_futures(self):
135
136
self ._output_future .add_done_callback (self ._resolve_output )
136
137
self .add_done_callback (self ._finalize_result )
137
138
138
- def iopub_streaming_output_callback (self , eid , msg ):
139
+ def _iopub_streaming_output_callback (self , eid , msg ):
140
+ """Callback registered during AsyncResult.stream_output()"""
139
141
msg_type = msg ['header' ]['msg_type' ]
140
142
if msg_type == 'stream' :
141
143
msg_content = msg ['content' ]
142
144
stream_name = msg_content ['name' ]
143
- if stream_name == ' stdout' :
144
- self ._display_stream (msg_content [ 'text' ], '[stdout:%i] ' % eid )
145
- elif stream_name == 'stderr' :
146
- self . _display_stream (
147
- msg_content [ 'text' ], '[stderr:%i] ' % eid , file = sys . stderr
148
- )
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
+ )
149
151
150
152
if get_ipython () is None :
151
153
return
@@ -157,25 +159,25 @@ def iopub_streaming_output_callback(self, eid, msg):
157
159
158
160
@contextmanager
159
161
def stream_output (self ):
160
- """
161
- Context manager that adds a iopub callback to stream stdout/stderr
162
- (instead of displaying it all at the end).
163
- """
162
+ """Stream output for this result as it arrives.
164
163
165
- from functools import partial
164
+ Returns a context manager, during which output is streamed.
165
+ """
166
166
167
167
# Keep a handle on the futures so we can remove the callback later
168
- msg_futures = []
168
+ future_callbacks = {}
169
169
for eid , msg_id in zip (self ._targets , self .msg_ids ):
170
- callback_func = partial (self .iopub_streaming_output_callback , eid )
171
- self ._client ._futures [msg_id ].iopub_callbacks .append (callback_func )
172
- msg_futures .append (self ._client ._futures [msg_id ])
173
-
174
- yield
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 )
175
174
176
- # Remove the callback
177
- for msg_future in msg_futures :
178
- msg_future .iopub_callbacks .pop ()
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 )
179
181
180
182
def __repr__ (self ):
181
183
if self ._ready :
0 commit comments