@@ -194,7 +194,123 @@ 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 ( error ) {
243
+ console . warn (
244
+ 'Failed to open "jupyter.widget.control" comm channel, fallback to slow fetching of widgets.' ,
245
+ error
246
+ ) ;
247
+ // Fallback to the old implementation for old ipywidgets versions (<=7.6)
248
+ return this . _build_models_slow ( ) ;
249
+ }
250
+
251
+ initComm . close ( ) ;
252
+
253
+ const states : any = data . states ;
254
+
255
+ // Extract buffer paths
256
+ // Why do we have to do this? Is there another way?
257
+ const bufferPaths : any = { } ;
258
+ for ( const bufferPath of data . buffer_paths ) {
259
+ if ( ! bufferPaths [ bufferPath [ 0 ] ] ) {
260
+ bufferPaths [ bufferPath [ 0 ] ] = [ ] ;
261
+ }
262
+ bufferPaths [ bufferPath [ 0 ] ] . push ( bufferPath . slice ( 1 ) ) ;
263
+ }
264
+
265
+ const widgetPromises : Promise < base . WidgetModel > [ ] = [ ] ;
266
+
267
+ // Start creating all widgets
268
+ for ( const [ widget_id , state ] of Object . entries ( states ) as any ) {
269
+ try {
270
+ const comm = await this . _create_comm ( 'jupyter.widget' , widget_id ) ;
271
+
272
+ // Put binary buffers
273
+ if ( widget_id in bufferPaths ) {
274
+ const nBuffers = bufferPaths [ widget_id ] . length ;
275
+ base . put_buffers (
276
+ state ,
277
+ bufferPaths [ widget_id ] ,
278
+ buffers . splice ( 0 , nBuffers )
279
+ ) ;
280
+ }
281
+
282
+ const modelPromise = this . new_model (
283
+ {
284
+ model_name : state . model_name ,
285
+ model_module : state . model_module ,
286
+ model_module_version : state . model_module_version ,
287
+ model_id : widget_id ,
288
+ comm : comm
289
+ } ,
290
+ state . state
291
+ ) ;
292
+ widgetPromises . push ( modelPromise ) ;
293
+ } catch ( error ) {
294
+ // Failed to create a widget model, we continue creating other models so that
295
+ // other widgets can render
296
+ console . error ( error ) ;
297
+ }
298
+ }
299
+
300
+ // Wait for widgets to be created
301
+ const widgets = await Promise . all ( widgetPromises ) ;
302
+ for ( const model of widgets ) {
303
+ models [ model . model_id ] = model ;
304
+ }
305
+
306
+ return models ;
307
+ }
308
+
309
+ /**
310
+ * This is the old implementation of building widgets models
311
+ * We keep it around for supporting old ipywidgets versions (<=7.6)
312
+ */
313
+ async _build_models_slow ( ) : Promise < { [ key : string ] : base . WidgetModel } > {
198
314
const comm_ids = await this . _get_comm_info ( ) ;
199
315
const models : { [ key : string ] : base . WidgetModel } = { } ;
200
316
/**
0 commit comments