@@ -385,7 +385,7 @@ abstract class ManagerBase<T> {
385
385
/**
386
386
* Fetch all widgets states from the kernel using the control comm channel
387
387
* If this fails (control comm handler not implemented kernel side),
388
- * it will fallback to `_loadFromKernelSlow `.
388
+ * it will fall back to `_loadFromKernelModels `.
389
389
*
390
390
* This is a utility function that can be used in subclasses.
391
391
*/
@@ -438,67 +438,102 @@ abstract class ManagerBase<T> {
438
438
initComm . close ( ) ;
439
439
} catch ( error ) {
440
440
console . warn (
441
- 'Failed to fetch widgets through the "jupyter.widget.control" comm channel, fallback to slow fetching of widgets . Reason:' ,
441
+ 'Failed to fetch ipywidgets through the "jupyter.widget.control" comm channel, fallback to fetching individual model state . Reason:' ,
442
442
error
443
443
) ;
444
- // Fallback to the old implementation for old ipywidgets backend versions (<=7.6)
445
- return this . _loadFromKernelSlow ( ) ;
444
+ // Fall back to the old implementation for old ipywidgets backend versions (ipywidgets <=7.6)
445
+ return this . _loadFromKernelModels ( ) ;
446
446
}
447
447
448
448
const states : any = data . states ;
449
-
450
- // Extract buffer paths
451
449
const bufferPaths : any = { } ;
452
- for ( const bufferPath of data . buffer_paths ) {
453
- if ( ! bufferPaths [ bufferPath [ 0 ] ] ) {
454
- bufferPaths [ bufferPath [ 0 ] ] = [ ] ;
450
+ const bufferGroups : any = { } ;
451
+
452
+ // Group buffers and buffer paths by widget id
453
+ for ( let i = 0 ; i < data . buffer_paths . length ; i ++ ) {
454
+ const [ widget_id , ...path ] = data . buffer_paths [ i ] ;
455
+ const b = buffers [ i ] ;
456
+ if ( ! bufferPaths [ widget_id ] ) {
457
+ bufferPaths [ widget_id ] = [ ] ;
458
+ bufferGroups [ widget_id ] = [ ] ;
455
459
}
456
- bufferPaths [ bufferPath [ 0 ] ] . push ( bufferPath . slice ( 1 ) ) ;
460
+ bufferPaths [ widget_id ] . push ( path ) ;
461
+ bufferGroups [ widget_id ] . push ( b ) ;
457
462
}
458
463
459
- // Start creating all widgets
460
- await Promise . all (
464
+ // Create comms for all new widgets.
465
+ let widget_comms = await Promise . all (
461
466
Object . keys ( states ) . map ( async ( widget_id ) => {
467
+ let comm = undefined ;
468
+ let modelPromise = undefined ;
462
469
try {
463
- const state = states [ widget_id ] ;
464
- const comm = await this . _create_comm ( 'jupyter.widget' , widget_id ) ;
465
-
466
- // Put binary buffers
467
- if ( widget_id in bufferPaths ) {
468
- const nBuffers = bufferPaths [ widget_id ] . length ;
469
- utils . put_buffers (
470
- state ,
471
- bufferPaths [ widget_id ] ,
472
- buffers . splice ( 0 , nBuffers )
473
- ) ;
470
+ modelPromise = this . get_model ( widget_id ) ;
471
+ if ( modelPromise === undefined ) {
472
+ comm = await this . _create_comm ( 'jupyter.widget' , widget_id ) ;
473
+ } else {
474
+ // For JLab, the promise is rejected, so we have to await to
475
+ // find out if it is actually a model.
476
+ await modelPromise ;
477
+ }
478
+ } catch ( e ) {
479
+ // The JLab widget manager will throw an error with this specific error message.
480
+ if ( e . message !== 'widget model not found' ) {
481
+ throw e ;
474
482
}
475
-
476
- await this . new_model (
477
- {
478
- model_name : state . model_name ,
479
- model_module : state . model_module ,
480
- model_module_version : state . model_module_version ,
481
- model_id : widget_id ,
482
- comm : comm ,
483
- } ,
484
- state . state
485
- ) ;
486
- } catch ( error ) {
487
- // Failed to create a widget model, we continue creating other models so that
488
- // other widgets can render
489
- console . error ( error ) ;
483
+ comm = await this . _create_comm ( 'jupyter.widget' , widget_id ) ;
490
484
}
485
+ return { widget_id, comm}
491
486
} )
492
- ) ;
487
+ )
488
+
489
+ await Promise . all ( widget_comms . map ( async ( { widget_id, comm} ) => {
490
+ const state = states [ widget_id ] ;
491
+ // Put binary buffers
492
+ if ( widget_id in bufferPaths ) {
493
+ utils . put_buffers (
494
+ state ,
495
+ bufferPaths [ widget_id ] ,
496
+ bufferGroups [ widget_id ]
497
+ ) ;
498
+ }
499
+ try {
500
+
501
+ if ( comm === undefined ) {
502
+ // model already exists here
503
+ const model = await this . get_model ( widget_id ) ;
504
+ model ! . set_state ( state . state ) ;
505
+ } else {
506
+ // This must be the first await in the code path that
507
+ // reaches here so that registering the model promise in
508
+ // new_model can register the widget promise before it may
509
+ // be required by other widgets.
510
+ await this . new_model (
511
+ {
512
+ model_name : state . model_name ,
513
+ model_module : state . model_module ,
514
+ model_module_version : state . model_module_version ,
515
+ model_id : widget_id ,
516
+ comm : comm ,
517
+ } ,
518
+ state . state
519
+ ) ;
520
+ }
521
+
522
+ } catch ( error ) {
523
+ // Failed to create a widget model, we continue creating other models so that
524
+ // other widgets can render
525
+ console . error ( error ) ;
526
+ }
527
+ } ) ) ;
493
528
}
494
529
495
530
/**
496
- * Old implementation of fetching widgets one by one using
531
+ * Old implementation of fetching widget models one by one using
497
532
* the request_state message on each comm.
498
533
*
499
534
* This is a utility function that can be used in subclasses.
500
535
*/
501
- protected async _loadFromKernelSlow ( ) : Promise < void > {
536
+ protected async _loadFromKernelModels ( ) : Promise < void > {
502
537
const comm_ids = await this . _get_comm_info ( ) ;
503
538
504
539
// For each comm id that we do not know about, create the comm, and request the state.
0 commit comments