@@ -194,7 +194,125 @@ export class WidgetManager extends JupyterLabManager {
194
194
} ) ;
195
195
}
196
196
197
+ /**
198
+ * This is the implementation of building widgets models making use of the
199
+ * jupyter.widget.control comm channel
200
+ */
197
201
async _build_models ( ) : Promise < { [ key : string ] : base . WidgetModel } > {
202
+ const models : { [ key : string ] : base . WidgetModel } = { } ;
203
+ const commId = base . uuid ( ) ;
204
+ const initComm = await this . _create_comm (
205
+ 'jupyter.widget.control' ,
206
+ commId ,
207
+ { widgets : null } ,
208
+ { version : '1.0.0' }
209
+ ) ;
210
+
211
+ // Fetch widget states
212
+ let data : any ;
213
+ let buffers : any ;
214
+ try {
215
+ await new Promise ( ( resolve , reject ) => {
216
+ initComm . on_msg ( msg => {
217
+ data = msg [ 'content' ] [ 'data' ] ;
218
+
219
+ if ( data . method !== 'update_states' ) {
220
+ console . warn ( `
221
+ Unknown ${ data . method } message on the Control channel
222
+ ` ) ;
223
+ return ;
224
+ }
225
+
226
+ buffers = ( msg . buffers || [ ] ) . map ( ( b : any ) => {
227
+ if ( b instanceof DataView ) {
228
+ return b ;
229
+ } else {
230
+ return new DataView ( b instanceof ArrayBuffer ? b : b . buffer ) ;
231
+ }
232
+ } ) ;
233
+
234
+ resolve ( null ) ;
235
+ } ) ;
236
+
237
+ initComm . on_close ( reject ) ;
238
+
239
+ // Send a states request msg
240
+ initComm . send ( { method : 'request_states' } , { } ) ;
241
+ } ) ;
242
+ } catch {
243
+ console . warn (
244
+ 'Failed to open "jupyter.widget.control" comm channel, fallback to slow fetching of widgets.'
245
+ ) ;
246
+ // Fallback to the old implementation for old ipywidgets versions (<=7.6)
247
+ return this . _build_models_slow ( ) ;
248
+ }
249
+
250
+ initComm . close ( ) ;
251
+
252
+ const states : any = data . states ;
253
+
254
+ // Extract buffer paths
255
+ // Why do we have to do this? Is there another way?
256
+ const bufferPaths : any = { } ;
257
+ for ( const bufferPath of data . buffer_paths ) {
258
+ if ( ! bufferPaths [ bufferPath [ 0 ] ] ) {
259
+ bufferPaths [ bufferPath [ 0 ] ] = [ ] ;
260
+ }
261
+ bufferPaths [ bufferPath [ 0 ] ] . push ( bufferPath . slice ( 1 ) ) ;
262
+ }
263
+
264
+ const widgetPromises : Promise < base . WidgetModel > [ ] = [ ] ;
265
+
266
+ // Start creating all widgets
267
+ for ( const widget_id in states ) {
268
+ const state = states [ widget_id ] ;
269
+
270
+ try {
271
+ const comm = await this . _create_comm ( 'jupyter.widget' , widget_id ) ;
272
+
273
+ // Put binary buffers
274
+ if ( widget_id in bufferPaths ) {
275
+ const nBuffers = bufferPaths [ widget_id ] . length ;
276
+ base . put_buffers (
277
+ state ,
278
+ bufferPaths [ widget_id ] ,
279
+ buffers . slice ( 0 , nBuffers )
280
+ ) ;
281
+ buffers = buffers . slice ( nBuffers ) ;
282
+ }
283
+
284
+ const modelPromise = this . new_model (
285
+ {
286
+ model_name : state . model_name ,
287
+ model_module : state . model_module ,
288
+ model_module_version : state . model_module_version ,
289
+ model_id : widget_id ,
290
+ comm : comm
291
+ } ,
292
+ state . state
293
+ ) ;
294
+ widgetPromises . push ( modelPromise ) ;
295
+ } catch ( error ) {
296
+ // Failed to create a widget model, we continue creating other models so that
297
+ // other widgets can render
298
+ console . error ( error ) ;
299
+ }
300
+ }
301
+
302
+ // Wait for widgets to be created
303
+ const widgets = await Promise . all ( widgetPromises ) ;
304
+ for ( const model of widgets ) {
305
+ models [ model . model_id ] = model ;
306
+ }
307
+
308
+ return models ;
309
+ }
310
+
311
+ /**
312
+ * This is the old implementation of building widgets models
313
+ * We keep it around for supporting old ipywidgets versions (<=7.6)
314
+ */
315
+ async _build_models_slow ( ) : Promise < { [ key : string ] : base . WidgetModel } > {
198
316
const comm_ids = await this . _get_comm_info ( ) ;
199
317
const models : { [ key : string ] : base . WidgetModel } = { } ;
200
318
/**
0 commit comments