Skip to content

Commit fb8adbe

Browse files
author
Alan Fleming
committed
Create new comm for existing models when restoring from kernel.
1 parent 86b5b0e commit fb8adbe

File tree

5 files changed

+42
-43
lines changed

5 files changed

+42
-43
lines changed

packages/base-manager/src/manager-base.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,9 @@ export abstract class ManagerBase implements IWidgetManager {
499499
model.constructor as typeof WidgetModel
500500
)._deserialize_state(state.state, this);
501501
model!.set_state(deserializedState);
502+
if (!model.comm_live) {
503+
model.comm = await this._create_comm('jupyter.widget', widget_id);
504+
}
502505
}
503506
} catch (error) {
504507
// Failed to create a widget model, we continue creating other models so that
@@ -750,12 +753,12 @@ export abstract class ManagerBase implements IWidgetManager {
750753

751754
/**
752755
* Disconnect the widget manager from the kernel, setting each model's comm
753-
* as dead.
756+
* as undefined.
754757
*/
755758
disconnect(): void {
756759
Object.keys(this._models).forEach((i) => {
757760
this._models[i].then((model) => {
758-
model.comm_live = false;
761+
model.comm = undefined;
759762
});
760763
});
761764
}

packages/base/src/errorwidget.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ export function createErrorWidgetModel(
2424
error: error,
2525
};
2626
super(attributes, options);
27-
this.comm_live = true;
27+
}
28+
get comm_live(): boolean {
29+
return true;
2830
}
2931
}
3032
return ErrorWidget;

packages/base/src/widget.ts

+25-31
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ export class WidgetModel extends Backbone.Model {
160160
// Attributes should be initialized here, since user initialization may depend on it
161161
this.widget_manager = options.widget_manager;
162162
this.model_id = options.model_id;
163-
const comm = options.comm;
163+
this.comm = options.comm;
164164

165165
this.views = Object.create(null);
166166
this.state_change = Promise.resolve();
@@ -174,27 +174,23 @@ export class WidgetModel extends Backbone.Model {
174174
// _buffered_state_diff must be created *after* the super.initialize
175175
// call above. See the note in the set() method below.
176176
this._buffered_state_diff = {};
177+
}
177178

178-
if (comm) {
179-
// Remember comm associated with the model.
180-
this.comm = comm;
179+
get comm() {
180+
return this._comm;
181+
}
181182

182-
// Hook comm messages up to model.
183+
set comm(comm: IClassicComm | undefined) {
184+
this._comm = comm;
185+
if (comm) {
183186
comm.on_close(this._handle_comm_closed.bind(this));
184187
comm.on_msg(this._handle_comm_msg.bind(this));
185-
186-
this.comm_live = true;
187-
} else {
188-
this.comm_live = false;
189188
}
189+
this.trigger('comm_live_update');
190190
}
191191

192-
get comm_live(): boolean {
193-
return this._comm_live;
194-
}
195-
set comm_live(x) {
196-
this._comm_live = x;
197-
this.trigger('comm_live_update');
192+
get comm_live() {
193+
return Boolean(this.comm);
198194
}
199195

200196
/**
@@ -218,42 +214,42 @@ export class WidgetModel extends Backbone.Model {
218214
*
219215
* @returns - a promise that is fulfilled when all the associated views have been removed.
220216
*/
221-
close(comm_closed = false): Promise<void> {
217+
async close(comm_closed = false): Promise<void> {
222218
// can only be closed once.
223219
if (this._closed) {
224-
return Promise.resolve();
220+
return;
225221
}
226222
this._closed = true;
227-
if (this.comm && !comm_closed && this.comm_live) {
223+
if (this._comm && !comm_closed) {
228224
try {
229-
this.comm.close();
225+
this._comm.close();
230226
} catch (err) {
231227
// Do Nothing
232228
}
233229
}
234230
this.stopListening();
235231
this.trigger('destroy', this);
236-
if (this.comm) {
237-
delete this.comm;
238-
}
232+
delete this._comm;
233+
239234
// Delete all views of this model
240235
if (this.views) {
241236
const views = Object.keys(this.views).map((id: string) => {
242237
return this.views![id].then((view) => view.remove());
243238
});
244239
delete this.views;
245-
return Promise.all(views).then(() => {
246-
return;
247-
});
240+
await Promise.all(views);
241+
return;
248242
}
249-
return Promise.resolve();
250243
}
251244

252245
/**
253246
* Handle when a widget comm is closed.
254247
*/
255248
_handle_comm_closed(msg: KernelMessage.ICommCloseMsg): void {
256-
this.comm_live = false;
249+
if (!this.comm) {
250+
return;
251+
}
252+
this.comm = undefined;
257253
this.trigger('comm:close');
258254
if (!this._closed) {
259255
this.close(true);
@@ -642,7 +638,7 @@ export class WidgetModel extends Backbone.Model {
642638
* This invokes a Backbone.Sync.
643639
*/
644640
save_changes(callbacks?: {}): void {
645-
if (this.comm_live) {
641+
if (this.comm) {
646642
const options: any = { patch: true };
647643
if (callbacks) {
648644
options.callbacks = callbacks;
@@ -728,11 +724,9 @@ export class WidgetModel extends Backbone.Model {
728724
model_id: string;
729725
views?: { [key: string]: Promise<WidgetView> };
730726
state_change: Promise<any>;
731-
comm?: IClassicComm;
732727
name: string;
733728
module: string;
734-
735-
private _comm_live: boolean;
729+
private _comm?: IClassicComm;
736730
private _closed: boolean;
737731
private _state_lock: any;
738732
private _buffered_state_diff: any;

packages/base/test/src/widget_test.ts

+7-7
Original file line numberDiff line numberDiff line change
@@ -194,15 +194,15 @@ describe('WidgetModel', function () {
194194
});
195195
});
196196

197-
it('sets the widget_manager, id, comm, and comm_live properties', function () {
198-
const widgetDead = new WidgetModel({}, {
199-
model_id: 'widgetDead',
197+
it('sets the widget_manager, id, comm, properties', function () {
198+
const widgetNoComm = new WidgetModel({}, {
199+
model_id: 'noComm',
200200
widget_manager: this.manager,
201201
} as IBackboneModelOptions);
202-
expect(widgetDead.model_id).to.equal('widgetDead');
203-
expect(widgetDead.widget_manager).to.equal(this.manager);
204-
expect(widgetDead.comm).to.be.undefined;
205-
expect(widgetDead.comm_live).to.be.false;
202+
expect(widgetNoComm.model_id).to.equal('noComm');
203+
expect(widgetNoComm.widget_manager).to.equal(this.manager);
204+
expect(widgetNoComm.comm).to.be.undefined;
205+
expect(widgetNoComm.comm_live).to.be.false;
206206

207207
const comm = new MockComm();
208208
const widgetLive = new WidgetModel({}, {

python/jupyterlab_widgets/src/manager.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ abstract class LabWidgetManager extends ManagerBase implements IDisposable {
302302
get_state_sync(options: IStateOptions = {}): ReadonlyPartialJSONValue {
303303
const models = [];
304304
for (const model of this._modelsSync.values()) {
305-
if (model.comm_live) {
305+
if (model.comm) {
306306
models.push(model);
307307
}
308308
}
@@ -488,6 +488,7 @@ export class KernelWidgetManager extends LabWidgetManager {
488488
case 'restarting':
489489
case 'dead':
490490
this.disconnect();
491+
this.clear_state();
491492
break;
492493
}
493494
}
@@ -510,7 +511,6 @@ export class KernelWidgetManager extends LabWidgetManager {
510511
this._restoredStatus = false;
511512
this._kernelRestoreInProgress = true;
512513
try {
513-
await this.clear_state();
514514
await this._loadFromKernel();
515515
} catch {
516516
/* empty */

0 commit comments

Comments
 (0)