@@ -11,6 +11,9 @@ var embedWidgets = require("./embed_widgets");
11
11
12
12
var MIME_TYPE = 'application/vnd.jupyter.widget-view+json' ;
13
13
14
+ var CONTROL_COMM_TARGET = 'jupyter.widget.control' ;
15
+ var CONTROL_COMM_VERSION = '1.0.0' ;
16
+
14
17
15
18
function polyfill_new_comm_buffers ( manager , target_name , data , callbacks , metadata , comm_id , buffers ) {
16
19
/**
@@ -75,45 +78,9 @@ export class WidgetManager extends base.ManagerBase {
75
78
76
79
// Attempt to reconstruct any live comms by requesting them from the back-end (2).
77
80
var that = this ;
78
- this . _get_comm_info ( ) . then ( function ( comm_ids ) {
79
81
80
- // Create comm class instances from comm ids (2).
81
- var comm_promises = Object . keys ( comm_ids ) . map ( function ( comm_id ) {
82
- return that . _create_comm ( that . comm_target_name , comm_id ) ;
83
- } ) ;
84
-
85
- // Send a state request message out for each widget comm and wait
86
- // for the responses (2).
87
- return Promise . all ( comm_promises ) . then ( function ( comms ) {
88
- return Promise . all ( comms . map ( function ( comm ) {
89
- var update_promise = new Promise ( function ( resolve , reject ) {
90
- comm . on_msg ( function ( msg ) {
91
- base . put_buffers ( msg . content . data . state , msg . content . data . buffer_paths , msg . buffers ) ;
92
- // A suspected response was received, check to see if
93
- // it's a state update. If so, resolve.
94
- if ( msg . content . data . method === 'update' ) {
95
- resolve ( {
96
- comm : comm ,
97
- msg : msg
98
- } ) ;
99
- }
100
- } ) ;
101
- } ) ;
102
- comm . send ( {
103
- method : 'request_state'
104
- } , that . callbacks ( ) ) ;
105
- return update_promise ;
106
- } ) ) ;
107
- } ) . then ( function ( widgets_info ) {
108
- return Promise . all ( widgets_info . map ( function ( widget_info ) {
109
- return that . new_model ( {
110
- model_name : widget_info . msg . content . data . state . _model_name ,
111
- model_module : widget_info . msg . content . data . state . _model_module ,
112
- model_module_version : widget_info . msg . content . data . state . _model_module_version ,
113
- comm : widget_info . comm ,
114
- } , widget_info . msg . content . data . state ) ;
115
- } ) ) ;
116
- } ) . then ( function ( ) {
82
+ this . _loadFromKernel ( )
83
+ . then ( function ( ) {
117
84
// Now that we have mirrored any widgets from the kernel...
118
85
// Restore any widgets from saved state that are not live (3)
119
86
if ( widget_md && widget_md [ 'application/vnd.jupyter.widget-state+json' ] ) {
@@ -132,7 +99,6 @@ export class WidgetManager extends base.ManagerBase {
132
99
}
133
100
} ) ;
134
101
} ) ;
135
- } ) ;
136
102
137
103
// Create the actions and menu
138
104
this . _init_actions ( ) ;
@@ -159,6 +125,162 @@ export class WidgetManager extends base.ManagerBase {
159
125
}
160
126
}
161
127
128
+ /**
129
+ * Fetch all widgets states using the control comm channel, or fallback to `_loadFromKernelSlow`
130
+ * if the backend does not implement the control comm.
131
+ */
132
+ _loadFromKernel ( ) {
133
+ var that = this ;
134
+
135
+ const commId = base . uuid ( ) ;
136
+ return this . _create_comm (
137
+ CONTROL_COMM_TARGET ,
138
+ commId ,
139
+ { widgets : null } ,
140
+ { version : CONTROL_COMM_VERSION }
141
+ ) . then ( function ( initComm ) {
142
+ // Try fetching all widget states through the control comm
143
+ let data ;
144
+ let buffers ;
145
+ try {
146
+ var controlCommPromise = new Promise ( function ( resolve , reject ) {
147
+ initComm . on_msg ( function ( msg ) {
148
+ data = msg [ 'content' ] [ 'data' ] ;
149
+
150
+ if ( data . method !== 'update_states' ) {
151
+ console . warn ( `
152
+ Unknown ${ data . method } message on the Control channel
153
+ ` ) ;
154
+ return ;
155
+ }
156
+
157
+ buffers = ( msg . buffers || [ ] ) . map ( function ( b ) {
158
+ if ( b instanceof DataView ) {
159
+ return b ;
160
+ } else {
161
+ return new DataView ( b instanceof ArrayBuffer ? b : b . buffer ) ;
162
+ }
163
+ } ) ;
164
+
165
+ resolve ( null ) ;
166
+ } ) ;
167
+
168
+ initComm . on_close ( reject ) ;
169
+
170
+ // Send a states request msg
171
+ initComm . send ( { method : 'request_states' } , { } ) ;
172
+ } ) ;
173
+
174
+ return controlCommPromise . then ( function ( ) {
175
+ initComm . close ( ) ;
176
+
177
+ const states = data . states ;
178
+
179
+ // Extract buffer paths
180
+ const bufferPaths = { } ;
181
+ for ( const bufferPath of data . buffer_paths ) {
182
+ if ( ! bufferPaths [ bufferPath [ 0 ] ] ) {
183
+ bufferPaths [ bufferPath [ 0 ] ] = [ ] ;
184
+ }
185
+ bufferPaths [ bufferPath [ 0 ] ] . push ( bufferPath . slice ( 1 ) ) ;
186
+ }
187
+
188
+ // Start creating all widgets
189
+ return Promise . all (
190
+ Object . keys ( states ) . map ( function ( widget_id ) {
191
+ const state = states [ widget_id ] ;
192
+
193
+ try {
194
+ return that . _create_comm ( 'jupyter.widget' , widget_id )
195
+ . then ( function ( comm ) {
196
+ // Put binary buffers
197
+ if ( widget_id in bufferPaths ) {
198
+ const nBuffers = bufferPaths [ widget_id ] . length ;
199
+ base . put_buffers (
200
+ state ,
201
+ bufferPaths [ widget_id ] ,
202
+ buffers . splice ( 0 , nBuffers )
203
+ ) ;
204
+ }
205
+
206
+ return that . new_model (
207
+ {
208
+ model_name : state . model_name ,
209
+ model_module : state . model_module ,
210
+ model_module_version : state . model_module_version ,
211
+ model_id : widget_id ,
212
+ comm : comm ,
213
+ } ,
214
+ state . state
215
+ ) ;
216
+ } ) ;
217
+ } catch ( error ) {
218
+ // Failed to create a widget model, we continue creating other models so that
219
+ // other widgets can render
220
+ console . error ( error ) ;
221
+ }
222
+ } )
223
+ ) ;
224
+ } ) ;
225
+ } catch ( error ) {
226
+ console . warn (
227
+ 'Failed to open "jupyter.widget.control" comm channel, fallback to slow fetching of widgets.' ,
228
+ error
229
+ ) ;
230
+ // Fallback to the old implementation for old ipywidgets backend versions (<=7.6)
231
+ return this . _loadFromKernelSlow ( ) ;
232
+ }
233
+ } ) ;
234
+ }
235
+
236
+ /**
237
+ * Old implementation of fetching widgets one by one using
238
+ * the request_state message on each comm.
239
+ */
240
+ _loadFromKernelSlow ( ) {
241
+ var that = this ;
242
+ return this . _get_comm_info ( ) . then ( function ( comm_ids ) {
243
+
244
+ // Create comm class instances from comm ids (2).
245
+ var comm_promises = Object . keys ( comm_ids ) . map ( function ( comm_id ) {
246
+ return that . _create_comm ( that . comm_target_name , comm_id ) ;
247
+ } ) ;
248
+
249
+ // Send a state request message out for each widget comm and wait
250
+ // for the responses (2).
251
+ return Promise . all ( comm_promises ) . then ( function ( comms ) {
252
+ return Promise . all ( comms . map ( function ( comm ) {
253
+ var update_promise = new Promise ( function ( resolve , reject ) {
254
+ comm . on_msg ( function ( msg ) {
255
+ base . put_buffers ( msg . content . data . state , msg . content . data . buffer_paths , msg . buffers ) ;
256
+ // A suspected response was received, check to see if
257
+ // it's a state update. If so, resolve.
258
+ if ( msg . content . data . method === 'update' ) {
259
+ resolve ( {
260
+ comm : comm ,
261
+ msg : msg
262
+ } ) ;
263
+ }
264
+ } ) ;
265
+ } ) ;
266
+ comm . send ( {
267
+ method : 'request_state'
268
+ } , that . callbacks ( ) ) ;
269
+ return update_promise ;
270
+ } ) ) ;
271
+ } ) . then ( function ( widgets_info ) {
272
+ return Promise . all ( widgets_info . map ( function ( widget_info ) {
273
+ return that . new_model ( {
274
+ model_name : widget_info . msg . content . data . state . _model_name ,
275
+ model_module : widget_info . msg . content . data . state . _model_module ,
276
+ model_module_version : widget_info . msg . content . data . state . _model_module_version ,
277
+ comm : widget_info . comm ,
278
+ } , widget_info . msg . content . data . state ) ;
279
+ } ) ) ;
280
+ } ) ;
281
+ } ) ;
282
+ }
283
+
162
284
/**
163
285
* Registers manager level actions with the notebook actions list
164
286
*/
@@ -336,7 +458,7 @@ export class WidgetManager extends base.ManagerBase {
336
458
}
337
459
338
460
/**
339
- * List of widget managers in *reverse* order
461
+ * List of widget managers in *reverse* order
340
462
* (_managers[0] is the most recent)
341
463
*/
342
- WidgetManager . _managers = [ ] ;
464
+ WidgetManager . _managers = [ ] ;
0 commit comments