Merge pull request #11 from minrk/widgets

Widget review
This commit is contained in:
Jonathan Frederic 2014-01-28 09:27:43 -08:00
commit 2230b751c1
25 changed files with 331 additions and 749 deletions

View File

@ -82,8 +82,7 @@
if (view === null) {
console.error("View creation failed", model);
}
if (cell.widget_subarea !== undefined
&& cell.widget_subarea !== null) {
if (cell.widget_subarea) {
cell.widget_area.show();
cell.widget_subarea.append(view.$el);
@ -95,7 +94,7 @@
// Creates a view for a particular model.
var view_name = model.get('_view_name');
var ViewType = WidgetManager._view_types[view_name];
if (ViewType !== undefined && ViewType !== null) {
if (ViewType) {
// If a view is passed into the method, use that view's cell as
// the cell for the view that is created.
@ -106,7 +105,7 @@
// Create and render the view...
var parameters = {model: model, options: options};
var view = new ViewType(parameters);
view = new ViewType(parameters);
view.render();
model.views.push(view);
model.on('destroy', view.remove, view);
@ -123,33 +122,31 @@
// If the view has a well defined element, inform the keyboard
// manager about the view's element, so as the element can
// escape the dreaded command mode.
if (view.$el !== undefined && view.$el !== null) {
if (view.$el) {
IPython.keyboard_manager.register_events(view.$el);
}
}
};
WidgetManager.prototype.get_msg_cell = function (msg_id) {
var cell = null;
// First, check to see if the msg was triggered by cell execution.
if (IPython.notebook !== undefined && IPython.notebook !== null) {
if (IPython.notebook) {
cell = IPython.notebook.get_msg_cell(msg_id);
}
if (cell !== null) {
return cell
return cell;
}
// Second, check to see if a get_cell callback was defined
// for the message. get_cell callbacks are registered for
// widget messages, so this block is actually checking to see if the
// message was triggered by a widget.
var kernel = this.comm_manager.kernel;
if (kernel !== undefined && kernel !== null) {
if (kernel) {
var callbacks = kernel.get_callbacks_for_msg(msg_id);
if (callbacks !== undefined &&
callbacks.iopub !== undefined &&
if (callbacks && callbacks.iopub &&
callbacks.iopub.get_cell !== undefined) {
return callbacks.iopub.get_cell();
}
}
}
// Not triggered by a cell or widget (no get_cell callback
@ -160,16 +157,13 @@
WidgetManager.prototype.callbacks = function (view) {
// callback handlers specific a view
var callbacks = {};
if (view !== undefined &&
view !== null &&
view.options.cell !== undefined &&
view.options.cell !== null) {
if (view && view.options.cell) {
// Try to get output handlers
var cell = view.options.cell;
var handle_output = null;
var handle_clear_output = null;
if (cell.output_area !== undefined && cell.output_area !== null) {
if (cell.output_area) {
handle_output = $.proxy(cell.output_area.handle_output, cell.output_area);
handle_clear_output = $.proxy(cell.output_area.handle_clear_output, cell.output_area);
}

View File

@ -21,7 +21,7 @@ function(WidgetManager, Underscore, Backbone){
var WidgetModel = Backbone.Model.extend({
constructor: function (widget_manager, model_id, comm) {
// Construcctor
// Constructor
//
// Creates a WidgetModel instance.
//
@ -111,7 +111,7 @@ function(WidgetManager, Underscore, Backbone){
if (this.msg_buffer !== null &&
this.msg_throttle === this.pending_msgs) {
var data = {method: 'backbone', sync_method: 'update', sync_data: this.msg_buffer};
this.comm.send(data, callbacks);
this.comm.send(data, callbacks);
this.msg_buffer = null;
} else {
--this.pending_msgs;
@ -131,7 +131,7 @@ function(WidgetManager, Underscore, Backbone){
var that = this;
callbacks.iopub.status = function (msg) {
that._handle_status(msg, callbacks);
}
};
return callbacks;
},
@ -141,7 +141,7 @@ function(WidgetManager, Underscore, Backbone){
// Make sure a comm exists.
var error = options.error || function() {
console.error('Backbone sync error:', arguments);
}
};
if (this.comm === undefined) {
error();
return false;
@ -233,7 +233,7 @@ function(WidgetManager, Underscore, Backbone){
return unpacked;
} else {
var model = this.widget_manager.get_model(value);
if (model !== null) {
if (model) {
return model;
} else {
return value;
@ -279,7 +279,7 @@ function(WidgetManager, Underscore, Backbone){
var view = this.child_views[child_model.id];
if (view !== undefined) {
delete this.child_views[child_model.id];
view.remove();
view.remove();
}
},
@ -373,7 +373,7 @@ function(WidgetManager, Underscore, Backbone){
// to render
var e = this.$el;
var visible = this.model.get('visible');
setTimeout(function() {e.toggle(visible)},0);
setTimeout(function() {e.toggle(visible);},0);
var css = this.model.get('_css');
if (css === undefined) {return;}
@ -387,17 +387,16 @@ function(WidgetManager, Underscore, Backbone){
});
}
});
},
_get_selector_element: function (selector) {
// Get the elements via the css selector.
// Get the elements via the css selector.
// If the selector is blank, apply the style to the $el_to_style
// element. If the $el_to_style element is not defined, use apply
// the style to the view's element.
var elements;
if (selector === undefined || selector === null || selector === '') {
if (!selector) {
if (this.$el_to_style === undefined) {
elements = this.$el;
} else {

View File

@ -16,7 +16,7 @@
define(["notebook/js/widgets/widget"], function(WidgetManager){
var ButtonView = IPython.DOMWidgetView.extend({
var ButtonView = IPython.DOMWidgetView.extend({
render : function(){
// Called when view is rendered.
this.setElement($("<button />")

View File

@ -16,22 +16,21 @@
define(["notebook/js/widgets/widget"], function(WidgetManager) {
var ContainerView = IPython.DOMWidgetView.extend({
var ContainerView = IPython.DOMWidgetView.extend({
render: function(){
// Called when view is rendered.
this.$el
.addClass('widget-container');
this.$el.addClass('widget-container');
this.children={};
this.update_children([], this.model.get('_children'));
this.model.on('change:_children', function(model, value, options) {
this.update_children(model.previous('_children'), value);
}, this);
this.update()
this.update();
},
update_children: function(old_list, new_list) {
// Called when the children list changes.
this.do_diff(old_list,
this.do_diff(old_list,
new_list,
$.proxy(this.remove_child_model, this),
$.proxy(this.add_child_model, this));
@ -57,17 +56,16 @@ define(["notebook/js/widgets/widget"], function(WidgetManager) {
return ContainerView.__super__.update.apply(this);
},
});
WidgetManager.register_widget_view('ContainerView', ContainerView);
var PopupView = IPython.DOMWidgetView.extend({
var PopupView = IPython.DOMWidgetView.extend({
render: function(){
// Called when view is rendered.
var that = this;
this.children={};
this.$el
.on("remove", function(){
this.$el.on("remove", function(){
that.$window.remove();
});
this.$window = $('<div />')

View File

@ -32,7 +32,7 @@ define(["notebook/js/widgets/widget",
WidgetManager.register_widget_view('FloatSliderView', FloatSliderView);
var FloatTextView = IntTextView.extend({
var FloatTextView = IntTextView.extend({
_parse_value: function(value) {
// Parse the value stored in a string.
return parseFloat(value);

View File

@ -16,7 +16,7 @@
define(["notebook/js/widgets/widget"], function(WidgetManager){
var IntSliderView = IPython.DOMWidgetView.extend({
var IntSliderView = IPython.DOMWidgetView.extend({
render : function(){
// Called when view is rendered.
this.$el
@ -32,7 +32,7 @@ define(["notebook/js/widgets/widget"], function(WidgetManager){
// Put the slider in a container
this.$slider_container = $('<div />')
.addClass('widget-hslider')
.append(this.$slider);
.append(this.$slider);
this.$el_to_style = this.$slider_container; // Set default element to style
this.$el.append(this.$slider_container);
@ -218,7 +218,7 @@ define(["notebook/js/widgets/widget"], function(WidgetManager){
}
},
handleChanged: function(e) {
handleChanged: function(e) {
// Applies validated input.
if (this.model.get('value') != e.target.value) {
e.target.value = this.model.get('value');
@ -233,7 +233,7 @@ define(["notebook/js/widgets/widget"], function(WidgetManager){
WidgetManager.register_widget_view('IntTextView', IntTextView);
var ProgressView = IPython.DOMWidgetView.extend({
var ProgressView = IPython.DOMWidgetView.extend({
render : function(){
// Called when view is rendered.
this.$el

View File

@ -18,7 +18,7 @@ define(["notebook/js/widgets/widget"], function(WidgetManager){
var DropdownView = IPython.DOMWidgetView.extend({
render : function(){
// Called when view is rendered.
// Called when view is rendered.
this.$el
.addClass('widget-hbox-single');
this.$label = $('<div />')

View File

@ -6,7 +6,7 @@ casper.notebook_test(function () {
// Check if the WidgetManager class is defined.
this.test.assert(this.evaluate(function() {
return IPython.WidgetManager != undefined;
return IPython.WidgetManager !== undefined;
}), 'WidgetManager class is defined');
});
@ -19,10 +19,10 @@ casper.notebook_test(function () {
this.wait(500); // Wait for require.js async callbacks to load dependencies.
this.then(function () {
// Check if the widget manager has been instanciated.
// Check if the widget manager has been instantiated.
this.test.assert(this.evaluate(function() {
return IPython.notebook.kernel.widget_manager != undefined;
}), 'Notebook widget manager instanciated');
return IPython.notebook.kernel.widget_manager !== undefined;
}), 'Notebook widget manager instantiated');
});
throttle_index = this.append_cell(
@ -33,10 +33,10 @@ casper.notebook_test(function () {
'def handle_change(name, old, new):\n' +
' print(len(new))\n' +
' time.sleep(0.5)\n' +
'textbox.on_trait_change(handle_change)\n' +
'textbox.on_trait_change(handle_change, "value")\n' +
'print("Success")');
this.execute_cell_then(throttle_index, function(index){
this.test.assert(this.get_output_cell(index).text == 'Success\n',
this.test.assertEquals(this.get_output_cell(index).text, 'Success\n',
'Test throttling cell executed with correct output');
this.test.assert(this.cell_element_exists(index,
@ -53,24 +53,17 @@ casper.notebook_test(function () {
this.wait(2000); // Wait for clicks to execute in kernel
this.then(function(){
var resume = true;
var i = 0;
while (resume) {
i++;
var output = this.get_output_cell(throttle_index, i);
if (output === undefined || output === null) {
resume = false;
i--;
}
}
var outputs = this.evaluate(function(i) {
return IPython.notebook.get_cell(i).output_area.outputs;
}, {i : throttle_index});
// Only 4 outputs should have printed, but because of timing, sometimes
// 5 outputs will print. All we need to do is verify num outputs <= 5
// because that is much less than 20.
this.test.assert(i <= 5, 'Messages throttled.');
this.test.assert(outputs.length <= 5, 'Messages throttled.');
// We also need to verify that the last state sent was correct.
var last_state = this.get_output_cell(throttle_index, i).text;
this.test.assert(last_state == "20\n", "Last state sent when throttling.");
var last_state = outputs[outputs.length-1].text;
this.test.assertEquals(last_state, "20\n", "Last state sent when throttling.");
});
});

View File

@ -14,7 +14,7 @@ casper.notebook_test(function () {
'print("Success")');
this.execute_cell_then(bool_index, function(index){
this.test.assert(this.get_output_cell(index).text == 'Success\n',
this.test.assertEquals(this.get_output_cell(index).text, 'Success\n',
'Create bool widget cell executed with correct output.');
this.test.assert(this.cell_element_exists(index,
@ -57,7 +57,7 @@ casper.notebook_test(function () {
'print("Success")');
this.execute_cell_then(index, function(index){
this.test.assert(this.get_output_cell(index).text == 'Success\n',
this.test.assertEquals(this.get_output_cell(index).text, 'Success\n',
'Change bool widget value cell executed with correct output.');
this.test.assert(! this.cell_element_function(bool_index,

View File

@ -15,7 +15,7 @@ casper.notebook_test(function () {
'button.on_click(handle_click)');
this.execute_cell_then(button_index, function(index){
this.test.assert(this.get_output_cell(index).text == 'Success\n',
this.test.assertEquals(this.get_output_cell(index).text, 'Success\n',
'Create button cell executed with correct output.');
this.test.assert(this.cell_element_exists(index,
@ -37,7 +37,7 @@ casper.notebook_test(function () {
this.wait(500); // Wait for click to execute in kernel and write output
this.then(function () {
this.test.assert(this.get_output_cell(button_index, 1).text == 'Clicked\n',
this.test.assertEquals(this.get_output_cell(button_index, 1).text, 'Clicked\n',
'Button click event fires.');
});
});

View File

@ -15,7 +15,7 @@ casper.notebook_test(function () {
'print("Success")\n');
this.execute_cell_then(container_index, function(index){
this.test.assert(this.get_output_cell(index).text == 'Success\n',
this.test.assertEquals(this.get_output_cell(index).text, 'Success\n',
'Create container cell executed with correct output.');
this.test.assert(this.cell_element_exists(index,
@ -40,7 +40,7 @@ casper.notebook_test(function () {
'print("Success")\n');
this.execute_cell_then(index, function(index){
this.test.assert(this.get_output_cell(index).text == 'Success\n',
this.test.assertEquals(this.get_output_cell(index).text, 'Success\n',
'Set container class CSS cell executed with correct output.');
this.test.assert(this.cell_element_function(container_index,
@ -53,7 +53,7 @@ casper.notebook_test(function () {
'print("Success")\n');
this.execute_cell_then(index, function(index){
this.test.assert(this.get_output_cell(index).text == 'Success\n',
this.test.assertEquals(this.get_output_cell(index).text, 'Success\n',
'Remove container class cell executed with correct output.');
this.test.assert(! this.cell_element_exists(container_index,
@ -66,7 +66,7 @@ casper.notebook_test(function () {
'print("Success")\n');
this.execute_cell_then(index, function(index){
this.test.assert(this.get_output_cell(index).text == 'Success\n',
this.test.assertEquals(this.get_output_cell(index).text, 'Success\n',
'Display container child executed with correct output.');
this.test.assert(! this.cell_element_exists(index,

View File

@ -15,7 +15,7 @@ casper.notebook_test(function () {
'print("Success")\n');
this.execute_cell_then(float_index, function(index){
this.test.assert(this.get_output_cell(index).text == 'Success\n',
this.test.assertEquals(this.get_output_cell(index).text, 'Success\n',
'Create float cell executed with correct output.');
this.test.assert(this.cell_element_exists(index,
@ -33,7 +33,7 @@ casper.notebook_test(function () {
index = this.append_cell('print(float_widget.value)\n');
this.execute_cell_then(index, function(index){
this.test.assert(this.get_output_cell(index).text == '1.05\n',
this.test.assertEquals(this.get_output_cell(index).text, '1.05\n',
'Float textbox value set.');
this.cell_element_function(float_index, float_text_query_2, 'val', ['']);
this.sendKeys(float_text_query_2, '123456789.0');
@ -43,7 +43,7 @@ casper.notebook_test(function () {
index = this.append_cell('print(float_widget.value)\n');
this.execute_cell_then(index, function(index){
this.test.assert(this.get_output_cell(index).text == '123456789.0\n',
this.test.assertEquals(this.get_output_cell(index).text, '123456789.0\n',
'Long float textbox value set (probably triggers throttling).');
this.cell_element_function(float_index, float_text_query_2, 'val', ['']);
this.sendKeys(float_text_query_2, '12hello');
@ -53,7 +53,7 @@ casper.notebook_test(function () {
index = this.append_cell('print(float_widget.value)\n');
this.execute_cell_then(index, function(index){
this.test.assert(this.get_output_cell(index).text == '12.0\n',
this.test.assertEquals(this.get_output_cell(index).text, '12.0\n',
'Invald float textbox value caught and filtered.');
});
@ -73,7 +73,7 @@ casper.notebook_test(function () {
'print("Success")\n');
this.execute_cell_then(floatrange_index, function(index){
this.test.assert(this.get_output_cell(index).text == 'Success\n',
this.test.assertEquals(this.get_output_cell(index).text, 'Success\n',
'Create float range cell executed with correct output.');
this.test.assert(this.cell_element_exists(index,
@ -95,7 +95,7 @@ casper.notebook_test(function () {
'print("Success")\n');
this.execute_cell_then(index, function(index){
this.test.assert(this.get_output_cell(index).text == 'Success\n',
this.test.assertEquals(this.get_output_cell(index).text, 'Success\n',
'Float range properties cell executed with correct output.');
this.test.assert(this.cell_element_exists(floatrange_index, slider_query),

View File

@ -32,7 +32,7 @@ casper.notebook_test(function () {
'print("Success")\n');
this.execute_cell_then(image_index, function(index){
this.test.assert(this.get_output_cell(index).text == 'Success\n',
this.test.assertEquals(this.get_output_cell(index).text, 'Success\n',
'Create image executed with correct output.');
this.test.assert(this.cell_element_exists(index,
@ -49,12 +49,12 @@ casper.notebook_test(function () {
this.captureSelector(capture_filename, '.my-test-image');
var stream = fs.open(capture_filename, 'rb');
var captured = btoa(stream.read());
stream.close()
stream.close();
fs.remove(capture_filename);
// Uncomment line below to output captured image data to a text file.
// fs.write('./captured.txt', captured, 'w');
this.test.assert(test_results==captured, "Red image data displayed correctly.");
this.test.assertEquals(test_results, captured, "Red image data displayed correctly.");
});
});

View File

@ -15,7 +15,7 @@ casper.notebook_test(function () {
'print("Success")\n');
this.execute_cell_then(int_index, function(index){
this.test.assert(this.get_output_cell(index).text == 'Success\n',
this.test.assertEquals(this.get_output_cell(index).text, 'Success\n',
'Create int cell executed with correct output.');
this.test.assert(this.cell_element_exists(index,
@ -33,7 +33,7 @@ casper.notebook_test(function () {
index = this.append_cell('print(int_widget.value)\n');
this.execute_cell_then(index, function(index){
this.test.assert(this.get_output_cell(index).text == '1\n',
this.test.assertEquals(this.get_output_cell(index).text, '1\n',
'Int textbox value set.');
this.cell_element_function(int_index, int_text_query_2, 'val', ['']);
this.sendKeys(int_text_query_2, '123456789');
@ -43,7 +43,7 @@ casper.notebook_test(function () {
index = this.append_cell('print(int_widget.value)\n');
this.execute_cell_then(index, function(index){
this.test.assert(this.get_output_cell(index).text == '123456789\n',
this.test.assertEquals(this.get_output_cell(index).text, '123456789\n',
'Long int textbox value set (probably triggers throttling).');
this.cell_element_function(int_index, int_text_query_2, 'val', ['']);
this.sendKeys(int_text_query_2, '12hello');
@ -53,7 +53,7 @@ casper.notebook_test(function () {
index = this.append_cell('print(int_widget.value)\n');
this.execute_cell_then(index, function(index){
this.test.assert(this.get_output_cell(index).text == '12\n',
this.test.assertEquals(this.get_output_cell(index).text, '12\n',
'Invald int textbox value caught and filtered.');
});
@ -74,7 +74,7 @@ casper.notebook_test(function () {
'print("Success")\n');
this.execute_cell_then(intrange_index, function(index){
this.test.assert(this.get_output_cell(index).text == 'Success\n',
this.test.assertEquals(this.get_output_cell(index).text, 'Success\n',
'Create int range cell executed with correct output.');
this.test.assert(this.cell_element_exists(index,
@ -96,7 +96,7 @@ casper.notebook_test(function () {
'print("Success")\n');
this.execute_cell_then(index, function(index){
this.test.assert(this.get_output_cell(index).text == 'Success\n',
this.test.assertEquals(this.get_output_cell(index).text, 'Success\n',
'Int range properties cell executed with correct output.');
this.test.assert(this.cell_element_exists(intrange_index, slider_query),
@ -119,7 +119,7 @@ casper.notebook_test(function () {
index = this.append_cell('print(intrange[0].value)\n');
this.execute_cell_then(index, function(index){
this.test.assert(this.get_output_cell(index).text == '1\n',
this.test.assertEquals(this.get_output_cell(index).text, '1\n',
'Int textbox set int range value');
// Clear the int textbox value and then set it to 120 by emulating
@ -132,7 +132,7 @@ casper.notebook_test(function () {
index = this.append_cell('print(intrange[0].value)\n');
this.execute_cell_then(index, function(index){
this.test.assert(this.get_output_cell(index).text == '50\n',
this.test.assertEquals(this.get_output_cell(index).text, '50\n',
'Int textbox value bound');
// Clear the int textbox value and then set it to 'hello world' by
@ -145,7 +145,7 @@ casper.notebook_test(function () {
index = this.append_cell('print(intrange[0].value)\n');
this.execute_cell_then(index, function(index){
this.test.assert(this.get_output_cell(index).text == '50\n',
this.test.assertEquals(this.get_output_cell(index).text, '50\n',
'Invalid int textbox characters ignored');
});
});

View File

@ -19,7 +19,7 @@ casper.notebook_test(function () {
'print("Success")\n');
this.execute_cell_then(multicontainer1_index, function(index){
this.test.assert(this.get_output_cell(index).text == 'Success\n',
this.test.assertEquals(this.get_output_cell(index).text, 'Success\n',
'Create multicontainer cell executed with correct output. (1)');
this.test.assert(this.cell_element_exists(index,
@ -33,7 +33,7 @@ casper.notebook_test(function () {
'First widget tab list exists.');
// JQuery selector is 1 based
this.click(multicontainer1_query + ' li:nth-child(2) a')
this.click(multicontainer1_query + ' li:nth-child(2) a');
});
this.wait(500); // Wait for change to execute in kernel
@ -42,16 +42,16 @@ casper.notebook_test(function () {
'print(multicontainer.selected_index)\n' +
'multicontainer.selected_index = 2'); // 0 based
this.execute_cell_then(index, function(index){
this.test.assert(this.get_output_cell(index).text == '1\n', // 0 based
this.test.assertEquals(this.get_output_cell(index).text, '1\n', // 0 based
'selected_index property updated with tab change.');
// JQuery selector is 1 based
this.test.assert(!this.cell_element_function(multicontainer1_index, multicontainer1_query + ' li:nth-child(1)', 'hasClass', ['active']),
"Tab 1 is not selected.")
"Tab 1 is not selected.");
this.test.assert(!this.cell_element_function(multicontainer1_index, multicontainer1_query + ' li:nth-child(2)', 'hasClass', ['active']),
"Tab 2 is not selected.")
"Tab 2 is not selected.");
this.test.assert(this.cell_element_function(multicontainer1_index, multicontainer1_query + ' li:nth-child(3)', 'hasClass', ['active']),
"Tab 3 is selected.")
"Tab 3 is selected.");
});
index = this.append_cell('multicontainer.set_title(1, "hello")\nprint("Success")'); // 0 based
@ -75,7 +75,7 @@ casper.notebook_test(function () {
'print("Success")\n');
this.execute_cell_then(multicontainer2_index, function(index){
this.test.assert(this.get_output_cell(index).text == 'Success\n',
this.test.assertEquals(this.get_output_cell(index).text, 'Success\n',
'Create multicontainer cell executed with correct output. (2)');
this.test.assert(this.cell_element_exists(index,
@ -102,7 +102,7 @@ casper.notebook_test(function () {
index = this.append_cell('print(multicontainer.selected_index)'); // 0 based
this.execute_cell_then(index, function(index){
this.test.assert(this.get_output_cell(index).text == '1\n', // 0 based
this.test.assertEquals(this.get_output_cell(index).text, '1\n', // 0 based
'selected_index property updated with tab change.');
});
});

View File

@ -6,10 +6,10 @@ casper.notebook_test(function () {
'print("Success")');
this.execute_cell_then(index);
var combo_selector = '.widget-area .widget-subarea .widget-hbox-single .btn-group .widget-combo-btn'
var multibtn_selector = '.widget-area .widget-subarea .widget-hbox-single .btn-group[data-toggle="buttons-radio"]'
var radio_selector = '.widget-area .widget-subarea .widget-hbox .vbox'
var list_selector = '.widget-area .widget-subarea .widget-hbox .widget-listbox'
var combo_selector = '.widget-area .widget-subarea .widget-hbox-single .btn-group .widget-combo-btn';
var multibtn_selector = '.widget-area .widget-subarea .widget-hbox-single .btn-group[data-toggle="buttons-radio"]';
var radio_selector = '.widget-area .widget-subarea .widget-hbox .vbox';
var list_selector = '.widget-area .widget-subarea .widget-hbox .widget-listbox';
var selection_index;
var selection_values = 'abcd';
@ -30,7 +30,7 @@ casper.notebook_test(function () {
combo_state == state;
}
return true;
}
};
var verify_selection = function(context, index){
for (var i = 0; i < selection_values.length; i++) {
@ -39,7 +39,7 @@ casper.notebook_test(function () {
}
}
return true;
}
};
//values=["' + selection_values + '"[i] for i in range(4)]
selection_index = this.append_cell(
@ -56,7 +56,7 @@ casper.notebook_test(function () {
' widget.on_trait_change(handle_change, "value")\n' +
'print("Success")\n');
this.execute_cell_then(selection_index, function(index){
this.test.assert(this.get_output_cell(index).text == 'Success\n',
this.test.assertEquals(this.get_output_cell(index).text, 'Success\n',
'Create selection cell executed with correct output.');
this.test.assert(this.cell_element_exists(index,
@ -84,7 +84,7 @@ casper.notebook_test(function () {
' widget.value = "a"\n' +
'print("Success")\n');
this.execute_cell_then(index, function(index){
this.test.assert(this.get_output_cell(index).text == 'Success\n',
this.test.assertEquals(this.get_output_cell(index).text, 'Success\n',
'Python select item executed with correct output.');
// Verify that the first item is selected.

View File

@ -15,7 +15,7 @@ casper.notebook_test(function () {
'print("Success")');
this.execute_cell_then(string_index, function(index){
this.test.assert(this.get_output_cell(index).text == 'Success\n',
this.test.assertEquals(this.get_output_cell(index).text, 'Success\n',
'Create string widget cell executed with correct output.');
this.test.assert(this.cell_element_exists(index,

View File

@ -13,37 +13,28 @@ in the IPython notebook front-end.
# Imports
#-----------------------------------------------------------------------------
from contextlib import contextmanager
import inspect
import types
from IPython.kernel.comm import Comm
from IPython.config import LoggingConfigurable
from IPython.utils.traitlets import Unicode, Dict, Instance, Bool, List
from IPython.utils.traitlets import Unicode, Dict, Instance, Bool, List, Tuple
from IPython.utils.py3compat import string_types
#-----------------------------------------------------------------------------
# Classes
#-----------------------------------------------------------------------------
class CallbackDispatcher(LoggingConfigurable):
acceptable_nargs = List([], help="""List of integers.
The number of arguments in the callbacks registered must match one of
the integers in this list. If this list is empty or None, it will be
ignored.""")
def __init__(self, *pargs, **kwargs):
"""Constructor"""
LoggingConfigurable.__init__(self, *pargs, **kwargs)
self.callbacks = {}
def __call__(self, *pargs, **kwargs):
"""Call all of the registered callbacks that have the same number of
positional arguments."""
nargs = len(pargs)
self._validate_nargs(nargs)
"""A structure for registering and running callbacks"""
callbacks = List()
def __call__(self, *args, **kwargs):
"""Call all of the registered callbacks."""
value = None
if nargs in self.callbacks:
for callback in self.callbacks[nargs]:
local_value = callback(*pargs, **kwargs)
for callback in self.callbacks:
try:
local_value = callback(*args, **kwargs)
except Exception as e:
self.log.warn("Exception in callback %s: %s", callback, e)
else:
value = local_value if local_value is not None else value
return value
@ -53,69 +44,37 @@ class CallbackDispatcher(LoggingConfigurable):
Parameters
----------
callback: method handle
Method to be registered or unregisted.
Method to be registered or unregistered.
remove=False: bool
Whether or not to unregister the callback."""
# Validate the number of arguments that the callback accepts.
nargs = self._get_nargs(callback)
self._validate_nargs(nargs)
# Get/create the appropriate list of callbacks.
if nargs not in self.callbacks:
self.callbacks[nargs] = []
callback_list = self.callbacks[nargs]
Whether to unregister the callback."""
# (Un)Register the callback.
if remove and callback in callback_list:
callback_list.remove(callback)
elif not remove and callback not in callback_list:
callback_list.append(callback)
def _validate_nargs(self, nargs):
if self.acceptable_nargs is not None and \
len(self.acceptable_nargs) > 0 and \
nargs not in self.acceptable_nargs:
raise TypeError('Invalid number of positional arguments. See acceptable_nargs list.')
def _get_nargs(self, callback):
"""Gets the number of arguments in a callback"""
if callable(callback):
argspec = inspect.getargspec(callback)
if argspec[0] is None:
nargs = 0
elif argspec[3] is None:
nargs = len(argspec[0]) # Only count vargs!
else:
nargs = len(argspec[0]) - len(argspec[3]) # Subtract number of defaults.
# Bound methods have an additional 'self' argument
if isinstance(callback, types.MethodType):
nargs -= 1
return nargs
else:
raise TypeError('Callback must be callable.')
if remove and callback in self.callbacks:
self.callbacks.remove(callback)
elif not remove and callback not in self.callbacks:
self.callbacks.append(callback)
class Widget(LoggingConfigurable):
#-------------------------------------------------------------------------
# Class attributes
#-------------------------------------------------------------------------
widget_construction_callback = None
_widget_construction_callback = None
widgets = {}
@staticmethod
def on_widget_constructed(callback):
"""Registers a callback to be called when a widget is constructed.
"""Registers a callback to be called when a widget is constructed.
The callback must have the following signature:
callback(widget)"""
Widget.widget_construction_callback = callback
Widget._widget_construction_callback = callback
@staticmethod
def _call_widget_constructed(widget):
"""Class method, called when a widget is constructed."""
if Widget.widget_construction_callback is not None and callable(Widget.widget_construction_callback):
Widget.widget_construction_callback(widget)
"""Static method, called when a widget is constructed."""
if Widget._widget_construction_callback is not None and callable(Widget._widget_construction_callback):
Widget._widget_construction_callback(widget)
#-------------------------------------------------------------------------
# Traits
@ -125,20 +84,23 @@ class Widget(LoggingConfigurable):
_view_name = Unicode(help="""Default view registered in the front-end
to use to represent the widget.""", sync=True)
_comm = Instance('IPython.kernel.comm.Comm')
closed = Bool(False)
keys = List()
def _keys_default(self):
return [name for name in self.traits(sync=True)]
_property_lock = Tuple((None, None))
_display_callbacks = Instance(CallbackDispatcher, ())
_msg_callbacks = Instance(CallbackDispatcher, ())
#-------------------------------------------------------------------------
# (Con/de)structor
#-------------------------------------------------------------------------
#-------------------------------------------------------------------------
def __init__(self, **kwargs):
"""Public constructor"""
self.closed = False
self._property_lock = (None, None)
self._keys = None
self._display_callbacks = CallbackDispatcher(acceptable_nargs=[0])
self._msg_callbacks = CallbackDispatcher(acceptable_nargs=[1, 2])
super(Widget, self).__init__(**kwargs)
self.on_trait_change(self._handle_property_changed, self.keys)
@ -150,16 +112,7 @@ class Widget(LoggingConfigurable):
#-------------------------------------------------------------------------
# Properties
#-------------------------------------------------------------------------
@property
def keys(self):
"""Gets a list of the traitlets that should be synced with the front-end."""
if self._keys is None:
self._keys = []
for trait_name in self.trait_names():
if self.trait_metadata(trait_name, 'sync'):
self._keys.append(trait_name)
return self._keys
#-------------------------------------------------------------------------
@property
def comm(self):
@ -186,15 +139,21 @@ class Widget(LoggingConfigurable):
#-------------------------------------------------------------------------
# Methods
#-------------------------------------------------------------------------
#-------------------------------------------------------------------------
def _close(self):
"""Private close - cleanup objects, registry entries"""
del Widget.widgets[self.model_id]
self._comm = None
self.closed = True
def close(self):
"""Close method.
"""Close method.
Closes the widget which closes the underlying comm.
When the comm is closed, all of the widget views are automatically
removed from the front-end."""
if not self.closed:
self._comm.close()
self._comm.close()
self._close()
def send_state(self, key=None):
@ -232,14 +191,13 @@ class Widget(LoggingConfigurable):
self._send({"method": "custom", "content": content})
def on_msg(self, callback, remove=False):
"""(Un)Register a custom msg recieve callback.
"""(Un)Register a custom msg receive callback.
Parameters
----------
callback: method handler
Can have a signature of:
- callback(content) Signature 1
- callback(sender, content) Signature 2
callback: callable
callback will be passed two arguments when a message arrives:
callback(widget, content)
remove: bool
True if the callback should be unregistered."""
self._msg_callbacks.register_callback(callback, remove=remove)
@ -250,9 +208,9 @@ class Widget(LoggingConfigurable):
Parameters
----------
callback: method handler
Can have a signature of:
- callback(sender, **kwargs)
kwargs from display call passed through without modification.
Must have a signature of:
callback(widget, **kwargs)
kwargs from display are passed through without modification.
remove: bool
True if the callback should be unregistered."""
self._display_callbacks.register_callback(callback, remove=remove)
@ -278,12 +236,6 @@ class Widget(LoggingConfigurable):
return key != self._property_lock[0] or \
value != self._property_lock[1]
def _close(self):
"""Unsafe close"""
del Widget.widgets[self.model_id]
self._comm = None
self.closed = True
# Event handlers
def _handle_msg(self, msg):
"""Called when a msg is received from the front-end"""
@ -312,8 +264,7 @@ class Widget(LoggingConfigurable):
def _handle_custom_msg(self, content):
"""Called when a custom msg is received."""
self._msg_callbacks(content) # Signature 1
self._msg_callbacks(self, content) # Signature 2
self._msg_callbacks(self, content)
def _handle_property_changed(self, name, old, new):
"""Called when a property has been changed."""
@ -324,7 +275,7 @@ class Widget(LoggingConfigurable):
def _handle_displayed(self, **kwargs):
"""Called when a view has been displayed for this widget instance"""
self._display_callbacks(**kwargs)
self._display_callbacks(self, **kwargs)
def _pack_widgets(self, x):
"""Recursively converts all widget instances to model id strings.
@ -367,7 +318,7 @@ class Widget(LoggingConfigurable):
class DOMWidget(Widget):
visible = Bool(True, help="Whether or not the widget is visible.", sync=True)
visible = Bool(True, help="Whether the widget is visible.", sync=True)
_css = Dict(sync=True) # Internal CSS property dict
def get_css(self, key, selector=""):
@ -388,7 +339,7 @@ class DOMWidget(Widget):
else:
return None
def set_css(self, *args, **kwargs):
def set_css(self, dict_or_key, value=None, selector=''):
"""Set one or more CSS properties of the widget.
This function has two signatures:
@ -401,9 +352,9 @@ class DOMWidget(Widget):
CSS key/value pairs to apply
key: unicode
CSS key
value
value:
CSS value
selector: unicode (optional)
selector: unicode (optional, kwarg only)
JQuery selector to use to apply the CSS key/value. If no selector
is provided, an empty selector is used. An empty selector makes the
front-end try to apply the css to a default element. The default
@ -411,37 +362,19 @@ class DOMWidget(Widget):
of the view that should be styled with common CSS (see
`$el_to_style` in the Javascript code).
"""
selector = kwargs.get('selector', '')
if not selector in self._css:
self._css[selector] = {}
# Signature 1: set_css(css_dict, selector='')
if len(args) == 1:
if isinstance(args[0], dict):
for (key, value) in args[0].items():
if not (key in self._css[selector] and value == self._css[selector][key]):
self._css[selector][key] = value
self.send_state('_css')
else:
raise Exception('css_dict must be a dict.')
# Signature 2: set_css(key, value, selector='')
elif len(args) == 2 or len(args) == 3:
# Selector can be a positional arg if it's the 3rd value
if len(args) == 3:
selector = args[2]
if selector not in self._css:
self._css[selector] = {}
# Only update the property if it has changed.
key = args[0]
value = args[1]
if not (key in self._css[selector] and value == self._css[selector][key]):
self._css[selector][key] = value
self.send_state('_css') # Send new state to client.
my_css = self._css[selector]
if value is None:
css_dict = dict_or_key
else:
raise Exception('set_css only accepts 1-3 arguments')
css_dict = {dict_or_key: value}
for (key, value) in css_dict.items():
if not (key in my_css and value == my_css[key]):
my_css[key] = value
self.send_state('_css')
def add_class(self, class_names, selector=""):
"""Add class[es] to a DOM element.

View File

@ -30,17 +30,14 @@ class ButtonWidget(DOMWidget):
def __init__(self, **kwargs):
"""Constructor"""
super(ButtonWidget, self).__init__(**kwargs)
self._click_handlers = CallbackDispatcher(acceptable_nargs=[0, 1])
self._click_handlers = CallbackDispatcher()
self.on_msg(self._handle_button_msg)
def on_click(self, callback, remove=False):
"""Register a callback to execute when the button is clicked.
"""Register a callback to execute when the button is clicked.
The callback can either accept no parameters or one sender parameter:
- callback()
- callback(sender)
If the callback has a sender parameter, the ButtonWidget instance that
called the callback will be passed into the method as the sender.
The callback will be called with one argument,
the clicked button widget instance.
Parameters
----------
@ -48,13 +45,12 @@ class ButtonWidget(DOMWidget):
Set to true to remove the callback from the list of callbacks."""
self._click_handlers.register_callback(callback, remove=remove)
def _handle_button_msg(self, content):
def _handle_button_msg(self, _, content):
"""Handle a msg from the front-end.
Parameters
----------
content: dict
Content of the msg."""
if 'event' in content and content['event'] == 'click':
self._click_handlers()
if content.get('event', '') == 'click':
self._click_handlers(self)

View File

@ -26,7 +26,7 @@ class _StringWidget(DOMWidget):
class HTMLWidget(_StringWidget):
_view_name = Unicode('HTMLView', sync=True)
_view_name = Unicode('HTMLView', sync=True)
class LatexWidget(_StringWidget):
@ -45,18 +45,17 @@ class TextBoxWidget(_StringWidget):
def __init__(self, **kwargs):
super(TextBoxWidget, self).__init__(**kwargs)
self._submission_callbacks = CallbackDispatcher(acceptable_nargs=[0, 1])
self._submission_callbacks = CallbackDispatcher()
self.on_msg(self._handle_string_msg)
def _handle_string_msg(self, content):
def _handle_string_msg(self, _, content):
"""Handle a msg from the front-end.
Parameters
----------
content: dict
Content of the msg."""
if 'event' in content and content['event'] == 'submit':
self._submission_callbacks()
if content.get('event', '') == 'submit':
self._submission_callbacks(self)
def on_submit(self, callback, remove=False):
@ -65,11 +64,9 @@ class TextBoxWidget(_StringWidget):
Triggered when the user clicks enter.
Parameters
callback: Method handle
Function to be called when the text has been submitted. Function
can have two possible signatures:
callback()
callback(sender)
----------
callback: callable
Will be called with exactly one argument: the Widget instance
remove: bool (optional)
Whether or not to unregister the callback"""
Whether to unregister the callback"""
self._submission_callbacks.register_callback(callback, remove=remove)

View File

@ -46,7 +46,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"The IPython notebook comes preloaded with basic widgets that represent common data types. These widgets are\n",
"IPython comes with basic widgets that represent common interactive controls. These widgets are\n",
"\n",
"- CheckBoxWidget\n",
"- ToggleButtonWidget\n",
@ -67,10 +67,10 @@
"- LatexWidget\n",
"- TextAreaWidget\n",
"- TextBoxWidget\n",
"- ButtonWidget\n",
"\n",
"A few special widgets are also included, that can be used to capture events and change how other widgets are displayed. These widgets are\n",
"\n",
"- ButtonWidget\n",
"- ContainerWidget\n",
"- PopupWidget\n",
"- AccordionWidget\n",
@ -128,7 +128,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"The basic widgets can all be constructed without arguments. The following creates a *FloatSliderWidget* without displaying it"
"The basic widgets all have sensible default values. Create a *FloatSliderWidget* without displaying it:"
]
},
{
@ -184,7 +184,7 @@
"source": [
"It's important to realize that widgets are not the same as output, even though they are displayed with `display`. Widgets are drawn in a special widget area. That area is marked with a close button which allows you to collapse the widgets. Widgets cannot be interleaved with output. Doing so would break the ability to make simple animations using `clear_output`.\n",
"\n",
"Widgets are manipulated via special instance properties (traitlets). The names of these instance properties are listed in the widget's `keys` property (as seen below). A few of these properties are common to most, if not all, widgets. The common properties are `value`, `description`, `visible`, and `disabled`. `_css` and `_view_name` are internal properties that exist in all widgets and should not be modified."
"Widgets are manipulated via special instance attributes (traitlets). The names of these traitlets are listed in the widget's `keys` attribute (as seen below). A few of these attributes are common to most widgets. The basic attributes are `value`, `description`, `visible`, and `disabled`. `_css` and `_view_name` are private attributes that exist in all widgets and should not be modified."
]
},
{
@ -202,15 +202,15 @@
"prompt_number": 6,
"text": [
"['_view_name',\n",
" 'description',\n",
" 'min',\n",
" 'orientation',\n",
" 'min',\n",
" 'max',\n",
" '_css',\n",
" 'value',\n",
" 'disabled',\n",
" 'visible',\n",
" 'step']"
" 'step',\n",
" 'description']"
]
}
],
@ -220,7 +220,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Changing a widget's property value will automatically update that widget everywhere it is displayed in the notebook. Here the value of `mywidget` is set. The slider shown above (after inputs 4 and 5) updates automatically to the new value. In reverse, changing the value of the displayed widget will update the property's value."
"Changing a widget's attribute will automatically update that widget everywhere it is displayed in the notebook. Here, the `value` attribute of `mywidget` is set. The slider shown above updates automatically with the new value. Syncing also works in the other direction - changing the value of the displayed widget will update the property's value."
]
},
{
@ -255,7 +255,7 @@
"output_type": "pyout",
"prompt_number": 8,
"text": [
"0.0"
"25.0"
]
}
],
@ -265,7 +265,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Widget property values can also be set with kwargs during the construction of the widget (as seen below)."
"Widget values can also be set with kwargs during the construction of the widget (as seen below)."
]
},
{

View File

@ -46,7 +46,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"As mentioned in Part 1, the widget properties are IPython traitlets. Traitlets are eventful. To handle property value changes, the `on_trait_change` method of the widget can be used to register an event handling callback. The doc string for `on_trait_change` can be seen below. Both the `name` and `remove` properties are optional."
"As mentioned in Part 1, the widget attributes are IPython traitlets. Traitlets are eventful. To handle changes, the `on_trait_change` method of the widget can be used to register a callback. The docstring for `on_trait_change` can be seen below. Both the `name` and `remove` properties are optional."
]
},
{
@ -109,13 +109,13 @@
"cell_type": "code",
"collapsed": false,
"input": [
"intrange = widgets.IntSliderWidget()\n",
"display(intrange)\n",
"int_range = widgets.IntSliderWidget()\n",
"display(int_range)\n",
"\n",
"def on_value_change(name, value):\n",
" print(value)\n",
"\n",
"intrange.on_trait_change(on_value_change, 'value')"
"int_range.on_trait_change(on_value_change, 'value')"
],
"language": "python",
"metadata": {},
@ -124,21 +124,21 @@
"output_type": "stream",
"stream": "stdout",
"text": [
"34\n"
"1\n"
]
},
{
"output_type": "stream",
"stream": "stdout",
"text": [
"74\n"
"2\n"
]
},
{
"output_type": "stream",
"stream": "stdout",
"text": [
"98\n"
"3\n"
]
}
],
@ -157,14 +157,14 @@
"level": 2,
"metadata": {},
"source": [
"Button On Click Event"
"Button Click Event"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The `ButtonWidget` is a special widget, like the `ContainerWidget` and `TabWidget`, that isn't used to represent a data type. Instead the button widget is used to handle mouse clicks. The `on_click` method of the `ButtonWidget` can be used to register a click even handler. The doc string of the `on_click` can be seen below."
"The `ButtonWidget` is a special widget, like the `ContainerWidget` and `TabWidget`, that isn't used to represent a data type. Instead the button widget is used to handle mouse clicks. The `on_click` method of the `ButtonWidget` can be used to register function to be called when the button is clicked. The docstring of the `on_click` can be seen below."
]
},
{
@ -180,13 +180,10 @@
"output_type": "stream",
"stream": "stdout",
"text": [
"Register a callback to execute when the button is clicked. \n",
"Register a callback to execute when the button is clicked.\n",
"\n",
" The callback can either accept no parameters or one sender parameter:\n",
" - callback()\n",
" - callback(sender)\n",
" If the callback has a sender parameter, the ButtonWidget instance that\n",
" called the callback will be passed into the method as the sender.\n",
" The callback will be called with one argument,\n",
" the clicked button widget instance.\n",
"\n",
" Parameters\n",
" ----------\n",
@ -211,7 +208,7 @@
"button = widgets.ButtonWidget(description=\"Click Me!\")\n",
"display(button)\n",
"\n",
"def on_button_clicked(sender):\n",
"def on_button_clicked(b):\n",
" print(\"Button clicked.\")\n",
"\n",
"button.on_click(on_button_clicked)"
@ -226,13 +223,6 @@
"Button clicked.\n"
]
},
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Button clicked.\n"
]
},
{
"output_type": "stream",
"stream": "stdout",
@ -254,17 +244,17 @@
"cell_type": "code",
"collapsed": false,
"input": [
"def show_button(sender):\n",
"def new_button(clicked):\n",
" button = widgets.ButtonWidget()\n",
" button.clicks = 0\n",
" sender.clicks += 1\n",
" button.description = \"%d\" % sender.clicks\n",
" clicked.clicks += 1\n",
" button.description = \"%d\" % clicked.clicks\n",
" display(button)\n",
" button.on_click(show_button)\n",
" button.on_click(new_button)\n",
"button = widgets.ButtonWidget(description = \"Start\")\n",
"button.clicks = 0\n",
"display(button)\n",
"button.on_click(show_button)\n",
"button.on_click(new_button)\n",
" "
],
"language": "python",

View File

@ -44,7 +44,11 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"When trying to design an attractive widget GUI, styling becomes important. Most Widgets views are DOM (document object model) elements that can be controlled with CSS. There are two helper methods defined on widget that allow the manipulation of the widget's CSS. The first is the `set_css` method, whos doc string is displayed below. This method allows one or more CSS attributes to be set at once. "
"When trying to design an attractive widget GUI, styling becomes important.\n",
"Most widget views are DOM (document object model) elements that can be controlled with CSS.\n",
"There are two helper methods that allow the manipulation of the widget's CSS.\n",
"The first is the `Widget.set_css` method.\n",
"This method allows one or more CSS attributes to be set at once. "
]
},
{
@ -72,9 +76,9 @@
" CSS key/value pairs to apply\n",
" key: unicode\n",
" CSS key\n",
" value\n",
" value:\n",
" CSS value\n",
" selector: unicode (optional)\n",
" selector: unicode (optional, kwarg only)\n",
" JQuery selector to use to apply the CSS key/value. If no selector \n",
" is provided, an empty selector is used. An empty selector makes the \n",
" front-end try to apply the css to a default element. The default\n",
@ -91,7 +95,8 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"The second is `get_css` which allows CSS attributes that have been set to be read. Note that this method will only read CSS attributes that have been set using the `set_css` method. `get_css`'s doc string is displayed below."
"The second is `get_css` which allows CSS attributesto be read.\n",
"Note that this method will only read CSS attributes that have been set using the `set_css` method."
]
},
{
@ -158,14 +163,17 @@
"level": 1,
"metadata": {},
"source": [
"DOM Classes"
"CSS Classes"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In some cases it's necessary to apply DOM classes to your widgets. DOM classes allow DOM elements to be indentified by Javascript and CSS. The notebook defines its own set of classes to stylize its elements. The `add_class` widget method allows you to add DOM classes to your widget's definition. The `add_class` method's doc string can be seen below."
"In some cases, it is necessary to apply CSS classes to your widgets.\n",
"CSS classes allow DOM elements to be indentified in Javascript and CSS.\n",
"The notebook defines its own set of classes to stylize its elements.\n",
"The `add_class` widget method allows you to add CSS classes to your widget."
]
},
{
@ -200,7 +208,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Since `add_class` if a DOM operation, **it will only affect widgets that have already been displayed**. `add_class` must be called after the widget has been displayed. Extending the example above, the corners of the container can be rounded by adding the `corner-all` notebook class to the container (as seen below). "
"Since `add_class` is a DOM operation, **it will only affect widgets that have already been displayed**.\n",
"`add_class` must be called after the widget has been displayed.\n",
"Extending the example above, the corners of the container can be rounded by adding the `corner-all` CSS class to the container."
]
},
{
@ -227,7 +237,8 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"The IPython notebook uses bootstrap for styling. The example above can be simplified by using a bootstrap class (as seen below). Bootstrap documentation can be found at http://getbootstrap.com/\u200e ."
"The IPython notebook uses [bootstrap](http://getbootstrap.com/\u200e) for styling.\n",
"The example above can be simplified by using a bootstrap class:"
]
},
{
@ -279,7 +290,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"It's also useful to be able to remove DOM classes from widgets. The `remove_class` widget method allows you to remove classes from widgets that have been displayed. Like `add_class`, it must be called after the widget has been displayed. The doc string of `remove_class` can be seen below."
"It is also useful to be able to remove CSS classes from widgets.\n",
"The `remove_class` method allows you to remove classes from widgets that have been displayed.\n",
"Like `add_class`, it must be called after the widget has been displayed."
]
},
{

View File

@ -19,7 +19,7 @@
"source": [
"[< Back to Part 5](Part 5 - Alignment.ipynb) or [Index](index.ipynb)\n",
"\n",
"Before reading, the author recommends the reader to review\n",
"Before reading, make sure to review\n",
"\n",
"- [MVC prgramming](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller)\n",
"- [Backbone.js](https://www.codeschool.com/courses/anatomy-of-backbonejs)\n",
@ -33,9 +33,9 @@
"input": [
"from __future__ import print_function # For py 2.7 compat\n",
"\n",
"from IPython.html import widgets # Widget definitions.\n",
"from IPython.display import display # Used to display widgets in the notebook.\n",
"from IPython.utils.traitlets import Unicode # Used to declare properties of our widget."
"from IPython.html import widgets # Widget definitions\n",
"from IPython.display import display # Used to display widgets in the notebook\n",
"from IPython.utils.traitlets import Unicode # Used to declare attributes of our widget"
],
"language": "python",
"metadata": {},
@ -54,7 +54,10 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"This notebook implements a custom date picker widget. The purpose of this notebook is to demonstrate the widget creation process. To create a custom widget, custom Python and JavaScript is required."
"This notebook implements a custom date picker widget,\n",
"in order to demonstrate the widget creation process.\n",
"\n",
"To create a custom widget, both Python and JavaScript code is required."
]
},
{
@ -77,7 +80,10 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"When starting a project like this, it is often easiest to make an overly simplified base to verify that the underlying framework is working as expected. To start we will create an empty widget and make sure that it can be rendered. The first step is to create the widget in Python."
"When starting a project like this, it is often easiest to make a simple base implementation,\n",
"to verify that the underlying framework is working as expected.\n",
"To start, we will create an empty widget and make sure that it can be rendered.\n",
"The first step is to define the widget in Python."
]
},
{
@ -96,7 +102,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Our widget inherits from `widgets.DOMWidget` since it is intended that it will be displayed in the notebook directly. The `_view_name` trait is specially named, the widget framework will read the `_view_name` trait to determine what Backbone view the widget is associated with. **Using `sync=True` is very important** because it tells the widget framework that that specific traitlet should be synced between the front- and back-ends."
"Our widget inherits from `widgets.DOMWidget` since it is intended that it will be displayed in the notebook directly.\n",
"The `_view_name` trait is special; the widget framework will read the `_view_name` trait to determine what Backbone view the widget is associated with.\n",
"**Using `sync=True` is very important** because it tells the widget framework that that specific traitlet should be synced between the front- and back-ends."
]
},
{
@ -111,7 +119,10 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"In the IPython notebook [require.js](http://requirejs.org/) is used to load JavaScript dependencies. All IPython widget code depends on `notebook/js/widgets/widget.js`. In it the base widget model and base view are defined. We need to use require.js to include this file:"
"In the IPython notebook [require.js](http://requirejs.org/) is used to load JavaScript dependencies.\n",
"All IPython widget code depends on `notebook/js/widgets/widget.js`,\n",
"where the base widget model and base view are defined.\n",
"We use require.js to load this file:"
]
},
{
@ -137,7 +148,7 @@
"metadata": {},
"output_type": "display_data",
"text": [
"<IPython.core.display.Javascript at 0x2a2e0d0>"
"<IPython.core.display.Javascript at 0x109491690>"
]
}
],
@ -147,7 +158,12 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Now we need to define a view that can be used to represent the model. To do this, the `IPython.DOMWidgetView` is extended. A render function must be defined. The render function is used to render a widget view instance to the DOM. For now the render function renders a div that contains the text *Hello World!* Lastly, the view needs to be registered with the widget manager.\n",
"Now we need to define a view that can be used to represent the model.\n",
"To do this, the `IPython.DOMWidgetView` is extended.\n",
"**A render function must be defined**.\n",
"The render function is used to render a widget view instance to the DOM.\n",
"For now, the render function renders a div that contains the text *Hello World!*\n",
"Lastly, the view needs to be registered with the widget manager.\n",
"\n",
"**Final JavaScript code below:**"
]
@ -189,7 +205,7 @@
"metadata": {},
"output_type": "display_data",
"text": [
"<IPython.core.display.Javascript at 0x2a2e3d0>"
"<IPython.core.display.Javascript at 0x1094917d0>"
]
}
],
@ -207,7 +223,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"To test, create the widget the same way that the other widgets are created."
"To test what we have so far, create the widget, just like you would the builtin widgets:"
]
},
{
@ -241,7 +257,11 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"In the last section we created a simple widget that displayed *Hello World!* To make an actual date widget, we need to add a property that will be synced between the Python model and the JavaScript model. The new property must be a traitlet property so the widget machinery can automatically handle it. The property needs to be constructed with a `sync=True` keyword argument so the widget machinery knows to syncronize it with the front-end. Adding this to the code from the last section:"
"In the last section we created a simple widget that displayed *Hello World!*\n",
"To make an actual date widget, we need to add a property that will be synced between the Python model and the JavaScript model.\n",
"The new attribute must be a traitlet, so the widget machinery can handle it.\n",
"The traitlet must be constructed with a `sync=True` keyword argument, to tell the widget machinery knows to synchronize it with the front-end.\n",
"Adding this to the code from the last section:"
]
},
{
@ -269,7 +289,10 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"In the JavaScript there is no need to define counterparts to the traitlets. When the JavaScript model is created for the first time, it copies all of the traitlet `sync=True` attributes from the Python model. We need to replace *Hello World!* with an actual HTML date picker widget."
"In the JavaScript, there is no need to define counterparts to the traitlets.\n",
"When the JavaScript model is created for the first time,\n",
"it copies all of the traitlet `sync=True` attributes from the Python model.\n",
"We need to replace *Hello World!* with an actual HTML date picker widget."
]
},
{
@ -321,7 +344,7 @@
"metadata": {},
"output_type": "display_data",
"text": [
"<IPython.core.display.Javascript at 0x2a2e6d0>"
"<IPython.core.display.Javascript at 0x109491750>"
]
}
],
@ -397,7 +420,7 @@
"metadata": {},
"output_type": "display_data",
"text": [
"<IPython.core.display.Javascript at 0x2a2e090>"
"<IPython.core.display.Javascript at 0x109491750>"
]
}
],
@ -407,7 +430,11 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"To get the changed value from the front-end to publish itself to the back-end, we need to listen to the change event triggered by the HTM date control and set the value in the model. After the date change event fires and the new value is set in the model, it's very important that we call `this.touch()` to let the widget machinery know which view changed the model. This is important because the widget machinery needs to know which cell to route the message callbacks to.\n",
"To get the changed value from the frontend to publish itself to the backend,\n",
"we need to listen to the change event triggered by the HTM date control and set the value in the model.\n",
"After the date change event fires and the new value is set in the model,\n",
"it is very important that we call `this.touch()` to let the widget machinery know which view changed the model.\n",
"This is important because the widget machinery needs to know which cell to route the message callbacks to.\n",
"\n",
"**Final JavaScript code below:**"
]
@ -495,7 +522,7 @@
"metadata": {},
"output_type": "display_data",
"text": [
"<IPython.core.display.Javascript at 0x2a2e750>"
"<IPython.core.display.Javascript at 0x109491b10>"
]
}
],
@ -567,7 +594,7 @@
"output_type": "pyout",
"prompt_number": 12,
"text": [
"u'2014-01-01'"
"u''"
]
}
],
@ -584,7 +611,7 @@
"cell_type": "code",
"collapsed": false,
"input": [
"my_widget.value = \"1998-12-01\" # December 1st, 1999"
"my_widget.value = \"1998-12-01\" # December 1st, 1998"
],
"language": "python",
"metadata": {},
@ -622,7 +649,10 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"In the last section we created a fully working date picker widget. Now we will add custom validation and support for labels. Currently only the ISO date format \"YYYY-MM-DD\" is supported. We will add support for all of the date formats recognized by the 3rd party Python dateutil library."
"In the last section we created a fully working date picker widget.\n",
"Now we will add custom validation and support for labels.\n",
"So far, only the ISO date format \"YYYY-MM-DD\" is supported.\n",
"Now, we will add support for all of the date formats recognized by the Python dateutil library."
]
},
{
@ -637,7 +667,8 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"The standard property name used for widget labels is `description`. In the code block below, `description` has been added to the Python widget."
"The standard property name used for widget labels is `description`.\n",
"In the code block below, `description` has been added to the Python widget."
]
},
{
@ -658,7 +689,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"The traitlet machinery searches the class that the trait is defined in for methods with \"`_changed`\" suffixed onto their names. Any method with the format \"`X_changed`\" will be called when \"`X`\" is modified. We can take advantage of this to perform validation and parsing of different date string formats. Below a method that listens to value has been added to the DateWidget."
"The traitlet machinery searches the class that the trait is defined in for methods with \"`_changed`\" suffixed onto their names. Any method with the format \"`_X_changed`\" will be called when \"`X`\" is modified.\n",
"We can take advantage of this to perform validation and parsing of different date string formats.\n",
"Below, a method that listens to value has been added to the DateWidget."
]
},
{
@ -684,7 +717,8 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Now the function that parses the date string and only sets it in the correct format can be added."
"Now the function parses the date string,\n",
"and only sets the value in the correct format."
]
},
{
@ -720,7 +754,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Finally, a `CallbackDispatcher` is added so the user can perform custom validation. If any one of the callbacks registered with the dispatcher returns False, the new date time is not set.\n",
"Finally, a `CallbackDispatcher` is added so the user can perform custom validation.\n",
"If any one of the callbacks registered with the dispatcher returns False,\n",
"the new date is not set.\n",
"\n",
"**Final Python code below:**"
]
@ -737,10 +773,7 @@
" def __init__(self, **kwargs):\n",
" super(DateWidget, self).__init__(**kwargs)\n",
" \n",
" # Specify the number of positional arguments supported. For \n",
" # validation we only are worried about one parameter, the\n",
" # new value that should be validated.\n",
" self.validation = widgets.CallbackDispatcher(acceptable_nargs=[1])\n",
" self.validate = widgets.CallbackDispatcher()\n",
" \n",
" # This function automatically gets called by the traitlet machinery when\n",
" # value is modified because of this function's name.\n",
@ -755,8 +788,8 @@
" \n",
" # Set the parsed date string if the current date string is different.\n",
" if old_value != new_value:\n",
" validation = self.validation(parsed_date)\n",
" if validation is None or validation == True:\n",
" valid = self.validate(parsed_date)\n",
" if valid in (None, True):\n",
" self.value = parsed_date_string\n",
" else:\n",
" self.value = old_value\n",
@ -781,7 +814,12 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Using the Javascript code from the last section, we add a label to the date time object. The label is a div with the `widget-hlabel` class applied to it. The `widget-hlabel` is a class provided by the widget framework that applies special styling to a div to make it look like the rest of the horizontal labels used with the built in widgets. Similar to the `widget-hlabel` class is the `widget-hbox-single` class. The `widget-hbox-single` class applies special styling to widget containers that store a single line horizontal widget. \n",
"Using the Javascript code from the last section,\n",
"we add a label to the date time object.\n",
"The label is a div with the `widget-hlabel` class applied to it.\n",
"`widget-hlabel` is a class provided by the widget framework that applies special styling to a div to make it look like the rest of the horizontal labels used with the built-in widgets.\n",
"Similar to the `widget-hlabel` class is the `widget-hbox-single` class.\n",
"The `widget-hbox-single` class applies special styling to widget containers that store a single line horizontal widget.\n",
"\n",
"We hide the label if the description value is blank."
]
@ -792,7 +830,6 @@
"input": [
"%%javascript\n",
"\n",
"\n",
"require([\"notebook/js/widgets/widget\"], function(WidgetManager){\n",
" \n",
" // Define the DatePickerView\n",
@ -848,7 +885,6 @@
"outputs": [
{
"javascript": [
"\n",
"\n",
"require([\"notebook/js/widgets/widget\"], function(WidgetManager){\n",
" \n",
@ -903,7 +939,7 @@
"metadata": {},
"output_type": "display_data",
"text": [
"<IPython.core.display.Javascript at 0x2a5a6d0>"
"<IPython.core.display.Javascript at 0x1094eef90>"
]
}
],
@ -955,9 +991,9 @@
"my_widget = DateWidget()\n",
"display(my_widget)\n",
"\n",
"def validate_date(date):\n",
"def require_2014(date):\n",
" return not date is None and date.year == 2014\n",
"my_widget.validation.register_callback(validate_date)"
"my_widget.validate.register_callback(require_2014)"
],
"language": "python",
"metadata": {},

View File

@ -20,7 +20,7 @@
"level": 2,
"metadata": {},
"source": [
"A short example implementation."
"A short example implementation"
]
},
{
@ -30,17 +30,27 @@
"This notebook demonstrates how one can use the widgets already built-in to IPython to create a working variable inspector much like the ones seen in popular commercial scientific computing environments."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"from IPython.html import widgets # Loads the Widget framework.\n",
"from IPython.core.magics.namespace import NamespaceMagics # Used to query namespace.\n",
"\n",
"# For this example, hide these names, just to avoid polluting the namespace further\n",
"get_ipython().user_ns_hidden['widgets'] = widgets\n",
"get_ipython().user_ns_hidden['NamespaceMagics'] = NamespaceMagics"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 1
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"class VariableInspectorWindow(object):\n",
" \n",
" # For this example file, the import sit inside the class, just to avoid poluting \n",
" # the namespace further.\n",
" from IPython.html import widgets # Loads the Widget framework.\n",
" from IPython.core.magics.namespace import NamespaceMagics # Used to query namespace.\n",
" \n",
" instance = None\n",
" \n",
" def __init__(self, ipython):\n",
@ -53,21 +63,21 @@
" \n",
" VariableInspectorWindow.instance = self\n",
" self.closed = False\n",
" self.namespace = self.NamespaceMagics()\n",
" self.namespace = NamespaceMagics()\n",
" self.namespace.shell = ipython.kernel.shell\n",
" \n",
" self._popout = self.widgets.PopupWidget()\n",
" self._popout = widgets.PopupWidget()\n",
" self._popout.description = \"Variable Inspector\"\n",
" self._popout.button_text = self._popout.description\n",
"\n",
" self._modal_body = self.widgets.ContainerWidget()\n",
" self._modal_body = widgets.ContainerWidget()\n",
" self._modal_body.set_css('overflow-y', 'scroll')\n",
"\n",
" self._modal_body_label = self.widgets.HTMLWidget(value = 'Not hooked')\n",
" self._modal_body_label = widgets.HTMLWidget(value = 'Not hooked')\n",
" self._modal_body.children = [self._modal_body_label]\n",
"\n",
" self._modal_footer = self.widgets.ContainerWidget()\n",
" self._var_filter = self.widgets.ToggleButtonsWidget(description=\"Method:\", values=['List', 'Details'], value='List')\n",
" self._modal_footer = widgets.ContainerWidget()\n",
" self._var_filter = widgets.ToggleButtonsWidget(description=\"Method:\", values=['List', 'Details'], value='List')\n",
" self._modal_footer.children = [self._var_filter]\n",
"\n",
" self._popout.children = [\n",
@ -109,7 +119,7 @@
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 17
"prompt_number": 2
},
{
"cell_type": "code",
@ -121,7 +131,7 @@
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 18
"prompt_number": 3
},
{
"cell_type": "heading",
@ -140,7 +150,7 @@
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 11
"prompt_number": 4
},
{
"cell_type": "code",
@ -151,7 +161,7 @@
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 12
"prompt_number": 5
},
{
"cell_type": "code",
@ -162,7 +172,7 @@
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 13
"prompt_number": 6
},
{
"cell_type": "code",
@ -173,7 +183,7 @@
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 14
"prompt_number": 7
},
{
"cell_type": "code",
@ -184,384 +194,7 @@
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 15
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"?"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 16
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"dir()"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 15,
"text": [
"['In',\n",
" 'Out',\n",
" 'VariableInspectorWindow',\n",
" '_',\n",
" '_10',\n",
" '_14',\n",
" '__',\n",
" '___',\n",
" '__builtin__',\n",
" '__builtins__',\n",
" '__doc__',\n",
" '__name__',\n",
" '__package__',\n",
" '_dh',\n",
" '_i',\n",
" '_i1',\n",
" '_i10',\n",
" '_i11',\n",
" '_i12',\n",
" '_i13',\n",
" '_i14',\n",
" '_i15',\n",
" '_i2',\n",
" '_i3',\n",
" '_i4',\n",
" '_i5',\n",
" '_i6',\n",
" '_i7',\n",
" '_i8',\n",
" '_i9',\n",
" '_ih',\n",
" '_ii',\n",
" '_iii',\n",
" '_oh',\n",
" '_sh',\n",
" 'exit',\n",
" 'get_ipython',\n",
" 'quit',\n",
" 'widgets']"
]
}
],
"prompt_number": 15
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"dir(get_ipython().kernel.shell)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 4,
"text": [
"['Completer',\n",
" 'CustomTB',\n",
" 'InteractiveTB',\n",
" 'SyntaxTB',\n",
" '__class__',\n",
" '__delattr__',\n",
" '__dict__',\n",
" '__doc__',\n",
" '__format__',\n",
" '__getattribute__',\n",
" '__hash__',\n",
" '__init__',\n",
" '__module__',\n",
" '__new__',\n",
" '__reduce__',\n",
" '__reduce_ex__',\n",
" '__repr__',\n",
" '__setattr__',\n",
" '__sizeof__',\n",
" '__str__',\n",
" '__subclasshook__',\n",
" '__weakref__',\n",
" '_add_notifiers',\n",
" '_call_pdb',\n",
" '_config_changed',\n",
" '_exit_now_changed',\n",
" '_exiter_default',\n",
" '_find_my_config',\n",
" '_format_user_obj',\n",
" '_get_call_pdb',\n",
" '_get_exc_info',\n",
" '_indent_current_str',\n",
" '_inspect',\n",
" '_instance',\n",
" '_ipython_dir_changed',\n",
" '_last_input_line',\n",
" '_load_config',\n",
" '_main_mod_cache',\n",
" '_notify_trait',\n",
" '_object_find',\n",
" '_ofind',\n",
" '_ofind_property',\n",
" '_orig_sys_module_state',\n",
" '_orig_sys_modules_main_mod',\n",
" '_orig_sys_modules_main_name',\n",
" '_post_execute',\n",
" '_prompt_in1_changed',\n",
" '_prompt_in2_changed',\n",
" '_prompt_out_changed',\n",
" '_prompt_pad_left_changed',\n",
" '_prompt_trait_changed',\n",
" '_remove_notifiers',\n",
" '_reply_content',\n",
" '_run_cached_cell_magic',\n",
" '_set_call_pdb',\n",
" '_showtraceback',\n",
" '_trait_dyn_inits',\n",
" '_trait_notifiers',\n",
" '_trait_values',\n",
" '_user_obj_error',\n",
" '_walk_mro',\n",
" 'alias_manager',\n",
" 'all_ns_refs',\n",
" 'ask_exit',\n",
" 'ask_yes_no',\n",
" 'ast_node_interactivity',\n",
" 'ast_transformers',\n",
" 'atexit_operations',\n",
" 'auto_rewrite_input',\n",
" 'autocall',\n",
" 'autoindent',\n",
" 'automagic',\n",
" 'builtin_trap',\n",
" 'cache_size',\n",
" 'call_pdb',\n",
" 'class_config_section',\n",
" 'class_get_help',\n",
" 'class_get_trait_help',\n",
" 'class_print_help',\n",
" 'class_trait_names',\n",
" 'class_traits',\n",
" 'cleanup',\n",
" 'clear_instance',\n",
" 'clear_main_mod_cache',\n",
" 'color_info',\n",
" 'colors',\n",
" 'colors_force',\n",
" 'comm_manager',\n",
" 'compile',\n",
" 'complete',\n",
" 'config',\n",
" 'configurables',\n",
" 'custom_exceptions',\n",
" 'data_pub',\n",
" 'data_pub_class',\n",
" 'db',\n",
" 'debug',\n",
" 'debugger',\n",
" 'deep_reload',\n",
" 'default_user_namespaces',\n",
" 'define_macro',\n",
" 'define_magic',\n",
" 'del_var',\n",
" 'dir_stack',\n",
" 'disable_failing_post_execute',\n",
" 'display_formatter',\n",
" 'display_pub',\n",
" 'display_pub_class',\n",
" 'display_trap',\n",
" 'displayhook',\n",
" 'displayhook_class',\n",
" 'drop_by_id',\n",
" 'enable_gui',\n",
" 'enable_matplotlib',\n",
" 'enable_pylab',\n",
" 'ev',\n",
" 'ex',\n",
" 'excepthook',\n",
" 'execution_count',\n",
" 'exit_now',\n",
" 'exiter',\n",
" 'extension_manager',\n",
" 'extract_input_lines',\n",
" 'filename',\n",
" 'find_cell_magic',\n",
" 'find_line_magic',\n",
" 'find_magic',\n",
" 'find_user_code',\n",
" 'get_ipython',\n",
" 'get_parent',\n",
" 'getoutput',\n",
" 'has_readline',\n",
" 'history_length',\n",
" 'history_manager',\n",
" 'home_dir',\n",
" 'hooks',\n",
" 'indent_current_nsp',\n",
" 'init_alias',\n",
" 'init_builtins',\n",
" 'init_comms',\n",
" 'init_completer',\n",
" 'init_create_namespaces',\n",
" 'init_data_pub',\n",
" 'init_display_formatter',\n",
" 'init_display_pub',\n",
" 'init_displayhook',\n",
" 'init_encoding',\n",
" 'init_environment',\n",
" 'init_extension_manager',\n",
" 'init_history',\n",
" 'init_hooks',\n",
" 'init_inspector',\n",
" 'init_instance_attrs',\n",
" 'init_io',\n",
" 'init_ipython_dir',\n",
" 'init_latextool',\n",
" 'init_logger',\n",
" 'init_logstart',\n",
" 'init_magics',\n",
" 'init_payload',\n",
" 'init_pdb',\n",
" 'init_prefilter',\n",
" 'init_profile_dir',\n",
" 'init_prompts',\n",
" 'init_pushd_popd_magic',\n",
" 'init_readline',\n",
" 'init_syntax_highlighting',\n",
" 'init_sys_modules',\n",
" 'init_traceback_handlers',\n",
" 'init_user_ns',\n",
" 'init_virtualenv',\n",
" 'initialized',\n",
" 'input_splitter',\n",
" 'input_transformer_manager',\n",
" 'inspector',\n",
" 'instance',\n",
" 'ipython_dir',\n",
" 'keepkernel_on_exit',\n",
" 'kernel',\n",
" 'logappend',\n",
" 'logfile',\n",
" 'logger',\n",
" 'logstart',\n",
" 'magic',\n",
" 'magics_manager',\n",
" 'meta',\n",
" 'mktempfile',\n",
" 'more',\n",
" 'multiline_history',\n",
" 'new_main_mod',\n",
" 'ns_table',\n",
" 'object_info_string_level',\n",
" 'object_inspect',\n",
" 'on_trait_change',\n",
" 'parent',\n",
" 'parent_header',\n",
" 'payload_manager',\n",
" 'pdb',\n",
" 'pre_readline',\n",
" 'prefilter',\n",
" 'prefilter_manager',\n",
" 'prepare_user_module',\n",
" 'profile',\n",
" 'profile_dir',\n",
" 'prompt_in1',\n",
" 'prompt_in2',\n",
" 'prompt_manager',\n",
" 'prompt_out',\n",
" 'prompts_pad_left',\n",
" 'push',\n",
" 'pycolorize',\n",
" 'pylab_gui_select',\n",
" 'quiet',\n",
" 'raw_input_original',\n",
" 'readline',\n",
" 'readline_delims',\n",
" 'readline_no_record',\n",
" 'readline_parse_and_bind',\n",
" 'readline_remove_delims',\n",
" 'readline_use',\n",
" 'refill_readline_hist',\n",
" 'register_magic_function',\n",
" 'register_magics',\n",
" 'register_post_execute',\n",
" 'reset',\n",
" 'reset_selective',\n",
" 'restore_sys_module_state',\n",
" 'rl_do_indent',\n",
" 'rl_next_input',\n",
" 'run_ast_nodes',\n",
" 'run_cell',\n",
" 'run_cell_magic',\n",
" 'run_code',\n",
" 'run_line_magic',\n",
" 'runcode',\n",
" 'safe_execfile',\n",
" 'safe_execfile_ipy',\n",
" 'safe_run_module',\n",
" 'save_sys_module_state',\n",
" 'section_names',\n",
" 'separate_in',\n",
" 'separate_out',\n",
" 'separate_out2',\n",
" 'set_autoindent',\n",
" 'set_completer_frame',\n",
" 'set_custom_completer',\n",
" 'set_custom_exc',\n",
" 'set_hook',\n",
" 'set_next_input',\n",
" 'set_parent',\n",
" 'set_readline_completer',\n",
" 'show_rewritten_input',\n",
" 'show_usage',\n",
" 'show_usage_error',\n",
" 'showindentationerror',\n",
" 'showsyntaxerror',\n",
" 'showtraceback',\n",
" 'starting_dir',\n",
" 'stdin_encoding',\n",
" 'strdispatchers',\n",
" 'sys_excepthook',\n",
" 'system',\n",
" 'system_piped',\n",
" 'system_raw',\n",
" 'tempfiles',\n",
" 'trait_metadata',\n",
" 'trait_names',\n",
" 'traits',\n",
" 'transform_ast',\n",
" 'update_config',\n",
" 'user_expressions',\n",
" 'user_global_ns',\n",
" 'user_module',\n",
" 'user_ns',\n",
" 'user_ns_hidden',\n",
" 'user_variables',\n",
" 'var_expand',\n",
" 'wildcards_case_sensitive',\n",
" 'write',\n",
" 'write_err',\n",
" 'xmode']"
]
}
],
"prompt_number": 4
},
{
"cell_type": "code",
"collapsed": false,
"input": [],
"language": "python",
"metadata": {},
"outputs": []
"prompt_number": 8
}
],
"metadata": {}