-
Notifications
You must be signed in to change notification settings - Fork 958
Widget persistence: only create comm for widgets having valid widget ids #62
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -293,6 +293,22 @@ define([ | |
}; | ||
|
||
WidgetManager.prototype.create_model = function (options) { | ||
/** | ||
* For backward compatibility. Custom widgets may be relying on the fact | ||
* that create_model was creating a comm if none was provided in options. | ||
* Unlike the old version of create_model, if no comm is passed, | ||
* options.model_id is used to create the new comm. | ||
*/ | ||
console.warn('WidgetManager.create_model is deprecated. Use WidgetManager.new_model'); | ||
if (!options.comm) { | ||
options.comm = this.comm_manager.new_comm('ipython.widget', | ||
{'widget_class': options.widget_class}, | ||
options.model_id); | ||
} | ||
return this.new_model(options); | ||
} | ||
|
||
WidgetManager.prototype.new_model = function (options) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why create a new method? Why not change There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. because |
||
/** | ||
* Create and return a promise for a new widget model | ||
* | ||
|
@@ -302,7 +318,7 @@ define([ | |
* Example | ||
* -------- | ||
* JS: | ||
* IPython.notebook.kernel.widget_manager.create_model({ | ||
* IPython.notebook.kernel.widget_manager.new_model({ | ||
* model_name: 'WidgetModel', | ||
* widget_class: 'ipywidgets.IntSlider' | ||
* }) | ||
|
@@ -320,19 +336,19 @@ define([ | |
* widget_class: (optional) string | ||
* Target name of the widget in the back-end. | ||
* comm: (optional) Comm | ||
* Comm object associated with the widget. | ||
* model_id: (optional) string | ||
* If not provided, the comm id is used. | ||
* | ||
* Create a comm if it wasn't provided. | ||
* Either a comm or a model_id must be provided. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure that it makes sense to require a comm or model id. Thinking symmetrically, you don't need to specify a comm or model id when instantiating a widget from the backend. If not in this method, it makes sense to have a method that can do this, for the case when the user just wants to make a new widget, and doesn't care about comms or model ids. I do not object to doing this in another PR. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or just renaming and keeping There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. create_model does not need a comm or a comm_id.
|
||
*/ | ||
var comm = options.comm; | ||
if (!comm) { | ||
comm = this.comm_manager.new_comm('ipython.widget', {'widget_class': options.widget_class}); | ||
} | ||
|
||
var that = this; | ||
var model_id = comm.comm_id; | ||
var model_promise = utils.load_class(options.model_name, options.model_module, WidgetManager._model_types) | ||
var model_id = options.model_id || options.comm.comm_id; | ||
var model_promise = utils.load_class(options.model_name, | ||
options.model_module, | ||
WidgetManager._model_types) | ||
.then(function(ModelType) { | ||
var widget_model = new ModelType(that, model_id, comm); | ||
var widget_model = new ModelType(that, model_id, options.comm); | ||
widget_model.once('comm:close', function () { | ||
delete that._models[model_id]; | ||
}); | ||
|
@@ -423,30 +439,34 @@ define([ | |
return this._get_connected_kernel().then(function(kernel) { | ||
|
||
// Recreate all the widget models for the given notebook state. | ||
var all_models = Promise.all(_.map(Object.keys(state), function (model_id) { | ||
// Recreate a comm using the widget's model id (model_id == comm_id). | ||
var new_comm = new comm.Comm(kernel.widget_manager.comm_target_name, model_id); | ||
kernel.comm_manager.register_comm(new_comm); | ||
|
||
// Create the model using the recreated comm. When the model is | ||
// created we don't know yet if the comm is valid so set_comm_live | ||
// false. Once we receive the first state push from the back-end | ||
// we know the comm is alive. | ||
return kernel.widget_manager.create_model({ | ||
comm: new_comm, | ||
model_name: state[model_id].model_name, | ||
model_module: state[model_id].model_module, | ||
}).then(function(model) { | ||
model.set_comm_live(false); | ||
return model._deserialize_state(state[model.id].state).then(function(state) { | ||
model.set_state(state); | ||
return model.request_state().then(function() { | ||
model.set_comm_live(true); | ||
return model; | ||
var all_models = that._get_comm_info(kernel).then(function(live_comms) { | ||
return Promise.all(_.map(Object.keys(state), function (model_id) { | ||
if (live_comms.hasOwnProperty(model_id)) { // live comm | ||
var new_comm = new comm.Comm(kernel.widget_manager.comm_target_name, model_id); | ||
kernel.comm_manager.register_comm(new_comm); | ||
return kernel.widget_manager.new_model({ | ||
comm: new_comm, | ||
model_name: state[model_id].model_name, | ||
model_module: state[model_id].model_module, | ||
}).then(function(model) { | ||
return model.request_state().then(function() { | ||
return model; | ||
}); | ||
}); | ||
}); | ||
}); | ||
}, this)); | ||
} else { // dead comm | ||
return kernel.widget_manager.new_model({ | ||
model_id: model_id, | ||
model_name: state[model_id].model_name, | ||
model_module: state[model_id].model_module, | ||
}).then(function(model) { | ||
return model._deserialize_state(state[model_id].state).then(function(state) { | ||
model.set_state(state); | ||
return model; | ||
}); | ||
}); | ||
} | ||
})); | ||
}); | ||
|
||
// Display all the views | ||
return all_models.then(function(models) { | ||
|
@@ -480,6 +500,35 @@ define([ | |
}); | ||
}; | ||
|
||
WidgetManager.prototype._get_comm_info = function(kernel) { | ||
/** | ||
* Gets a promise for the open comms in the backend | ||
*/ | ||
|
||
// Version using the comm_list_[request/reply] shell message. | ||
/*var that = this; | ||
return new Promise(function(resolve, reject) { | ||
kernel.comm_info(function(msg) { | ||
resolve(msg['content']['comms']); | ||
}); | ||
});*/ | ||
|
||
// Workaround for absence of comm_list_[request/reply] shell message. | ||
// Create a new widget that gives the comm list and commits suicide. | ||
var that = this; | ||
return new Promise(function(resolve, reject) { | ||
var comm = that.comm_manager.new_comm('ipython.widget', | ||
{'widget_class': 'ipywidgets.CommInfo'}, | ||
'comm_info'); | ||
comm.on_msg(function(msg) { | ||
var data = msg.content.data; | ||
if (data.content && data.method === 'custom') { | ||
resolve(data.content.comms); | ||
} | ||
}); | ||
}); | ||
}; | ||
|
||
// Backwards compatibility. | ||
IPython.WidgetManager = WidgetManager; | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Backwards incompatibility
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not backward incompatible because we could not pass model id in the options before.
The new create_model only allows setting the model id.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah gotcha, read too quick. Saw "Unlike the old version of create_model"