diff --git a/IPython/html/services/kernels/handlers.py b/IPython/html/services/kernels/handlers.py
index 3d4337f..b51861e 100644
--- a/IPython/html/services/kernels/handlers.py
+++ b/IPython/html/services/kernels/handlers.py
@@ -84,6 +84,9 @@ class KernelActionHandler(IPythonHandler):
class ZMQChannelHandler(AuthenticatedZMQStreamHandler):
+ def __repr__(self):
+ return "%s(%s)" % (self.__class__.__name__, getattr(self, 'kernel_id', 'uninitialized'))
+
def create_stream(self):
km = self.kernel_manager
meth = getattr(km, 'connect_%s' % self.channel)
@@ -145,6 +148,12 @@ class ZMQChannelHandler(AuthenticatedZMQStreamHandler):
self.zmq_stream.on_recv(self._on_zmq_reply)
def on_message(self, msg):
+ if self.zmq_stream is None:
+ return
+ elif self.zmq_stream.closed():
+ self.log.info("%s closed, closing websocket.", self)
+ self.close()
+ return
msg = json.loads(msg)
self.session.send(self.zmq_stream, msg)
diff --git a/IPython/html/static/base/less/flexbox.less b/IPython/html/static/base/less/flexbox.less
index 4623833..62eaad2 100644
--- a/IPython/html/static/base/less/flexbox.less
+++ b/IPython/html/static/base/less/flexbox.less
@@ -184,6 +184,30 @@ Browsers not listed, including Safari, are supported via the styling under the
justify-content: center;
}
+.hbox.baseline,
+.vbox.baseline,
+.baseline {
+ /* Old browsers */
+ -webkit-box-pack: baseline;
+ -moz-box-pack: baseline;
+ box-pack: baseline;
+
+ /* Modern browsers */
+ justify-content: baseline;
+}
+
+.hbox.stretch,
+.vbox.stretch,
+.stretch {
+ /* Old browsers */
+ -webkit-box-pack: stretch;
+ -moz-box-pack: stretch;
+ box-pack: stretch;
+
+ /* Modern browsers */
+ justify-content: stretch;
+}
+
.hbox.align-start,
.vbox.align-start,
.align-start {
@@ -219,3 +243,27 @@ Browsers not listed, including Safari, are supported via the styling under the
/* Modern browsers */
align-items: center;
}
+
+.hbox.align-baseline,
+.vbox.align-baseline,
+.align-baseline {
+ /* Old browsers */
+ -webkit-box-align: baseline;
+ -moz-box-align: baseline;
+ box-align: baseline;
+
+ /* Modern browsers */
+ align-items: baseline;
+}
+
+.hbox.align-stretch,
+.vbox.align-stretch,
+.align-stretch {
+ /* Old browsers */
+ -webkit-box-align: stretch;
+ -moz-box-align: stretch;
+ box-align: stretch;
+
+ /* Modern browsers */
+ align-items: stretch;
+}
diff --git a/IPython/html/static/notebook/js/kernelselector.js b/IPython/html/static/notebook/js/kernelselector.js
index 764db72..ce9b919 100644
--- a/IPython/html/static/notebook/js/kernelselector.js
+++ b/IPython/html/static/notebook/js/kernelselector.js
@@ -54,9 +54,19 @@ define([
return;
}
var ks = this.kernelspecs[kernel_name];
+ try {
+ this.notebook.start_session(kernel_name);
+ } catch (e) {
+ if (e.name === 'SessionAlreadyStarting') {
+ console.log("Cannot change kernel while waiting for pending session start.");
+ } else {
+ // unhandled error
+ throw e;
+ }
+ // only trigger spec_changed if change was successful
+ return;
+ }
this.events.trigger('spec_changed.Kernel', ks);
- this.notebook.session.delete();
- this.notebook.start_session(kernel_name);
};
KernelSelector.prototype.bind_events = function() {
diff --git a/IPython/html/static/notebook/js/menubar.js b/IPython/html/static/notebook/js/menubar.js
index a6f0b28..67e0d5b 100644
--- a/IPython/html/static/notebook/js/menubar.js
+++ b/IPython/html/static/notebook/js/menubar.js
@@ -157,12 +157,13 @@ define([
}
});
this.element.find('#kill_and_exit').click(function () {
- that.notebook.session.delete();
- setTimeout(function(){
+ var close_window = function () {
// allow closing of new tabs in Chromium, impossible in FF
window.open('', '_self', '');
window.close();
- }, 500);
+ };
+ // finish with close on success or failure
+ that.notebook.session.delete(close_window, close_window);
});
// Edit
this.element.find('#cut_cell').click(function () {
diff --git a/IPython/html/static/notebook/js/notebook.js b/IPython/html/static/notebook/js/notebook.js
index e22fd51..8aaf8b4 100644
--- a/IPython/html/static/notebook/js/notebook.js
+++ b/IPython/html/static/notebook/js/notebook.js
@@ -62,6 +62,7 @@ define([
this.save_widget = options.save_widget;
this.tooltip = new tooltip.Tooltip(this.events);
this.ws_url = options.ws_url;
+ this._session_starting = false;
// default_kernel_name is a temporary measure while we implement proper
// kernel selection and delayed start. Do not rely on it.
this.default_kernel_name = 'python';
@@ -1525,9 +1526,38 @@ define([
* @method start_session
*/
Notebook.prototype.start_session = function (kernel_name) {
+ var that = this;
if (kernel_name === undefined) {
kernel_name = this.default_kernel_name;
}
+ if (this._session_starting) {
+ throw new session.SessionAlreadyStarting();
+ }
+ this._session_starting = true;
+
+ if (this.session !== null) {
+ var s = this.session;
+ this.session = null;
+ // need to start the new session in a callback after delete,
+ // because javascript does not guarantee the ordering of AJAX requests (?!)
+ s.delete(function () {
+ // on successful delete, start new session
+ that._session_starting = false;
+ that.start_session(kernel_name);
+ }, function (jqXHR, status, error) {
+ // log the failed delete, but still create a new session
+ // 404 just means it was already deleted by someone else,
+ // but other errors are possible.
+ utils.log_ajax_error(jqXHR, status, error);
+ that._session_starting = false;
+ that.start_session(kernel_name);
+ }
+ );
+ return;
+ }
+
+
+
this.session = new session.Session({
base_url: this.base_url,
ws_url: this.ws_url,
@@ -1539,7 +1569,10 @@ define([
kernel_name: kernel_name,
notebook: this});
- this.session.start($.proxy(this._session_started, this));
+ this.session.start(
+ $.proxy(this._session_started, this),
+ $.proxy(this._session_start_failed, this)
+ );
};
@@ -1548,7 +1581,8 @@ define([
* comm manager to the widget manager
*
*/
- Notebook.prototype._session_started = function(){
+ Notebook.prototype._session_started = function (){
+ this._session_starting = false;
this.kernel = this.session.kernel;
var ncells = this.ncells();
for (var i=0; i')
.addClass('widget-modal-title')
.html(" ")
- .appendTo(this.$title_bar);
- this.$body = $('
')
+ .appendTo(this.$title_bar);
+ this.$box = $('')
.addClass('modal-body')
.addClass('widget-modal-body')
- .addClass('widget-container')
+ .addClass('widget-box')
.addClass('vbox')
.appendTo(this.$window);
@@ -149,7 +195,7 @@ define([
this.$window.draggable({handle: '.popover-title', snap: '#notebook, .modal', snapMode: 'both'});
this.$window.resizable();
this.$window.on('resize', function(){
- that.$body.outerHeight(that.$window.innerHeight() - that.$title_bar.outerHeight());
+ that.$box.outerHeight(that.$window.innerHeight() - that.$title_bar.outerHeight());
});
this._shown_once = false;
@@ -203,29 +249,6 @@ define([
this.$window.css('z-index', max_zindex);
},
- update_children: function(old_list, new_list) {
- // Called when the children list is modified.
- this.do_diff(old_list, new_list,
- $.proxy(this.remove_child_model, this),
- $.proxy(this.add_child_model, this));
- },
-
- remove_child_model: function(model) {
- // Called when a child is removed from children list.
- this.pop_child_view(model).remove();
- },
-
- add_child_model: function(model) {
- // Called when a child is added to children list.
- var view = this.create_child_view(model);
- this.$body.append(view.$el);
-
- // Trigger the displayed event of the child view.
- this.after_displayed(function() {
- view.trigger('displayed');
- });
- },
-
update: function(){
// Update the contents of this view
//
@@ -277,7 +300,8 @@ define([
});
return {
- 'ContainerView': ContainerView,
+ 'BoxView': BoxView,
'PopupView': PopupView,
+ 'FlexBoxView': FlexBoxView,
};
});
diff --git a/IPython/html/static/widgets/less/widgets.less b/IPython/html/static/widgets/less/widgets.less
index 28996f6..c26aa27 100644
--- a/IPython/html/static/widgets/less/widgets.less
+++ b/IPython/html/static/widgets/less/widgets.less
@@ -226,7 +226,7 @@
margin : 5px;
.start();
- .widget-container();
+ .widget-box();
}
.widget-hbox {
@@ -258,7 +258,7 @@
}
.widget-modal {
- /* ContainerWidget - ModalView */
+ /* Box - ModalView */
overflow : hidden;
position : absolute !important;
top : 0px;
@@ -267,12 +267,12 @@
}
.widget-modal-body {
- /* ContainerWidget - ModalView Body */
+ /* Box - ModalView Body */
max-height: none !important;
}
-.widget-container {
- /* ContainerWidget */
+.widget-box {
+ /* Box */
.border-box-sizing();
.align-start();
}
diff --git a/IPython/html/tests/services/kernel.js b/IPython/html/tests/services/kernel.js
index bcbda9e..4ff1eee 100644
--- a/IPython/html/tests/services/kernel.js
+++ b/IPython/html/tests/services/kernel.js
@@ -1,12 +1,12 @@
//
-// Miscellaneous javascript tests
+// Kernel tests
//
casper.notebook_test(function () {
this.evaluate(function () {
IPython.notebook.kernel.kernel_info(
function(msg){
- IPython._kernel_info_response = msg;
+ IPython._kernel_info_response = msg;
})
});
@@ -24,5 +24,41 @@ casper.notebook_test(function () {
this.test.assertTrue( kernel_info_response.msg_type === 'kernel_info_reply', 'Kernel info request return kernel_info_reply');
this.test.assertTrue( kernel_info_response.content !== undefined, 'Kernel_info_reply is not undefined');
});
-
+
+ this.thenEvaluate(function () {
+ var kernel = IPython.notebook.session.kernel;
+ IPython._channels = [
+ kernel.shell_channel,
+ kernel.iopub_channel,
+ kernel.stdin_channel
+ ];
+ kernel.kill();
+ });
+
+ this.waitFor(function () {
+ return this.evaluate(function(){
+ for (var i=0; i < IPython._channels.length; i++) {
+ var ws = IPython._channels[i];
+ if (ws.readyState !== ws.CLOSED) {
+ return false;
+ }
+ }
+ return true;
+ });
+ });
+
+ this.then(function () {
+ var states = this.evaluate(function() {
+ var states = [];
+ for (var i = 0; i < IPython._channels.length; i++) {
+ states.push(IPython._channels[i].readyState);
+ }
+ return states;
+ });
+
+ for (var i = 0; i < states.length; i++) {
+ this.test.assertEquals(states[i], WebSocket.CLOSED,
+ "Kernel.kill closes websockets[" + i + "]");
+ }
+ });
});
diff --git a/IPython/html/tests/services/session.js b/IPython/html/tests/services/session.js
new file mode 100644
index 0000000..af066cf
--- /dev/null
+++ b/IPython/html/tests/services/session.js
@@ -0,0 +1,43 @@
+
+//
+// Tests for the Session object
+//
+
+casper.notebook_test(function () {
+ this.evaluate(function () {
+ var kernel = IPython.notebook.session.kernel;
+ IPython._channels = [
+ kernel.shell_channel,
+ kernel.iopub_channel,
+ kernel.stdin_channel
+ ];
+ IPython.notebook.session.delete();
+ });
+
+ this.waitFor(function () {
+ return this.evaluate(function(){
+ for (var i=0; i < IPython._channels.length; i++) {
+ var ws = IPython._channels[i];
+ if (ws.readyState !== ws.CLOSED) {
+ return false;
+ }
+ }
+ return true;
+ });
+ });
+
+ this.then(function () {
+ var states = this.evaluate(function() {
+ var states = [];
+ for (var i = 0; i < IPython._channels.length; i++) {
+ states.push(IPython._channels[i].readyState);
+ }
+ return states;
+ });
+
+ for (var i = 0; i < states.length; i++) {
+ this.test.assertEquals(states[i], WebSocket.CLOSED,
+ "Session.delete closes websockets[" + i + "]");
+ }
+ });
+});
diff --git a/IPython/html/tests/widgets/widget.js b/IPython/html/tests/widgets/widget.js
index 787b0f2..005d75e 100644
--- a/IPython/html/tests/widgets/widget.js
+++ b/IPython/html/tests/widgets/widget.js
@@ -147,7 +147,7 @@ casper.notebook_test(function () {
var textbox = {};
throttle_index = this.append_cell(
'import time\n' +
- 'textbox = widgets.TextWidget()\n' +
+ 'textbox = widgets.Text()\n' +
'display(textbox)\n' +
'textbox.add_class("my-throttle-textbox", selector="input")\n' +
'def handle_change(name, old, new):\n' +
diff --git a/IPython/html/tests/widgets/widget_bool.js b/IPython/html/tests/widgets/widget_bool.js
index 4fd1007..0fe80b9 100644
--- a/IPython/html/tests/widgets/widget_bool.js
+++ b/IPython/html/tests/widgets/widget_bool.js
@@ -7,8 +7,8 @@ casper.notebook_test(function () {
this.execute_cell_then(index);
var bool_index = this.append_cell(
- 'bool_widgets = [widgets.CheckboxWidget(description="Title", value=True),\n' +
- ' widgets.ToggleButtonWidget(description="Title", value=True)]\n' +
+ 'bool_widgets = [widgets.Checkbox(description="Title", value=True),\n' +
+ ' widgets.ToggleButton(description="Title", value=True)]\n' +
'display(bool_widgets[0])\n' +
'display(bool_widgets[1])\n' +
'print("Success")');
diff --git a/IPython/html/tests/widgets/widget_container.js b/IPython/html/tests/widgets/widget_box.js
similarity index 93%
rename from IPython/html/tests/widgets/widget_container.js
rename to IPython/html/tests/widgets/widget_box.js
index e3faa75..c1b422a 100644
--- a/IPython/html/tests/widgets/widget_container.js
+++ b/IPython/html/tests/widgets/widget_box.js
@@ -7,8 +7,8 @@ casper.notebook_test(function () {
this.execute_cell_then(index);
var container_index = this.append_cell(
- 'container = widgets.ContainerWidget()\n' +
- 'button = widgets.ButtonWidget()\n'+
+ 'container = widgets.Box()\n' +
+ 'button = widgets.Button()\n'+
'container.children = [button]\n'+
'display(container)\n'+
'container.add_class("my-test-class")\n'+
@@ -23,7 +23,7 @@ casper.notebook_test(function () {
'Widget subarea exists.');
this.test.assert(this.cell_element_exists(index,
- '.widget-area .widget-subarea .widget-container'),
+ '.widget-area .widget-subarea .widget-box'),
'Widget container exists.');
this.test.assert(this.cell_element_exists(index,
@@ -70,7 +70,7 @@ casper.notebook_test(function () {
'Display container child executed with correct output.');
this.test.assert(! this.cell_element_exists(index,
- '.widget-area .widget-subarea .widget-container'),
+ '.widget-area .widget-subarea .widget-box'),
'Parent container not displayed.');
this.test.assert(this.cell_element_exists(index,
diff --git a/IPython/html/tests/widgets/widget_button.js b/IPython/html/tests/widgets/widget_button.js
index ae0aec6..304f64d 100644
--- a/IPython/html/tests/widgets/widget_button.js
+++ b/IPython/html/tests/widgets/widget_button.js
@@ -7,7 +7,7 @@ casper.notebook_test(function () {
this.execute_cell_then(index);
var button_index = this.append_cell(
- 'button = widgets.ButtonWidget(description="Title")\n' +
+ 'button = widgets.Button(description="Title")\n' +
'display(button)\n' +
'print("Success")\n' +
'def handle_click(sender):\n' +
diff --git a/IPython/html/tests/widgets/widget_float.js b/IPython/html/tests/widgets/widget_float.js
index a26c42d..a2f4e74 100644
--- a/IPython/html/tests/widgets/widget_float.js
+++ b/IPython/html/tests/widgets/widget_float.js
@@ -9,7 +9,7 @@ casper.notebook_test(function () {
var float_text = {};
float_text.query = '.widget-area .widget-subarea .widget-hbox-single .my-second-float-text';
float_text.index = this.append_cell(
- 'float_widget = widgets.FloatTextWidget()\n' +
+ 'float_widget = widgets.FloatText()\n' +
'display(float_widget)\n' +
'float_widget.add_class("my-second-float-text", selector="input")\n' +
'print(float_widget.model_id)\n');
@@ -59,8 +59,8 @@ casper.notebook_test(function () {
var slider = {};
slider.query = '.widget-area .widget-subarea .widget-hbox-single .slider';
slider.index = this.append_cell(
- 'floatrange = [widgets.BoundedFloatTextWidget(), \n' +
- ' widgets.FloatSliderWidget()]\n' +
+ 'floatrange = [widgets.BoundedFloatText(), \n' +
+ ' widgets.FloatSlider()]\n' +
'[display(floatrange[i]) for i in range(2)]\n' +
'print("Success")\n');
this.execute_cell_then(slider.index, function(index){
diff --git a/IPython/html/tests/widgets/widget_image.js b/IPython/html/tests/widgets/widget_image.js
index 04b1451..c858c68 100644
--- a/IPython/html/tests/widgets/widget_image.js
+++ b/IPython/html/tests/widgets/widget_image.js
@@ -18,7 +18,7 @@ casper.notebook_test(function () {
var image_index = this.append_cell(
'import base64\n' +
'data = base64.b64decode("' + test_jpg + '")\n' +
- 'image = widgets.ImageWidget()\n' +
+ 'image = widgets.Image()\n' +
'image.format = "jpeg"\n' +
'image.value = data\n' +
'image.width = "50px"\n' +
diff --git a/IPython/html/tests/widgets/widget_int.js b/IPython/html/tests/widgets/widget_int.js
index 4393664..a9bc43d 100644
--- a/IPython/html/tests/widgets/widget_int.js
+++ b/IPython/html/tests/widgets/widget_int.js
@@ -9,7 +9,7 @@ casper.notebook_test(function () {
var int_text = {};
int_text.query = '.widget-area .widget-subarea .widget-hbox-single .my-second-int-text';
int_text.index = this.append_cell(
- 'int_widget = widgets.IntTextWidget()\n' +
+ 'int_widget = widgets.IntText()\n' +
'display(int_widget)\n' +
'int_widget.add_class("my-second-int-text", selector="input")\n' +
'print(int_widget.model_id)\n');
diff --git a/IPython/html/tests/widgets/widget_selection.js b/IPython/html/tests/widgets/widget_selection.js
index 25d5b86..dac47e0 100644
--- a/IPython/html/tests/widgets/widget_selection.js
+++ b/IPython/html/tests/widgets/widget_selection.js
@@ -44,10 +44,10 @@ casper.notebook_test(function () {
//values=["' + selection_values + '"[i] for i in range(4)]
selection_index = this.append_cell(
'values=["' + selection_values + '"[i] for i in range(4)]\n' +
- 'selection = [widgets.DropdownWidget(values=values),\n' +
- ' widgets.ToggleButtonsWidget(values=values),\n' +
- ' widgets.RadioButtonsWidget(values=values),\n' +
- ' widgets.SelectWidget(values=values)]\n' +
+ 'selection = [widgets.Dropdown(values=values),\n' +
+ ' widgets.ToggleButtons(values=values),\n' +
+ ' widgets.RadioButtons(values=values),\n' +
+ ' widgets.Select(values=values)]\n' +
'[display(selection[i]) for i in range(4)]\n' +
'for widget in selection:\n' +
' def handle_change(name,old,new):\n' +
diff --git a/IPython/html/tests/widgets/widget_selectioncontainer.js b/IPython/html/tests/widgets/widget_selectioncontainer.js
index 1cc9526..57e9bd1 100644
--- a/IPython/html/tests/widgets/widget_selectioncontainer.js
+++ b/IPython/html/tests/widgets/widget_selectioncontainer.js
@@ -9,10 +9,10 @@ casper.notebook_test(function () {
// Test tab view
var multicontainer1_query = '.widget-area .widget-subarea div div.nav-tabs';
var multicontainer1_index = this.append_cell(
- 'multicontainer = widgets.TabWidget()\n' +
- 'page1 = widgets.TextWidget()\n' +
- 'page2 = widgets.TextWidget()\n' +
- 'page3 = widgets.TextWidget()\n' +
+ 'multicontainer = widgets.Tab()\n' +
+ 'page1 = widgets.Text()\n' +
+ 'page2 = widgets.Text()\n' +
+ 'page3 = widgets.Text()\n' +
'multicontainer.children = [page1, page2, page3]\n' +
'display(multicontainer)\n' +
'multicontainer.selected_index = 0\n' +
@@ -64,10 +64,10 @@ casper.notebook_test(function () {
// Test accordion view
var multicontainer2_query = '.widget-area .widget-subarea .panel-group';
var multicontainer2_index = this.append_cell(
- 'multicontainer = widgets.AccordionWidget()\n' +
- 'page1 = widgets.TextWidget()\n' +
- 'page2 = widgets.TextWidget()\n' +
- 'page3 = widgets.TextWidget()\n' +
+ 'multicontainer = widgets.Accordion()\n' +
+ 'page1 = widgets.Text()\n' +
+ 'page2 = widgets.Text()\n' +
+ 'page3 = widgets.Text()\n' +
'multicontainer.children = [page1, page2, page3]\n' +
'multicontainer.set_title(2, "good")\n' +
'display(multicontainer)\n' +
diff --git a/IPython/html/tests/widgets/widget_string.js b/IPython/html/tests/widgets/widget_string.js
index 1288cbd..8e9acee 100644
--- a/IPython/html/tests/widgets/widget_string.js
+++ b/IPython/html/tests/widgets/widget_string.js
@@ -7,10 +7,10 @@ casper.notebook_test(function () {
this.execute_cell_then(index);
var string_index = this.append_cell(
- 'string_widget = [widgets.TextWidget(value = "xyz", placeholder = "abc"),\n' +
- ' widgets.TextareaWidget(value = "xyz", placeholder = "def"),\n' +
- ' widgets.HTMLWidget(value = "xyz"),\n' +
- ' widgets.LatexWidget(value = "$\\\\LaTeX{}$")]\n' +
+ 'string_widget = [widgets.Text(value = "xyz", placeholder = "abc"),\n' +
+ ' widgets.Textarea(value = "xyz", placeholder = "def"),\n' +
+ ' widgets.HTML(value = "xyz"),\n' +
+ ' widgets.Latex(value = "$\\\\LaTeX{}$")]\n' +
'[display(widget) for widget in string_widget]\n'+
'print("Success")');
this.execute_cell_then(string_index, function(index){
diff --git a/IPython/html/widgets/__init__.py b/IPython/html/widgets/__init__.py
index c0b3d2a..d3cdb11 100644
--- a/IPython/html/widgets/__init__.py
+++ b/IPython/html/widgets/__init__.py
@@ -1,12 +1,23 @@
from .widget import Widget, DOMWidget, CallbackDispatcher
+from .widget_bool import Checkbox, ToggleButton
+from .widget_button import Button
+from .widget_box import Box, Popup, FlexBox, HBox, VBox
+from .widget_float import FloatText, BoundedFloatText, FloatSlider, FloatProgress, FloatRangeSlider
+from .widget_image import Image
+from .widget_int import IntText, BoundedIntText, IntSlider, IntProgress, IntRangeSlider
+from .widget_selection import RadioButtons, ToggleButtons, Dropdown, Select
+from .widget_selectioncontainer import Tab, Accordion
+from .widget_string import HTML, Latex, Text, Textarea
+from .interaction import interact, interactive, fixed
+
+# Deprecated classes
from .widget_bool import CheckboxWidget, ToggleButtonWidget
from .widget_button import ButtonWidget
-from .widget_container import ContainerWidget, PopupWidget
-from .widget_float import FloatTextWidget, BoundedFloatTextWidget, FloatSliderWidget, FloatProgressWidget, FloatRangeSliderWidget
+from .widget_box import ContainerWidget, PopupWidget
+from .widget_float import FloatTextWidget, BoundedFloatTextWidget, FloatSliderWidget, FloatProgressWidget
from .widget_image import ImageWidget
-from .widget_int import IntTextWidget, BoundedIntTextWidget, IntSliderWidget, IntProgressWidget, IntRangeSliderWidget
+from .widget_int import IntTextWidget, BoundedIntTextWidget, IntSliderWidget, IntProgressWidget
from .widget_selection import RadioButtonsWidget, ToggleButtonsWidget, DropdownWidget, SelectWidget
from .widget_selectioncontainer import TabWidget, AccordionWidget
from .widget_string import HTMLWidget, LatexWidget, TextWidget, TextareaWidget
-from .interaction import interact, interactive, fixed
diff --git a/IPython/html/widgets/interaction.py b/IPython/html/widgets/interaction.py
index 1b59de8..86c7125 100644
--- a/IPython/html/widgets/interaction.py
+++ b/IPython/html/widgets/interaction.py
@@ -21,9 +21,9 @@ except ImportError:
from inspect import getcallargs
from IPython.core.getipython import get_ipython
-from IPython.html.widgets import (Widget, TextWidget,
- FloatSliderWidget, IntSliderWidget, CheckboxWidget, DropdownWidget,
- ContainerWidget, DOMWidget)
+from IPython.html.widgets import (Widget, Text,
+ FloatSlider, IntSlider, Checkbox, Dropdown,
+ Box, DOMWidget)
from IPython.display import display, clear_output
from IPython.utils.py3compat import string_types, unicode_type
from IPython.utils.traitlets import HasTraits, Any, Unicode
@@ -70,17 +70,17 @@ def _get_min_max_value(min, max, value=None, step=None):
def _widget_abbrev_single_value(o):
"""Make widgets from single values, which can be used as parameter defaults."""
if isinstance(o, string_types):
- return TextWidget(value=unicode_type(o))
+ return Text(value=unicode_type(o))
elif isinstance(o, dict):
- return DropdownWidget(values=o)
+ return Dropdown(values=o)
elif isinstance(o, bool):
- return CheckboxWidget(value=o)
+ return Checkbox(value=o)
elif isinstance(o, float):
min, max, value = _get_min_max_value(None, None, o)
- return FloatSliderWidget(value=o, min=min, max=max)
+ return FloatSlider(value=o, min=min, max=max)
elif isinstance(o, int):
min, max, value = _get_min_max_value(None, None, o)
- return IntSliderWidget(value=o, min=min, max=max)
+ return IntSlider(value=o, min=min, max=max)
else:
return None
@@ -89,13 +89,13 @@ def _widget_abbrev(o):
float_or_int = (float, int)
if isinstance(o, (list, tuple)):
if o and all(isinstance(x, string_types) for x in o):
- return DropdownWidget(values=[unicode_type(k) for k in o])
+ return Dropdown(values=[unicode_type(k) for k in o])
elif _matches(o, (float_or_int, float_or_int)):
min, max, value = _get_min_max_value(o[0], o[1])
if all(isinstance(_, int) for _ in o):
- cls = IntSliderWidget
+ cls = IntSlider
else:
- cls = FloatSliderWidget
+ cls = FloatSlider
return cls(value=value, min=min, max=max)
elif _matches(o, (float_or_int, float_or_int, float_or_int)):
step = o[2]
@@ -103,9 +103,9 @@ def _widget_abbrev(o):
raise ValueError("step must be >= 0, not %r" % step)
min, max, value = _get_min_max_value(o[0], o[1], step=step)
if all(isinstance(_, int) for _ in o):
- cls = IntSliderWidget
+ cls = IntSlider
else:
- cls = FloatSliderWidget
+ cls = FloatSlider
return cls(value=value, min=min, max=max, step=step)
else:
return _widget_abbrev_single_value(o)
@@ -176,7 +176,7 @@ def interactive(__interact_f, **kwargs):
f = __interact_f
co = kwargs.pop('clear_output', True)
kwargs_widgets = []
- container = ContainerWidget()
+ container = Box()
container.result = None
container.args = []
container.kwargs = dict()
diff --git a/IPython/html/widgets/tests/test_interaction.py b/IPython/html/widgets/tests/test_interaction.py
index df15577..74d00c4 100644
--- a/IPython/html/widgets/tests/test_interaction.py
+++ b/IPython/html/widgets/tests/test_interaction.py
@@ -92,7 +92,7 @@ def test_single_value_string():
c = interactive(f, a=a)
w = c.children[0]
check_widget(w,
- cls=widgets.TextWidget,
+ cls=widgets.Text,
description='a',
value=a,
)
@@ -102,7 +102,7 @@ def test_single_value_bool():
c = interactive(f, a=a)
w = c.children[0]
check_widget(w,
- cls=widgets.CheckboxWidget,
+ cls=widgets.Checkbox,
description='a',
value=a,
)
@@ -115,7 +115,7 @@ def test_single_value_dict():
c = interactive(f, d=d)
w = c.children[0]
check_widget(w,
- cls=widgets.DropdownWidget,
+ cls=widgets.Dropdown,
description='d',
values=d,
value=next(iter(d.values())),
@@ -126,7 +126,7 @@ def test_single_value_float():
c = interactive(f, a=a)
w = c.children[0]
check_widget(w,
- cls=widgets.FloatSliderWidget,
+ cls=widgets.FloatSlider,
description='a',
value=a,
min= -a if a > 0 else 3*a,
@@ -141,7 +141,7 @@ def test_single_value_int():
nt.assert_equal(len(c.children), 1)
w = c.children[0]
check_widget(w,
- cls=widgets.IntSliderWidget,
+ cls=widgets.IntSlider,
description='a',
value=a,
min= -a if a > 0 else 3*a,
@@ -159,7 +159,7 @@ def test_list_tuple_2_int():
c = interactive(f, tup=(min, max), lis=[min, max])
nt.assert_equal(len(c.children), 2)
d = dict(
- cls=widgets.IntSliderWidget,
+ cls=widgets.IntSlider,
min=min,
max=max,
step=1,
@@ -176,7 +176,7 @@ def test_list_tuple_3_int():
c = interactive(f, tup=(min, max, step), lis=[min, max, step])
nt.assert_equal(len(c.children), 2)
d = dict(
- cls=widgets.IntSliderWidget,
+ cls=widgets.IntSlider,
min=min,
max=max,
step=step,
@@ -193,7 +193,7 @@ def test_list_tuple_2_float():
c = interactive(f, tup=(min, max), lis=[min, max])
nt.assert_equal(len(c.children), 2)
d = dict(
- cls=widgets.FloatSliderWidget,
+ cls=widgets.FloatSlider,
min=min,
max=max,
step=.1,
@@ -212,7 +212,7 @@ def test_list_tuple_3_float():
c = interactive(f, tup=(min, max, step), lis=[min, max, step])
nt.assert_equal(len(c.children), 2)
d = dict(
- cls=widgets.FloatSliderWidget,
+ cls=widgets.FloatSlider,
min=min,
max=max,
step=step,
@@ -227,7 +227,7 @@ def test_list_tuple_str():
c = interactive(f, tup=tuple(values), lis=list(values))
nt.assert_equal(len(c.children), 2)
d = dict(
- cls=widgets.DropdownWidget,
+ cls=widgets.Dropdown,
value=first,
values=dvalues
)
@@ -253,15 +253,15 @@ def test_defaults():
c = interactive(f)
check_widgets(c,
n=dict(
- cls=widgets.IntSliderWidget,
+ cls=widgets.IntSlider,
value=10,
),
f=dict(
- cls=widgets.FloatSliderWidget,
+ cls=widgets.FloatSlider,
value=4.5,
),
g=dict(
- cls=widgets.IntSliderWidget,
+ cls=widgets.IntSlider,
value=1,
),
)
@@ -274,24 +274,24 @@ def test_default_values():
c = interactive(f)
check_widgets(c,
n=dict(
- cls=widgets.IntSliderWidget,
+ cls=widgets.IntSlider,
value=10,
),
f=dict(
- cls=widgets.FloatSliderWidget,
+ cls=widgets.FloatSlider,
value=4.5,
),
g=dict(
- cls=widgets.IntSliderWidget,
+ cls=widgets.IntSlider,
value=5,
),
h=dict(
- cls=widgets.DropdownWidget,
+ cls=widgets.Dropdown,
values={'a': 1, 'b': 2},
value=2
),
j=dict(
- cls=widgets.DropdownWidget,
+ cls=widgets.Dropdown,
values={'hi':'hi', 'there':'there'},
value='there'
),
@@ -305,34 +305,34 @@ def test_default_out_of_bounds():
c = interactive(f)
check_widgets(c,
f=dict(
- cls=widgets.FloatSliderWidget,
+ cls=widgets.FloatSlider,
value=5.,
),
h=dict(
- cls=widgets.DropdownWidget,
+ cls=widgets.Dropdown,
values={'a': 1},
value=1,
),
j=dict(
- cls=widgets.DropdownWidget,
+ cls=widgets.Dropdown,
values={'hi':'hi', 'there':'there'},
value='hi',
),
)
def test_annotations():
- @annotate(n=10, f=widgets.FloatTextWidget())
+ @annotate(n=10, f=widgets.FloatText())
def f(n, f):
pass
c = interactive(f)
check_widgets(c,
n=dict(
- cls=widgets.IntSliderWidget,
+ cls=widgets.IntSlider,
value=10,
),
f=dict(
- cls=widgets.FloatTextWidget,
+ cls=widgets.FloatText,
),
)
@@ -344,11 +344,11 @@ def test_priority():
c = interactive(f, kwarg='kwarg')
check_widgets(c,
kwarg=dict(
- cls=widgets.TextWidget,
+ cls=widgets.Text,
value='kwarg',
),
annotate=dict(
- cls=widgets.TextWidget,
+ cls=widgets.Text,
value='annotate',
),
)
@@ -362,7 +362,7 @@ def test_decorator_kwarg():
nt.assert_equal(len(displayed), 1)
w = displayed[0].children[0]
check_widget(w,
- cls=widgets.IntSliderWidget,
+ cls=widgets.IntSlider,
value=5,
)
@@ -375,7 +375,7 @@ def test_decorator_no_call():
nt.assert_equal(len(displayed), 1)
w = displayed[0].children[0]
check_widget(w,
- cls=widgets.TextWidget,
+ cls=widgets.Text,
value='default',
)
@@ -388,7 +388,7 @@ def test_call_interact():
nt.assert_equal(len(displayed), 1)
w = displayed[0].children[0]
check_widget(w,
- cls=widgets.TextWidget,
+ cls=widgets.Text,
value='default',
)
@@ -401,7 +401,7 @@ def test_call_interact_kwargs():
nt.assert_equal(len(displayed), 1)
w = displayed[0].children[0]
check_widget(w,
- cls=widgets.IntSliderWidget,
+ cls=widgets.IntSlider,
value=10,
)
@@ -417,7 +417,7 @@ def test_call_decorated_on_trait_change():
nt.assert_equal(len(displayed), 1)
w = displayed[0].children[0]
check_widget(w,
- cls=widgets.TextWidget,
+ cls=widgets.Text,
value='default',
)
# test calling the function directly
@@ -441,7 +441,7 @@ def test_call_decorated_kwargs_on_trait_change():
nt.assert_equal(len(displayed), 1)
w = displayed[0].children[0]
check_widget(w,
- cls=widgets.TextWidget,
+ cls=widgets.Text,
value='kwarg',
)
# test calling the function directly
@@ -458,7 +458,7 @@ def test_fixed():
nt.assert_equal(len(c.children), 1)
w = c.children[0]
check_widget(w,
- cls=widgets.TextWidget,
+ cls=widgets.Text,
value='text',
description='b',
)
@@ -467,22 +467,22 @@ def test_default_description():
c = interactive(f, b='text')
w = c.children[0]
check_widget(w,
- cls=widgets.TextWidget,
+ cls=widgets.Text,
value='text',
description='b',
)
def test_custom_description():
- c = interactive(f, b=widgets.TextWidget(value='text', description='foo'))
+ c = interactive(f, b=widgets.Text(value='text', description='foo'))
w = c.children[0]
check_widget(w,
- cls=widgets.TextWidget,
+ cls=widgets.Text,
value='text',
description='foo',
)
def test_int_range_logic():
- irsw = widgets.IntRangeSliderWidget
+ irsw = widgets.IntRangeSlider
w = irsw(value=(2, 4), min=0, max=6)
check_widget(w, cls=irsw, value=(2, 4), min=0, max=6)
w.value = (4, 2)
@@ -537,7 +537,7 @@ def test_int_range_logic():
def test_float_range_logic():
- frsw = widgets.FloatRangeSliderWidget
+ frsw = widgets.FloatRangeSlider
w = frsw(value=(.2, .4), min=0., max=.6)
check_widget(w, cls=frsw, value=(.2, .4), min=0., max=.6)
w.value = (.4, .2)
@@ -588,4 +588,4 @@ def test_float_range_logic():
with nt.assert_raises(ValueError):
frsw(value=(2, 4), lower=3, upper=3)
with nt.assert_raises(ValueError):
- frsw(min=.2, max=.1)
\ No newline at end of file
+ frsw(min=.2, max=.1)
diff --git a/IPython/html/widgets/widget_bool.py b/IPython/html/widgets/widget_bool.py
index ac07d7f..b7bbb1d 100644
--- a/IPython/html/widgets/widget_bool.py
+++ b/IPython/html/widgets/widget_bool.py
@@ -1,4 +1,4 @@
-"""BoolWidget class.
+"""Bool class.
Represents a boolean using a widget.
"""
@@ -15,20 +15,29 @@ Represents a boolean using a widget.
#-----------------------------------------------------------------------------
from .widget import DOMWidget
from IPython.utils.traitlets import Unicode, Bool
+from IPython.utils.warn import DeprecatedClass
#-----------------------------------------------------------------------------
# Classes
#-----------------------------------------------------------------------------
-class _BoolWidget(DOMWidget):
+class _Bool(DOMWidget):
+ """A base class for creating widgets that represent booleans."""
value = Bool(False, help="Bool value", sync=True)
- description = Unicode('', help="Description of the boolean (label).", sync=True)
+ description = Unicode('', help="Description of the boolean (label).", sync=True)
disabled = Bool(False, help="Enable or disable user changes.", sync=True)
-class CheckboxWidget(_BoolWidget):
+class Checkbox(_Bool):
+ """Displays a boolean `value`."""
_view_name = Unicode('CheckboxView', sync=True)
-class ToggleButtonWidget(_BoolWidget):
- _view_name = Unicode('ToggleButtonView', sync=True)
+class ToggleButton(_Bool):
+ """Displays a boolean `value`."""
+ _view_name = Unicode('ToggleButtonView', sync=True)
+
+
+# Remove in IPython 4.0
+CheckboxWidget = DeprecatedClass(Checkbox, 'CheckboxWidget')
+ToggleButtonWidget = DeprecatedClass(ToggleButton, 'ToggleButtonWidget')
diff --git a/IPython/html/widgets/widget_box.py b/IPython/html/widgets/widget_box.py
new file mode 100644
index 0000000..bd204bd
--- /dev/null
+++ b/IPython/html/widgets/widget_box.py
@@ -0,0 +1,73 @@
+"""Box class.
+
+Represents a container that can be used to group other widgets.
+"""
+
+# Copyright (c) IPython Development Team.
+# Distributed under the terms of the Modified BSD License.
+
+from .widget import DOMWidget
+from IPython.utils.traitlets import Unicode, Tuple, TraitError, Int, CaselessStrEnum
+from IPython.utils.warn import DeprecatedClass
+
+class Box(DOMWidget):
+ """Displays multiple widgets in a group."""
+ _view_name = Unicode('BoxView', sync=True)
+
+ # Child widgets in the container.
+ # Using a tuple here to force reassignment to update the list.
+ # When a proper notifying-list trait exists, that is what should be used here.
+ children = Tuple(sync=True, allow_none=False)
+
+ def __init__(self, children = (), **kwargs):
+ kwargs['children'] = children
+ super(Box, self).__init__(**kwargs)
+ self.on_displayed(Box._fire_children_displayed)
+
+ def _fire_children_displayed(self):
+ for child in self.children:
+ child._handle_displayed()
+
+
+class Popup(Box):
+ """Displays multiple widgets in an in page popup div."""
+ _view_name = Unicode('PopupView', sync=True)
+
+ description = Unicode(sync=True)
+ button_text = Unicode(sync=True)
+
+
+class FlexBox(Box):
+ """Displays multiple widgets using the flexible box model."""
+ _view_name = Unicode('FlexBoxView', sync=True)
+ orientation = CaselessStrEnum(values=['vertical', 'horizontal'], default_value='vertical', sync=True)
+ flex = Int(0, sync=True, help="""Specify the flexible-ness of the model.""")
+ def _flex_changed(self, name, old, new):
+ new = min(max(0, new), 2)
+ if self.flex != new:
+ self.flex = new
+
+ _locations = ['start', 'center', 'end', 'baseline', 'stretch']
+ pack = CaselessStrEnum(
+ values=_locations,
+ default_value='start', allow_none=False, sync=True)
+ align = CaselessStrEnum(
+ values=_locations,
+ default_value='start', allow_none=False, sync=True)
+
+
+def VBox(*pargs, **kwargs):
+ """Displays multiple widgets vertically using the flexible box model."""
+ kwargs['orientation'] = 'vertical'
+ return FlexBox(*pargs, **kwargs)
+
+def HBox(*pargs, **kwargs):
+ """Displays multiple widgets horizontally using the flexible box model."""
+ kwargs['orientation'] = 'horizontal'
+ return FlexBox(*pargs, **kwargs)
+
+
+# Remove in IPython 4.0
+ContainerWidget = DeprecatedClass(Box, 'ContainerWidget')
+PopupWidget = DeprecatedClass(Popup, 'PopupWidget')
+
diff --git a/IPython/html/widgets/widget_button.py b/IPython/html/widgets/widget_button.py
index 3fdfe72..17774cc 100644
--- a/IPython/html/widgets/widget_button.py
+++ b/IPython/html/widgets/widget_button.py
@@ -1,4 +1,4 @@
-"""ButtonWidget class.
+"""Button class.
Represents a button in the frontend using a widget. Allows user to listen for
click events on the button and trigger backend code when the clicks are fired.
@@ -16,11 +16,16 @@ click events on the button and trigger backend code when the clicks are fired.
#-----------------------------------------------------------------------------
from .widget import DOMWidget, CallbackDispatcher
from IPython.utils.traitlets import Unicode, Bool
+from IPython.utils.warn import DeprecatedClass
#-----------------------------------------------------------------------------
# Classes
#-----------------------------------------------------------------------------
-class ButtonWidget(DOMWidget):
+class Button(DOMWidget):
+ """Button widget.
+
+ This widget has an `on_click` method that allows you to listen for the
+ user clicking on the button. The click event itself is stateless."""
_view_name = Unicode('ButtonView', sync=True)
# Keys
@@ -29,7 +34,7 @@ class ButtonWidget(DOMWidget):
def __init__(self, **kwargs):
"""Constructor"""
- super(ButtonWidget, self).__init__(**kwargs)
+ super(Button, self).__init__(**kwargs)
self._click_handlers = CallbackDispatcher()
self.on_msg(self._handle_button_msg)
@@ -54,3 +59,7 @@ class ButtonWidget(DOMWidget):
Content of the msg."""
if content.get('event', '') == 'click':
self._click_handlers(self)
+
+
+# Remove in IPython 4.0
+ButtonWidget = DeprecatedClass(Button, 'ButtonWidget')
diff --git a/IPython/html/widgets/widget_container.py b/IPython/html/widgets/widget_container.py
deleted file mode 100644
index 6ba8206..0000000
--- a/IPython/html/widgets/widget_container.py
+++ /dev/null
@@ -1,34 +0,0 @@
-"""ContainerWidget class.
-
-Represents a container that can be used to group other widgets.
-"""
-
-# Copyright (c) IPython Development Team.
-# Distributed under the terms of the Modified BSD License.
-
-from .widget import DOMWidget
-from IPython.utils.traitlets import Unicode, Tuple, TraitError
-
-class ContainerWidget(DOMWidget):
- _view_name = Unicode('ContainerView', sync=True)
-
- # Child widgets in the container.
- # Using a tuple here to force reassignment to update the list.
- # When a proper notifying-list trait exists, that is what should be used here.
- children = Tuple(sync=True, allow_none=False)
-
- def __init__(self, children = (), **kwargs):
- kwargs['children'] = children
- super(ContainerWidget, self).__init__(**kwargs)
- self.on_displayed(ContainerWidget._fire_children_displayed)
-
- def _fire_children_displayed(self):
- for child in self.children:
- child._handle_displayed()
-
-
-class PopupWidget(ContainerWidget):
- _view_name = Unicode('PopupView', sync=True)
-
- description = Unicode(sync=True)
- button_text = Unicode(sync=True)
diff --git a/IPython/html/widgets/widget_float.py b/IPython/html/widgets/widget_float.py
index db7b350..e5d5aac 100644
--- a/IPython/html/widgets/widget_float.py
+++ b/IPython/html/widgets/widget_float.py
@@ -1,4 +1,4 @@
-"""FloatWidget class.
+"""Float class.
Represents an unbounded float using a widget.
"""
@@ -15,17 +15,18 @@ Represents an unbounded float using a widget.
#-----------------------------------------------------------------------------
from .widget import DOMWidget
from IPython.utils.traitlets import Unicode, CFloat, Bool, Enum, Tuple
+from IPython.utils.warn import DeprecatedClass
#-----------------------------------------------------------------------------
# Classes
#-----------------------------------------------------------------------------
-class _FloatWidget(DOMWidget):
- value = CFloat(0.0, help="Float value", sync=True)
+class _Float(DOMWidget):
+ value = CFloat(0.0, help="Float value", sync=True)
disabled = Bool(False, help="Enable or disable user changes", sync=True)
description = Unicode(help="Description of the value this widget represents", sync=True)
-class _BoundedFloatWidget(_FloatWidget):
+class _BoundedFloat(_Float):
max = CFloat(100.0, help="Max value", sync=True)
min = CFloat(0.0, help="Min value", sync=True)
step = CFloat(0.1, help="Minimum step that the value can take (ignored by some views)", sync=True)
@@ -42,26 +43,26 @@ class _BoundedFloatWidget(_FloatWidget):
self.value = min(max(new, self.min), self.max)
-class FloatTextWidget(_FloatWidget):
+class FloatText(_Float):
_view_name = Unicode('FloatTextView', sync=True)
-class BoundedFloatTextWidget(_BoundedFloatWidget):
+class BoundedFloatText(_BoundedFloat):
_view_name = Unicode('FloatTextView', sync=True)
-class FloatSliderWidget(_BoundedFloatWidget):
+class FloatSlider(_BoundedFloat):
_view_name = Unicode('FloatSliderView', sync=True)
- orientation = Enum([u'horizontal', u'vertical'], u'horizontal',
+ orientation = Enum([u'horizontal', u'vertical'], u'horizontal',
help="Vertical or horizontal.", sync=True)
range = Bool(False, help="Display a range selector", sync=True)
readout = Bool(True, help="Display the current value of the slider next to it.", sync=True)
-class FloatProgressWidget(_BoundedFloatWidget):
+class FloatProgress(_BoundedFloat):
_view_name = Unicode('ProgressView', sync=True)
-class _FloatRangeWidget(_FloatWidget):
+class _FloatRange(_Float):
value = Tuple(CFloat, CFloat, default_value=(0.0, 1.0), help="Tuple of (lower, upper) bounds", sync=True)
lower = CFloat(0.0, help="Lower bound", sync=False)
upper = CFloat(1.0, help="Upper bound", sync=False)
@@ -90,14 +91,14 @@ class _FloatRangeWidget(_FloatWidget):
elif name == 'upper':
self.value = (self.value[0], new)
-class _BoundedFloatRangeWidget(_FloatRangeWidget):
+class _BoundedFloatRange(_FloatRange):
step = CFloat(1.0, help="Minimum step that the value can take (ignored by some views)", sync=True)
max = CFloat(100.0, help="Max value", sync=True)
min = CFloat(0.0, help="Min value", sync=True)
def __init__(self, *pargs, **kwargs):
any_value_given = 'value' in kwargs or 'upper' in kwargs or 'lower' in kwargs
- _FloatRangeWidget.__init__(self, *pargs, **kwargs)
+ _FloatRange.__init__(self, *pargs, **kwargs)
# ensure a minimal amount of sanity
if self.min > self.max:
@@ -156,9 +157,15 @@ class _BoundedFloatRangeWidget(_FloatRangeWidget):
self.lower = low
-class FloatRangeSliderWidget(_BoundedFloatRangeWidget):
+class FloatRangeSlider(_BoundedFloatRange):
_view_name = Unicode('FloatSliderView', sync=True)
orientation = Enum([u'horizontal', u'vertical'], u'horizontal',
help="Vertical or horizontal.", sync=True)
range = Bool(True, help="Display a range selector", sync=True)
readout = Bool(True, help="Display the current value of the slider next to it.", sync=True)
+
+# Remove in IPython 4.0
+FloatTextWidget = DeprecatedClass(FloatText, 'FloatTextWidget')
+BoundedFloatTextWidget = DeprecatedClass(BoundedFloatText, 'BoundedFloatTextWidget')
+FloatSliderWidget = DeprecatedClass(FloatSlider, 'FloatSliderWidget')
+FloatProgressWidget = DeprecatedClass(FloatProgress, 'FloatProgressWidget')
diff --git a/IPython/html/widgets/widget_image.py b/IPython/html/widgets/widget_image.py
index 0e18bde..f8ff8d4 100644
--- a/IPython/html/widgets/widget_image.py
+++ b/IPython/html/widgets/widget_image.py
@@ -1,4 +1,4 @@
-"""ImageWidget class.
+"""Image class.
Represents an image in the frontend using a widget.
"""
@@ -17,11 +17,18 @@ import base64
from .widget import DOMWidget
from IPython.utils.traitlets import Unicode, CUnicode, Bytes
+from IPython.utils.warn import DeprecatedClass
#-----------------------------------------------------------------------------
# Classes
#-----------------------------------------------------------------------------
-class ImageWidget(DOMWidget):
+class Image(DOMWidget):
+ """Displays an image as a widget.
+
+ The `value` of this widget accepts a byte string. The byte string is the raw
+ image data that you want the browser to display. You can explicitly define
+ the format of the byte string using the `format` trait (which defaults to
+ "png")."""
_view_name = Unicode('ImageView', sync=True)
# Define the custom state properties to sync with the front-end
@@ -33,3 +40,7 @@ class ImageWidget(DOMWidget):
value = Bytes()
def _value_changed(self, name, old, new):
self._b64value = base64.b64encode(new)
+
+
+# Remove in IPython 4.0
+ImageWidget = DeprecatedClass(Image, 'ImageWidget')
diff --git a/IPython/html/widgets/widget_int.py b/IPython/html/widgets/widget_int.py
index f2f4f92..4497990 100644
--- a/IPython/html/widgets/widget_int.py
+++ b/IPython/html/widgets/widget_int.py
@@ -1,4 +1,4 @@
-"""IntWidget class.
+"""Int class.
Represents an unbounded int using a widget.
"""
@@ -15,17 +15,21 @@ Represents an unbounded int using a widget.
#-----------------------------------------------------------------------------
from .widget import DOMWidget
from IPython.utils.traitlets import Unicode, CInt, Bool, Enum, Tuple
+from IPython.utils.warn import DeprecatedClass
#-----------------------------------------------------------------------------
# Classes
#-----------------------------------------------------------------------------
-class _IntWidget(DOMWidget):
- value = CInt(0, help="Int value", sync=True)
+class _Int(DOMWidget):
+ """Base class used to create widgets that represent an int."""
+ value = CInt(0, help="Int value", sync=True)
disabled = Bool(False, help="Enable or disable user changes", sync=True)
description = Unicode(help="Description of the value this widget represents", sync=True)
-class _BoundedIntWidget(_IntWidget):
+class _BoundedInt(_Int):
+ """Base class used to create widgets that represent a int that is bounded
+ by a minium and maximum."""
step = CInt(1, help="Minimum step that the value can take (ignored by some views)", sync=True)
max = CInt(100, help="Max value", sync=True)
min = CInt(0, help="Min value", sync=True)
@@ -41,26 +45,30 @@ class _BoundedIntWidget(_IntWidget):
self.value = min(max(new, self.min), self.max)
-class IntTextWidget(_IntWidget):
+class IntText(_Int):
+ """Textbox widget that represents a int."""
_view_name = Unicode('IntTextView', sync=True)
-class BoundedIntTextWidget(_BoundedIntWidget):
+class BoundedIntText(_BoundedInt):
+ """Textbox widget that represents a int bounded by a minimum and maximum value."""
_view_name = Unicode('IntTextView', sync=True)
-class IntSliderWidget(_BoundedIntWidget):
+class IntSlider(_BoundedInt):
+ """Slider widget that represents a int bounded by a minimum and maximum value."""
_view_name = Unicode('IntSliderView', sync=True)
- orientation = Enum([u'horizontal', u'vertical'], u'horizontal',
+ orientation = Enum([u'horizontal', u'vertical'], u'horizontal',
help="Vertical or horizontal.", sync=True)
range = Bool(False, help="Display a range selector", sync=True)
readout = Bool(True, help="Display the current value of the slider next to it.", sync=True)
-class IntProgressWidget(_BoundedIntWidget):
+class IntProgress(_BoundedInt):
+ """Progress bar that represents a int bounded by a minimum and maximum value."""
_view_name = Unicode('ProgressView', sync=True)
-class _IntRangeWidget(_IntWidget):
+class _IntRange(_Int):
value = Tuple(CInt, CInt, default_value=(0, 1), help="Tuple of (lower, upper) bounds", sync=True)
lower = CInt(0, help="Lower bound", sync=False)
upper = CInt(1, help="Upper bound", sync=False)
@@ -89,14 +97,14 @@ class _IntRangeWidget(_IntWidget):
elif name == 'upper':
self.value = (self.value[0], new)
-class _BoundedIntRangeWidget(_IntRangeWidget):
+class _BoundedIntRange(_IntRange):
step = CInt(1, help="Minimum step that the value can take (ignored by some views)", sync=True)
max = CInt(100, help="Max value", sync=True)
min = CInt(0, help="Min value", sync=True)
def __init__(self, *pargs, **kwargs):
any_value_given = 'value' in kwargs or 'upper' in kwargs or 'lower' in kwargs
- _IntRangeWidget.__init__(self, *pargs, **kwargs)
+ _IntRange.__init__(self, *pargs, **kwargs)
# ensure a minimal amount of sanity
if self.min > self.max:
@@ -153,9 +161,15 @@ class _BoundedIntRangeWidget(_IntRangeWidget):
self.upper = high
self.lower = low
-class IntRangeSliderWidget(_BoundedIntRangeWidget):
+class IntRangeSlider(_BoundedIntRange):
_view_name = Unicode('IntSliderView', sync=True)
orientation = Enum([u'horizontal', u'vertical'], u'horizontal',
help="Vertical or horizontal.", sync=True)
range = Bool(True, help="Display a range selector", sync=True)
readout = Bool(True, help="Display the current value of the slider next to it.", sync=True)
+
+# Remove in IPython 4.0
+IntTextWidget = DeprecatedClass(IntText, 'IntTextWidget')
+BoundedIntTextWidget = DeprecatedClass(BoundedIntText, 'BoundedIntTextWidget')
+IntSliderWidget = DeprecatedClass(IntSlider, 'IntSliderWidget')
+IntProgressWidget = DeprecatedClass(IntProgress, 'IntProgressWidget')
diff --git a/IPython/html/widgets/widget_selection.py b/IPython/html/widgets/widget_selection.py
index e9706d1..7c4f2f1 100644
--- a/IPython/html/widgets/widget_selection.py
+++ b/IPython/html/widgets/widget_selection.py
@@ -1,4 +1,4 @@
-"""SelectionWidget classes.
+"""Selection classes.
Represents an enumeration using a widget.
"""
@@ -20,11 +20,12 @@ from threading import Lock
from .widget import DOMWidget
from IPython.utils.traitlets import Unicode, List, Bool, Any, Dict, TraitError
from IPython.utils.py3compat import unicode_type
+from IPython.utils.warn import DeprecatedClass
#-----------------------------------------------------------------------------
# SelectionWidget
#-----------------------------------------------------------------------------
-class _SelectionWidget(DOMWidget):
+class _Selection(DOMWidget):
"""Base class for Selection widgets
``values`` can be specified as a list or dict. If given as a list,
@@ -109,17 +110,30 @@ class _SelectionWidget(DOMWidget):
self.value_lock.release()
-class ToggleButtonsWidget(_SelectionWidget):
+class ToggleButtons(_Selection):
+ """Group of toggle buttons that represent an enumeration. Only one toggle
+ button can be toggled at any point in time."""
_view_name = Unicode('ToggleButtonsView', sync=True)
-class DropdownWidget(_SelectionWidget):
+class Dropdown(_Selection):
+ """Allows you to select a single item from a dropdown."""
_view_name = Unicode('DropdownView', sync=True)
-class RadioButtonsWidget(_SelectionWidget):
+class RadioButtons(_Selection):
+ """Group of radio buttons that represent an enumeration. Only one radio
+ button can be toggled at any point in time."""
_view_name = Unicode('RadioButtonsView', sync=True)
-class SelectWidget(_SelectionWidget):
+class Select(_Selection):
+ """Listbox that only allows one item to be selected at any given time."""
_view_name = Unicode('SelectView', sync=True)
+
+
+# Remove in IPython 4.0
+ToggleButtonsWidget = DeprecatedClass(ToggleButtons, 'ToggleButtonsWidget')
+DropdownWidget = DeprecatedClass(Dropdown, 'DropdownWidget')
+RadioButtonsWidget = DeprecatedClass(RadioButtons, 'RadioButtonsWidget')
+SelectWidget = DeprecatedClass(Select, 'SelectWidget')
diff --git a/IPython/html/widgets/widget_selectioncontainer.py b/IPython/html/widgets/widget_selectioncontainer.py
index ef91559..729090b 100644
--- a/IPython/html/widgets/widget_selectioncontainer.py
+++ b/IPython/html/widgets/widget_selectioncontainer.py
@@ -1,4 +1,4 @@
-"""SelectionContainerWidget class.
+"""SelectionContainer class.
Represents a multipage container that can be used to group other widgets into
pages.
@@ -14,13 +14,15 @@ pages.
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
-from .widget_container import ContainerWidget
+from .widget_box import Box
from IPython.utils.traitlets import Unicode, Dict, CInt
+from IPython.utils.warn import DeprecatedClass
#-----------------------------------------------------------------------------
# Classes
#-----------------------------------------------------------------------------
-class _SelectionContainerWidget(ContainerWidget):
+class _SelectionContainer(Box):
+ """Base class used to display multiple child widgets."""
_titles = Dict(help="Titles of the pages", sync=True)
selected_index = CInt(0, sync=True)
@@ -50,9 +52,16 @@ class _SelectionContainerWidget(ContainerWidget):
return None
-class AccordionWidget(_SelectionContainerWidget):
+class Accordion(_SelectionContainer):
+ """Displays children each on a separate accordion page."""
_view_name = Unicode('AccordionView', sync=True)
-class TabWidget(_SelectionContainerWidget):
+class Tab(_SelectionContainer):
+ """Displays children each on a separate accordion tab."""
_view_name = Unicode('TabView', sync=True)
+
+
+# Remove in IPython 4.0
+AccordionWidget = DeprecatedClass(Accordion, 'AccordionWidget')
+TabWidget = DeprecatedClass(Tab, 'TabWidget')
diff --git a/IPython/html/widgets/widget_string.py b/IPython/html/widgets/widget_string.py
index 9f6aa30..26b06cc 100644
--- a/IPython/html/widgets/widget_string.py
+++ b/IPython/html/widgets/widget_string.py
@@ -1,4 +1,4 @@
-"""StringWidget class.
+"""String class.
Represents a unicode string using a widget.
"""
@@ -15,37 +15,44 @@ Represents a unicode string using a widget.
#-----------------------------------------------------------------------------
from .widget import DOMWidget, CallbackDispatcher
from IPython.utils.traitlets import Unicode, Bool
+from IPython.utils.warn import DeprecatedClass
#-----------------------------------------------------------------------------
# Classes
#-----------------------------------------------------------------------------
-class _StringWidget(DOMWidget):
+class _String(DOMWidget):
+ """Base class used to create widgets that represent a string."""
value = Unicode(help="String value", sync=True)
disabled = Bool(False, help="Enable or disable user changes", sync=True)
description = Unicode(help="Description of the value this widget represents", sync=True)
placeholder = Unicode("", help="Placeholder text to display when nothing has been typed", sync=True)
-class HTMLWidget(_StringWidget):
+class HTML(_String):
+ """Renders the string `value` as HTML."""
_view_name = Unicode('HTMLView', sync=True)
-class LatexWidget(_StringWidget):
+class Latex(_String):
+ """Renders math inside the string `value` as Latex (requires $ $ or $$ $$
+ and similar latex tags)."""
_view_name = Unicode('LatexView', sync=True)
-class TextareaWidget(_StringWidget):
+class Textarea(_String):
+ """Multiline text area widget."""
_view_name = Unicode('TextareaView', sync=True)
def scroll_to_bottom(self):
self.send({"method": "scroll_to_bottom"})
-class TextWidget(_StringWidget):
+class Text(_String):
+ """Single line textbox widget."""
_view_name = Unicode('TextView', sync=True)
def __init__(self, **kwargs):
- super(TextWidget, self).__init__(**kwargs)
+ super(Text, self).__init__(**kwargs)
self._submission_callbacks = CallbackDispatcher()
self.on_msg(self._handle_string_msg)
@@ -71,3 +78,10 @@ class TextWidget(_StringWidget):
remove: bool (optional)
Whether to unregister the callback"""
self._submission_callbacks.register_callback(callback, remove=remove)
+
+
+# Remove in IPython 4.0
+HTMLWidget = DeprecatedClass(HTML, 'HTMLWidget')
+LatexWidget = DeprecatedClass(Latex, 'LatexWidget')
+TextareaWidget = DeprecatedClass(Textarea, 'TextareaWidget')
+TextWidget = DeprecatedClass(Text, 'TextWidget')
diff --git a/IPython/kernel/kernelspec.py b/IPython/kernel/kernelspec.py
index c708a8c..f129886 100644
--- a/IPython/kernel/kernelspec.py
+++ b/IPython/kernel/kernelspec.py
@@ -8,7 +8,7 @@ pjoin = os.path.join
from IPython.utils.path import get_ipython_dir
from IPython.utils.py3compat import PY3
-from IPython.utils.traitlets import HasTraits, List, Unicode, Dict
+from IPython.utils.traitlets import HasTraits, List, Unicode, Dict, Any
if os.name == 'nt':
programdata = os.environ.get('PROGRAMDATA', None)
@@ -36,18 +36,12 @@ class KernelSpec(HasTraits):
argv = List()
display_name = Unicode()
language = Unicode()
- codemirror_mode = None
+ codemirror_mode = Any() # can be unicode or dict
env = Dict()
-
resource_dir = Unicode()
- def __init__(self, resource_dir, argv, display_name, language,
- codemirror_mode=None):
- super(KernelSpec, self).__init__(resource_dir=resource_dir, argv=argv,
- display_name=display_name, language=language,
- codemirror_mode=codemirror_mode)
- if not self.codemirror_mode:
- self.codemirror_mode = self.language
+ def _codemirror_mode_default(self):
+ return self.language
@classmethod
def from_resource_dir(cls, resource_dir):
diff --git a/IPython/utils/_process_cli.py b/IPython/utils/_process_cli.py
index eb69d3f..a7b7b90 100644
--- a/IPython/utils/_process_cli.py
+++ b/IPython/utils/_process_cli.py
@@ -61,3 +61,18 @@ def getoutput(cmd):
myError = reg.StandardError
error = myError.ReadToEnd()
return output
+
+def check_pid(pid):
+ """
+ Check if a process with the given PID (pid) exists
+ """
+ try:
+ System.Diagnostics.Process.GetProcessById(pid)
+ # process with given pid is running
+ return True
+ except System.InvalidOperationException:
+ # process wasn't started by this object (but is running)
+ return True
+ except System.ArgumentException:
+ # process with given pid isn't running
+ return False
diff --git a/IPython/utils/process.py b/IPython/utils/process.py
index 2a19945..64b7254 100644
--- a/IPython/utils/process.py
+++ b/IPython/utils/process.py
@@ -23,7 +23,7 @@ import sys
if sys.platform == 'win32':
from ._process_win32 import _find_cmd, system, getoutput, arg_split, check_pid
elif sys.platform == 'cli':
- from ._process_cli import _find_cmd, system, getoutput, arg_split
+ from ._process_cli import _find_cmd, system, getoutput, arg_split, check_pid
else:
from ._process_posix import _find_cmd, system, getoutput, arg_split, check_pid
diff --git a/IPython/utils/tests/test_traitlets.py b/IPython/utils/tests/test_traitlets.py
index fcb3ca2..9251ae8 100644
--- a/IPython/utils/tests/test_traitlets.py
+++ b/IPython/utils/tests/test_traitlets.py
@@ -406,6 +406,13 @@ class TestHasTraits(TestCase):
a = A()
self.assertEqual(a.trait_metadata('i','config_key'), 'MY_VALUE')
+ def test_trait_metadata_default(self):
+ class A(HasTraits):
+ i = Int()
+ a = A()
+ self.assertEqual(a.trait_metadata('i', 'config_key'), None)
+ self.assertEqual(a.trait_metadata('i', 'config_key', 'default'), 'default')
+
def test_traits(self):
class A(HasTraits):
i = Int
diff --git a/IPython/utils/traitlets.py b/IPython/utils/traitlets.py
index 7b65196..c81f68a 100644
--- a/IPython/utils/traitlets.py
+++ b/IPython/utils/traitlets.py
@@ -458,8 +458,8 @@ class TraitType(object):
% (self.name, self.info(), repr_type(value))
raise TraitError(e)
- def get_metadata(self, key):
- return getattr(self, '_metadata', {}).get(key, None)
+ def get_metadata(self, key, default=None):
+ return getattr(self, '_metadata', {}).get(key, default)
def set_metadata(self, key, value):
getattr(self, '_metadata', {})[key] = value
@@ -728,7 +728,7 @@ class HasTraits(py3compat.with_metaclass(MetaHasTraits, object)):
return result
- def trait_metadata(self, traitname, key):
+ def trait_metadata(self, traitname, key, default=None):
"""Get metadata values for trait by key."""
try:
trait = getattr(self.__class__, traitname)
@@ -736,7 +736,7 @@ class HasTraits(py3compat.with_metaclass(MetaHasTraits, object)):
raise TraitError("Class %s does not have a trait named %s" %
(self.__class__.__name__, traitname))
else:
- return trait.get_metadata(key)
+ return trait.get_metadata(key, default)
#-----------------------------------------------------------------------------
# Actual TraitTypes implementations/subclasses
diff --git a/IPython/utils/warn.py b/IPython/utils/warn.py
index 693eeb3..6ad6acc 100644
--- a/IPython/utils/warn.py
+++ b/IPython/utils/warn.py
@@ -16,6 +16,7 @@ Utilities for warnings. Shoudn't we just use the built in warnings module.
from __future__ import print_function
import sys
+import warnings
from IPython.utils import io
@@ -65,3 +66,16 @@ def fatal(msg,exit_val=1):
warn(msg,exit_val=exit_val,level=4)
+
+def DeprecatedClass(base, class_name):
+ # Hook the init method of the base class.
+ def init_hook(self, *pargs, **kwargs):
+ base.__init__(self, *pargs, **kwargs)
+
+ # Warn once per class.
+ if base not in DeprecatedClass._warned_classes:
+ DeprecatedClass._warned_classes.append(base)
+ warn('"{}" is deprecated, please use "{}" instead.'.format(
+ class_name, base.__name__))
+ return type(class_name, (base,), {'__init__': init_hook})
+DeprecatedClass._warned_classes = []
diff --git a/docs/source/whatsnew/pr/incompat-deprecated-widget-names.rst b/docs/source/whatsnew/pr/incompat-deprecated-widget-names.rst
new file mode 100644
index 0000000..6ccd7aa
--- /dev/null
+++ b/docs/source/whatsnew/pr/incompat-deprecated-widget-names.rst
@@ -0,0 +1,6 @@
+* The widget classes have been renamed from `*Widget` to `*`. The old names are
+ still functional, but are deprecated. i.e. `IntSliderWidget` has been renamed
+ to `IntSlider`.
+* The ContainerWidget was renamed to Box and no longer defaults as a flexible
+ box in the web browser. A new FlexBox widget was added, which allows you to
+ use the flexible box model.
diff --git a/tox.ini b/tox.ini
index 5852233..dae0b87 100644
--- a/tox.ini
+++ b/tox.ini
@@ -3,23 +3,44 @@
# test suite on all supported python versions. To use it, "pip install tox"
# and then run "tox" from this directory.
+# Building the source distribution requires both fabric's fab binary
+# (http://www.fabfile.org/) and the lessc binary of the css preprocessor
+# less (http://lesscss.org/) in the PATH.
+# "pip install fabric" will install fabric. Less can be installed by
+# node.js' (http://nodejs.org/) package manager npm:
+# "npm install -g less".
+
+# Javascript tests need additional dependencies that can be installed
+# using node.js' package manager npm:
+# [*] casperjs: "npm install -g casperjs"
+# [*] slimerjs: "npm install -g slimerjs"
+# [*] phantomjs: "npm install -g phantomjs"
+
+# Note: qt4 versions break some tests with tornado versions >=4.0.
+
[tox]
-envlist = py27, py33
+envlist = py27, py33, py34
[testenv]
-deps =
+deps =
+ pyzmq
nose
- mock
- tornado
+ tornado<4.0
jinja2
sphinx
pygments
+ jsonpointer
+ jsonschema
+ mistune
+
# To avoid loading IPython module in the current directory, change
# current directory to ".tox/py*/tmp" before running test.
changedir = {envtmpdir}
commands =
- # As pip does not treat egg, use easy_install to install PyZMQ.
- # See also: https://github.com/zeromq/pyzmq
- easy_install -q pyzmq
- iptest --all
+ iptest --all
+
+[testenv:py27]
+deps=
+ mock
+ {[testenv]deps}