Repository: bokeh/bokeh

Issue:
The child property of panel can't be a widget.
Folllowing code raises error in Javascript:

```
from bokeh.io import curdoc
from bokeh.layouts import row
from bokeh.models.widgets import MultiSelect, Panel, Tabs

doc = curdoc()

select1 = MultiSelect(title="A", options=["A", "B"])
panel1 = Panel(title="Tab A", child=select1)
tabs = Tabs(tabs=[panel1])
doc.add_root(tabs)
```

Here is the error message:

```
connection.js:189 [bokeh] Failed to repull session Error: Instance property 'child' given invalid value: []
```

To fix it, I need wrap `select1` by `row()`.

```
panel1 = Panel(title="Tab A", child=row(select1))
```


Discussion:
That's a one nasty bug. 

Resolving patch:
diff --git a/examples/integration/widgets/tabs_with_multiselect.py b/examples/integration/widgets/tabs_with_multiselect.py
new file mode 100644
--- /dev/null
+++ b/examples/integration/widgets/tabs_with_multiselect.py
@@ -0,0 +1,10 @@
+from __future__ import absolute_import
+
+from bokeh.io import save
+from bokeh.models.widgets import MultiSelect, Panel, Tabs
+
+select = MultiSelect(options=["First option", "Second option"])
+panel = Panel(title="A tab", child=select)
+tabs = Tabs(tabs=[panel], width=300)
+
+save(tabs)


Test patch:
diff --git a/bokehjs/test/core/properties.coffee b/bokehjs/test/core/properties.coffee
--- a/bokehjs/test/core/properties.coffee
+++ b/bokehjs/test/core/properties.coffee
@@ -60,6 +60,46 @@ describe "properties module", ->
   spec_value_trans = {a: {value: 2, transform: new TestTransform()}}
   spec_value_null  = {a: {value: null}}
 
+  describe "isSpec", ->
+
+    it "should identify field specs", ->
+      prop = new properties.Property(new SomeHasProps(a: {field: "foo"}), 'a')
+      expect(p.isSpec(prop.spec)).to.be.true
+
+    it "should identify value specs", ->
+      prop = new properties.Property(new SomeHasProps(a: {value: "foo"}), 'a')
+      expect(p.isSpec(prop.spec)).to.be.true
+
+    it "should identify expr specs", ->
+      prop = new properties.Property(new SomeHasProps(a: {expr: "foo"}), 'a')
+      expect(p.isSpec(prop.spec)).to.be.true
+
+    it "should reject non-specs", ->
+      expect(p.isSpec(1)).to.be.false
+      expect(p.isSpec({})).to.be.false
+      expect(p.isSpec([])).to.be.false
+      expect(p.isSpec(null)).to.be.false
+      expect(p.isSpec(undefined)).to.be.false
+
+    it "should reject bad specs", ->
+      prop = new properties.Property(new SomeHasProps(a: {expr: "foo"}), 'a')
+      prop.spec.value = "bar"
+      expect(p.isSpec(prop.spec)).to.be.false
+      prop.spec.expr = "bar"
+      expect(p.isSpec(prop.spec)).to.be.false
+
+      prop = new properties.Property(new SomeHasProps(a: {value: "foo"}), 'a')
+      prop.spec.field = "bar"
+      expect(p.isSpec(prop.spec)).to.be.false
+      prop.spec.expr = "bar"
+      expect(p.isSpec(prop.spec)).to.be.false
+
+      prop = new properties.Property(new SomeHasProps(a: {field: "foo"}), 'a')
+      prop.spec.value = "bar"
+      expect(p.isSpec(prop.spec)).to.be.false
+      prop.spec.expr = "bar"
+      expect(p.isSpec(prop.spec)).to.be.false
+
   describe "Property", ->
 
     describe "construction", ->