@@ -40,8 +40,6 @@ import { Widget } from '@lumino/widgets';
40
40
41
41
import { requireLoader } from './loader' ;
42
42
43
- import { batchRateMap } from './utils' ;
44
-
45
43
if ( typeof window !== 'undefined' && typeof window . define !== 'undefined' ) {
46
44
window . define ( '@jupyter-widgets/base' , base ) ;
47
45
window . define ( '@jupyter-widgets/controls' , controls ) ;
@@ -98,7 +96,7 @@ export class WidgetManager extends JupyterLabManager {
98
96
}
99
97
100
98
async build_widgets ( ) : Promise < void > {
101
- const models = await this . _build_models ( ) ;
99
+ await this . _loadFromKernel ( ) ;
102
100
const tags = document . body . querySelectorAll (
103
101
'script[type="application/vnd.jupyter.widget-view+json"]'
104
102
) ;
@@ -110,7 +108,7 @@ export class WidgetManager extends JupyterLabManager {
110
108
try {
111
109
const widgetViewObject = JSON . parse ( viewtag . innerHTML ) ;
112
110
const { model_id } = widgetViewObject ;
113
- const model = models [ model_id ] ;
111
+ const model = await this . get_model ( model_id ) ;
114
112
const widgetel = document . createElement ( 'div' ) ;
115
113
viewtag . parentElement . insertBefore ( widgetel , viewtag ) ;
116
114
// TODO: fix typing
@@ -199,193 +197,5 @@ export class WidgetManager extends JupyterLabManager {
199
197
} ) ;
200
198
}
201
199
202
- /**
203
- * This is the implementation of building widgets models making use of the
204
- * jupyter.widget.control comm channel
205
- */
206
- async _build_models ( ) : Promise < { [ key : string ] : base . WidgetModel } > {
207
- const models : { [ key : string ] : base . WidgetModel } = { } ;
208
- const commId = base . uuid ( ) ;
209
- const initComm = await this . _create_comm (
210
- 'jupyter.widget.control' ,
211
- commId ,
212
- { widgets : null } ,
213
- { version : '1.0.0' }
214
- ) ;
215
-
216
- // Fetch widget states
217
- let data : any ;
218
- let buffers : any ;
219
- try {
220
- await new Promise ( ( resolve , reject ) => {
221
- initComm . on_msg ( msg => {
222
- data = msg [ 'content' ] [ 'data' ] ;
223
-
224
- if ( data . method !== 'update_states' ) {
225
- console . warn ( `
226
- Unknown ${ data . method } message on the Control channel
227
- ` ) ;
228
- return ;
229
- }
230
-
231
- buffers = ( msg . buffers || [ ] ) . map ( ( b : any ) => {
232
- if ( b instanceof DataView ) {
233
- return b ;
234
- } else {
235
- return new DataView ( b instanceof ArrayBuffer ? b : b . buffer ) ;
236
- }
237
- } ) ;
238
-
239
- resolve ( null ) ;
240
- } ) ;
241
-
242
- initComm . on_close ( reject ) ;
243
-
244
- // Send a states request msg
245
- initComm . send ( { method : 'request_states' } , { } ) ;
246
-
247
- // Reject if we didn't get a response in time
248
- setTimeout (
249
- ( ) => reject ( 'Control comm did not respond in time' ) ,
250
- CONTROL_COMM_TIMEOUT
251
- ) ;
252
- } ) ;
253
- } catch ( error ) {
254
- console . warn (
255
- 'Failed to open "jupyter.widget.control" comm channel, fallback to slow fetching of widgets.' ,
256
- error
257
- ) ;
258
- // Fallback to the old implementation for old ipywidgets versions (<=7.6)
259
- return this . _build_models_slow ( ) ;
260
- }
261
-
262
- initComm . close ( ) ;
263
-
264
- const states : any = data . states ;
265
-
266
- // Extract buffer paths
267
- // Why do we have to do this? Is there another way?
268
- const bufferPaths : any = { } ;
269
- for ( const bufferPath of data . buffer_paths ) {
270
- if ( ! bufferPaths [ bufferPath [ 0 ] ] ) {
271
- bufferPaths [ bufferPath [ 0 ] ] = [ ] ;
272
- }
273
- bufferPaths [ bufferPath [ 0 ] ] . push ( bufferPath . slice ( 1 ) ) ;
274
- }
275
-
276
- const widgetPromises : Promise < base . WidgetModel > [ ] = [ ] ;
277
-
278
- // Start creating all widgets
279
- for ( const [ widget_id , state ] of Object . entries ( states ) as any ) {
280
- try {
281
- const comm = await this . _create_comm ( 'jupyter.widget' , widget_id ) ;
282
-
283
- // Put binary buffers
284
- if ( widget_id in bufferPaths ) {
285
- const nBuffers = bufferPaths [ widget_id ] . length ;
286
- base . put_buffers (
287
- state ,
288
- bufferPaths [ widget_id ] ,
289
- buffers . splice ( 0 , nBuffers )
290
- ) ;
291
- }
292
-
293
- const modelPromise = this . new_model (
294
- {
295
- model_name : state . model_name ,
296
- model_module : state . model_module ,
297
- model_module_version : state . model_module_version ,
298
- model_id : widget_id ,
299
- comm : comm
300
- } ,
301
- state . state
302
- ) ;
303
- widgetPromises . push ( modelPromise ) ;
304
- } catch ( error ) {
305
- // Failed to create a widget model, we continue creating other models so that
306
- // other widgets can render
307
- console . error ( error ) ;
308
- }
309
- }
310
-
311
- // Wait for widgets to be created
312
- const widgets = await Promise . all ( widgetPromises ) ;
313
- for ( const model of widgets ) {
314
- models [ model . model_id ] = model ;
315
- }
316
-
317
- return models ;
318
- }
319
-
320
- /**
321
- * This is the old implementation of building widgets models
322
- * We keep it around for supporting old ipywidgets versions (<=7.6)
323
- */
324
- async _build_models_slow ( ) : Promise < { [ key : string ] : base . WidgetModel } > {
325
- const comm_ids = await this . _get_comm_info ( ) ;
326
- const models : { [ key : string ] : base . WidgetModel } = { } ;
327
- /**
328
- * For the classical notebook, iopub_msg_rate_limit=1000 (default)
329
- * And for zmq, we are affected by the default ZMQ_SNDHWM setting of 1000
330
- * See https://github.com/voila-dashboards/voila/issues/534 for a discussion
331
- */
332
- const maxMessagesInTransit = 100 ; // really save limit compared to ZMQ_SNDHWM
333
- const maxMessagesPerSecond = 500 ; // lets be on the save side, in case the kernel sends more msg'es
334
- const widgets_info = await Promise . all (
335
- batchRateMap (
336
- Object . keys ( comm_ids ) ,
337
- async comm_id => {
338
- const comm = await this . _create_comm ( this . comm_target_name , comm_id ) ;
339
- return this . _update_comm ( comm ) ;
340
- } ,
341
- { room : maxMessagesInTransit , rate : maxMessagesPerSecond }
342
- )
343
- ) ;
344
-
345
- await Promise . all (
346
- widgets_info . map ( async widget_info => {
347
- const state = ( widget_info as any ) . msg . content . data . state ;
348
- try {
349
- const modelPromise = this . new_model (
350
- {
351
- model_name : state . _model_name ,
352
- model_module : state . _model_module ,
353
- model_module_version : state . _model_module_version ,
354
- comm : ( widget_info as any ) . comm
355
- } ,
356
- state
357
- ) ;
358
- const model = await modelPromise ;
359
- models [ model . model_id ] = model ;
360
- } catch ( error ) {
361
- // Failed to create a widget model, we continue creating other models so that
362
- // other widgets can render
363
- console . error ( error ) ;
364
- }
365
- } )
366
- ) ;
367
- return models ;
368
- }
369
-
370
- async _update_comm (
371
- comm : base . IClassicComm
372
- ) : Promise < { comm : base . IClassicComm ; msg : any } > {
373
- return new Promise ( ( resolve , reject ) => {
374
- comm . on_msg ( async msg => {
375
- if ( msg . content . data . buffer_paths ) {
376
- base . put_buffers (
377
- msg . content . data . state ,
378
- msg . content . data . buffer_paths ,
379
- msg . buffers
380
- ) ;
381
- }
382
- if ( msg . content . data . method === 'update' ) {
383
- resolve ( { comm : comm , msg : msg } ) ;
384
- }
385
- } ) ;
386
- comm . send ( { method : 'request_state' } , { } ) ;
387
- } ) ;
388
- }
389
-
390
200
private _loader : ( name : any , version : any ) => Promise < any > ;
391
201
}
0 commit comments