Repository: bokeh/bokeh

Issue:
Ensure canvas state reset at start of drawing
Continuing discussion from #4405. The [`render()` method](https://github.com/bokeh/bokeh/blob/master/bokehjs/src/coffee/models/plots/plot_canvas.coffee#L374) in `plot_canvas.coffee` is the main entry point for the rendering; we should assume a clear state of the context because at the start of that function, we [make a call](https://github.com/bokeh/bokeh/blob/master/bokehjs/src/coffee/models/plots/plot_canvas.coffee#L407-L411) to `@canvas_view.prepare_canvas()`, which might resize the canvas (which resets context state).

All our `ctx.save()` and `ctx.restore()` usage pairs up as it should, however, if an error occurs (for whatever reason), any matching `ctx.restore()` may not be called, leaving the context in an unpredictable state. Since one of the first things we do in `plot_canvas.render()` is set a scaling transformation for the HIDPI, the plot will generally "blow up" in such a situation.

Although this is not a terrible thing per-see, as it only occurs when something is going wrong anyway, I think it can be a nasty / distracting side-effect. People might be wondering (and reporting) the plot from blowing up while the error is due to something completely unrelated.

Therefore, I propose to _ensure_ that the state of the context is clear before we start rendering, by making it reset in the `@canvas_view.prepare_canvas()` method (which already does a reset when it resizes the canvas).

Since there is no `ctx.reset()`, I propose to call `ctx.restore()` a couple of times. I agree that the _number_ of times to call `ctx.restore()` is rather arbitrary, and it generally means that we'll be doing a few unnecessary calls to `ctx.restore()` but I don't think the effect would be significant. 

A more sophisticated approach might be to keep tack of the depth of the stack by replacing `ctx.save()` and ctx.restore()` and updating a counter, and resetting based on that, but that feels a bit hacky.



Discussion:

Resolving patch:
diff --git a/bokeh/embed.py b/bokeh/embed.py
--- a/bokeh/embed.py
+++ b/bokeh/embed.py
@@ -29,6 +29,7 @@
 from .document import Document, DEFAULT_TITLE
 from .model import Model
 from .resources import BaseResources, DEFAULT_SERVER_HTTP_URL, _SessionCoordinates
+from .settings import settings
 from .util.deprecation import deprecated
 from .util.string import encode_utf8, format_docstring
 from .util.serialization import make_id
@@ -619,12 +620,17 @@ def autoload_server(model=None, app_path=None, session_id=None, url="default", r
 autoload_server.__doc__ = format_docstring(autoload_server.__doc__, DEFAULT_SERVER_HTTP_URL=DEFAULT_SERVER_HTTP_URL)
 
 def _script_for_render_items(docs_json, render_items, app_path=None, absolute_url=None):
-    return _wrap_in_onload(_wrap_in_safely(DOC_JS.render(
+    js = DOC_JS.render(
         docs_json=serialize_json(docs_json),
         render_items=serialize_json(render_items),
         app_path=app_path,
         absolute_url=absolute_url,
-    )))
+    )
+
+    if not settings.dev:
+        js = _wrap_in_safely(js)
+
+    return _wrap_in_onload(js)
 
 def _html_page_for_render_items(bundle, docs_json, render_items, title,
                                 template=FILE, template_variables={}):
diff --git a/bokeh/server/views/static_handler.py b/bokeh/server/views/static_handler.py
--- a/bokeh/server/views/static_handler.py
+++ b/bokeh/server/views/static_handler.py
@@ -28,10 +28,14 @@ def __init__(self, tornado_app, *args, **kw):
     # static files from multiple paths at once in the future.
     @classmethod
     def append_version(cls, path):
-        # this version is cached on the StaticFileHandler class,
+        # This version is cached on the StaticFileHandler class,
         # keyed by absolute filesystem path, and only invalidated
         # on an explicit StaticFileHandler.reset(). The reset is
-        # automatic on every request if you set
-        # static_hash_cache=False in TornadoApplication kwargs.
-        version = StaticFileHandler.get_version(dict(static_path=settings.bokehjsdir()), path)
-        return ("%s?v=%s" % (path, version))
+        # automatic on every request if you set static_hash_cache=False
+        # in TornadoApplication kwargs. In dev mode rely on dev tools
+        # to manage caching. This improves the ability to debug code.
+        if settings.dev:
+            return path
+        else:
+            version = StaticFileHandler.get_version(dict(static_path=settings.bokehjsdir()), path)
+            return ("%s?v=%s" % (path, version))
diff --git a/bokeh/settings.py b/bokeh/settings.py
--- a/bokeh/settings.py
+++ b/bokeh/settings.py
@@ -30,6 +30,10 @@ def _get(self, key, default=None):
     def _is_dev(self):
         return self._get_bool("DEV", False)
 
+    @property
+    def dev(self):
+        return self._is_dev
+
     def _dev_or_default(self, default, dev):
         return dev if dev is not None and self._is_dev else default
 


Test patch:
diff --git a/bokehjs/test/common/ui_events.coffee b/bokehjs/test/common/ui_events.coffee
--- a/bokehjs/test/common/ui_events.coffee
+++ b/bokehjs/test/common/ui_events.coffee
@@ -24,12 +24,10 @@ describe "ui_events module", ->
 
   afterEach ->
     utils.unstub_canvas()
-    utils.unstub_solver()
     UIEvents.prototype._configure_hammerjs.restore()
 
   beforeEach ->
     utils.stub_canvas()
-    utils.stub_solver()
     sinon.stub(UIEvents.prototype, "_configure_hammerjs")
 
     @toolbar = new Toolbar()
@@ -40,9 +38,10 @@ describe "ui_events module", ->
       y_range: new Range1d({start: 0, end: 1})
       toolbar: @toolbar
     })
+    @plot_view = new @plot.default_view({model: @plot, parent: null})
     canvas.document.add_root(@plot)
     @plot.plot_canvas.attach_document(canvas.document)
-    @plot_canvas_view = new @plot.plot_canvas.default_view({ 'model': @plot.plot_canvas })
+    @plot_canvas_view = new @plot.plot_canvas.default_view({ model: @plot.plot_canvas, parent: @plot_view })
     @ui_events = @plot_canvas_view.ui_event_bus
 
   describe "_trigger method", ->
@@ -107,7 +106,7 @@ describe "ui_events module", ->
 
       it "should change cursor on view_renderer with cursor method", ->
         legend = new Legend({click_policy: "mute"})
-        legend_view = new legend.default_view({'model': legend})
+        legend_view = new legend.default_view({model: legend, parent: null}) # wrong
 
         ss = sinon.stub(@ui_events, "_hit_test_renderers").returns(legend_view)
 
@@ -122,7 +121,7 @@ describe "ui_events module", ->
         @plot.add_tools(inspector)
 
         legend = new Legend({click_policy: "mute"})
-        legend_view = new legend.default_view({'model': legend})
+        legend_view = new legend.default_view({model: legend, parent: null}) # wrong
 
         ss = sinon.stub(@ui_events, "_hit_test_renderers").returns(legend_view)
 
@@ -157,7 +156,7 @@ describe "ui_events module", ->
 
       it "should call on_hit method on view renderer if exists", ->
         legend = new Legend({click_policy: "mute"})
-        legend_view = new legend.default_view({'model': legend})
+        legend_view = new legend.default_view({model: legend, parent: null}) # wrong
 
         ss = sinon.stub(@ui_events, "_hit_test_renderers").returns(legend_view)
         on_hit = sinon.stub(legend_view, "on_hit")
diff --git a/bokehjs/test/core/layout/side_panel.coffee b/bokehjs/test/core/layout/side_panel.coffee
--- a/bokehjs/test/core/layout/side_panel.coffee
+++ b/bokehjs/test/core/layout/side_panel.coffee
@@ -74,19 +74,11 @@ describe "SidePanel", ->
       @axis = new Axis({ ticker: new BasicTicker(), formatter: new BasicTickFormatter() })
       plot.add_layout(@axis, 'below')
       doc.add_root(plot)
-      plot_view = new plot.default_view({ 'model': plot })
-      @plot_canvas = new PlotCanvas({ 'plot': plot })
+      plot_view = new plot.default_view({model: plot, parent: null})
+      @plot_canvas = new PlotCanvas({plot: plot})
       @plot_canvas.attach_document(doc)
-      @plot_canvas_view = new @plot_canvas.default_view({ 'model': @plot_canvas })
-      @axis_view = new @axis.default_view({ model: @axis, plot_view: @plot_canvas_view })
-
-    it "should not fail if visible is not on model", ->
-      an = new Annotation()
-      an_view = new an.default_view({model: an, plot_view: @plot_canvas_view})
-      expect(an_view._size_constraint).to.be.undefined
-      update_constraints(an_view)
-      # Should still be undefined because visible is false
-      expect(an_view._size_constraint).to.be.undefined
+      @plot_canvas_view = new @plot_canvas.default_view({model: @plot_canvas, parent: plot_view})
+      @axis_view = new @axis.default_view({model: @axis, plot_view: @plot_canvas_view, parent: @plot_canvas_view})
 
     it "should not set _size_constraint if visible is false", ->
       @axis.visible = false
@@ -101,19 +93,13 @@ describe "SidePanel", ->
       sinon.stub(@axis_view, '_tick_label_extent', () -> 0.11)
       expect(@axis_view._size_constraint).to.be.undefined
       update_constraints(@axis_view)
-      expect(@axis_view._last_size).to.be.equal 0.33
+      expect(@axis_view._size_constraint.expression().constant()).to.be.equal(-0.33)
 
     it "should add two constraints on first call (one for size, one for full)", ->
       add_constraint_call_count = @solver_add_constraint.callCount
       update_constraints(@axis_view)
       expect(@solver_add_constraint.callCount).to.be.equal add_constraint_call_count + 2
 
-    it "should add one constraints on first call (for size) if manually set view._full_set to true", ->
-      add_constraint_call_count = @solver_add_constraint.callCount
-      @axis_view._full_set = true
-      update_constraints(@axis_view)
-      expect(@solver_add_constraint.callCount).to.be.equal add_constraint_call_count + 1
-
     it "should add and remove a constraint if the size changes", ->
       @axis_view._tick_extent = sinon.stub()
       @axis_view._tick_extent.onCall(0).returns(0.11)
@@ -124,21 +110,10 @@ describe "SidePanel", ->
 
       update_constraints(@axis_view)
 
-      expect(@solver_add_constraint.callCount).to.be.equal add_constraint_call_count + 2
-      expect(@solver_remove_constraint.callCount).to.be.equal remove_constraint_call_count + 0
+      expect(@solver_add_constraint.callCount).to.be.equal(add_constraint_call_count + 2)
+      expect(@solver_remove_constraint.callCount).to.be.equal(remove_constraint_call_count + 0)
 
       update_constraints(@axis_view)
 
-      expect(@solver_add_constraint.callCount).to.be.equal add_constraint_call_count + 3
-      expect(@solver_remove_constraint.callCount).to.be.equal remove_constraint_call_count + 1
-
-    it "should not add and remove a constraint if the size is the same", ->
-      @axis_view._tick_extent = sinon.stub()
-      @axis_view._tick_extent.returns(0.11)
-
-      update_constraints(@axis_view)
-      add_constraint_call_count = @solver_add_constraint.callCount
-      remove_constraint_call_count = @solver_remove_constraint.callCount
-      update_constraints(@axis_view)
-      expect(@solver_add_constraint.callCount).to.be.equal add_constraint_call_count
-      expect(@solver_remove_constraint.callCount).to.be.equal remove_constraint_call_count
+      expect(@solver_add_constraint.callCount).to.be.equal(add_constraint_call_count + 4)
+      expect(@solver_remove_constraint.callCount).to.be.equal(remove_constraint_call_count + 0)
diff --git a/bokehjs/test/document.coffee b/bokehjs/test/document.coffee
--- a/bokehjs/test/document.coffee
+++ b/bokehjs/test/document.coffee
@@ -9,6 +9,7 @@ sinon = require "sinon"
 js_version = utils.require("version").version
 {Models} = utils.require "base"
 {Model} = utils.require "model"
+{LayoutDOM} = utils.require "models/layouts/layout_dom"
 logging = utils.require "core/logging"
 p = utils.require "core/properties"
 
@@ -75,7 +76,7 @@ class ComplicatedModelWithConstructTimeChanges extends Model
 Models.register('ComplicatedModelWithConstructTimeChanges', ComplicatedModelWithConstructTimeChanges)
 
 
-class LayoutableModel extends Model
+class LayoutableModel extends LayoutDOM
   type: 'LayoutableModel'
 
   get_constraints: () ->
@@ -86,10 +87,6 @@ class LayoutableModel extends Model
 
   get_constrained_variables: () ->
     {}
-
-  @internal {
-    layoutable: [ p.Bool, true ]
-  }
 Models.register('LayoutableModel', LayoutableModel)
 
 class ModelWithConstraint extends LayoutableModel
@@ -135,8 +132,8 @@ class ModelWithConstrainedVariables extends LayoutableModel
       height: @_height
     }
 
-  @define {
-    sizing_mode: [ p.SizingMode, 'scale_width']
+  @override {
+    sizing_mode: 'scale_width'
   }
 
 Models.register('ModelWithConstrainedVariables', ModelWithConstrainedVariables)
@@ -153,8 +150,8 @@ class ModelWithConstrainedWidthVariable extends LayoutableModel
       width: @_width
     }
 
-  @define {
-    sizing_mode: [ p.SizingMode, 'scale_width']
+  @override {
+    sizing_mode: 'scale_width'
   }
 
 Models.register('ModelWithConstrainedWidthVariable', ModelWithConstrainedWidthVariable)
@@ -172,8 +169,8 @@ class ModelWithConstrainedHeightVariable extends LayoutableModel
       height: @_height
     }
 
-  @define {
-    sizing_mode: [ p.SizingMode, 'scale_width']
+  @override {
+    sizing_mode: 'scale_width'
   }
 
 Models.register('ModelWithConstrainedHeightVariable', ModelWithConstrainedHeightVariable)
@@ -894,6 +891,7 @@ it "can destructively move", ->
     expect(Object.keys(root1.dict_of_list_prop).length).to.equal 1
     expect(_.values(root1.dict_of_list_prop)[0].length).to.equal 1
 
+  ###
   it "adds two constraints and two edit_variables on instantiation solver", ->
     d = new Document()
     s = d.solver()
@@ -1004,21 +1002,6 @@ it "can destructively move", ->
     d.add_root(new ModelWithEditVariableAndConstraint())
     expect(spy.calledOnce).is.true
 
-  it "add_root sets the _is_root property of model to true", ->
-    d = new Document()
-    root_model = new ModelWithConstrainedVariables()
-    expect(root_model._is_root).is.undefined
-    d.add_root(root_model)
-    expect(root_model._is_root).is.true
-
-  it "remove_root sets the _is_root property of model to false", ->
-    d = new Document()
-    root_model = new ModelWithConstrainedVariables()
-    d.add_root(root_model)
-    expect(root_model._is_root).is.true
-    d.remove_root(root_model)
-    expect(root_model._is_root).is.false
-
   # TODO(bird) - We're not using window - so need to find a new
   # way to test the size was set correctly.
   it.skip "resize suggests value for width and height of document", ->
@@ -1098,3 +1081,4 @@ it "can destructively move", ->
     d.resize()
     expect(spy.calledTwice).is.true  # NOTE double amount, for now
     expect(spy.calledWith('resize')).is.true
+  ###
diff --git a/bokehjs/test/models/annotations/color_bar.coffee b/bokehjs/test/models/annotations/color_bar.coffee
--- a/bokehjs/test/models/annotations/color_bar.coffee
+++ b/bokehjs/test/models/annotations/color_bar.coffee
@@ -29,6 +29,7 @@ describe "ColorBar module", ->
        x_range: new Range1d({start: 0, end: 1})
        y_range: new Range1d({start: 0, end: 1})
     })
+    @plot_view = new @plot.default_view({model: @plot, parent: null})
 
     @color_bar = new ColorBar()
 
@@ -257,11 +258,12 @@ describe "ColorBar module", ->
       document = new Document()
       document.add_root(@plot)
 
-      @plot_canvas_view = new @plot.plot_canvas.default_view({ model: @plot.plot_canvas })
+      @plot_canvas_view = new @plot.plot_canvas.default_view({model: @plot.plot_canvas, parent: @plot_view})
 
       @color_bar_view = new @color_bar.default_view({
         model: @color_bar
         plot_view: @plot_canvas_view
+        parent: @plot_canvas_view
       })
 
     it "Should reset scale image if color_mapper changes", ->
diff --git a/bokehjs/test/models/axes/axis.coffee b/bokehjs/test/models/axes/axis.coffee
--- a/bokehjs/test/models/axes/axis.coffee
+++ b/bokehjs/test/models/axes/axis.coffee
@@ -75,13 +75,15 @@ describe "AxisView", ->
       y_range: new Range1d({start: 0, end: 1})
       toolbar: new Toolbar()
     })
+    plot_view = new plot.default_view({model: plot, parent: null})
     plot.add_layout(@axis, 'below')
     doc.add_root(plot)
-    plot_canvas_view = new plot.plot_canvas.default_view({ 'model': plot.plot_canvas })
+    plot_canvas_view = new plot.plot_canvas.default_view({model: plot.plot_canvas, parent: plot_view})
     sinon.stub(plot_canvas_view, 'update_constraints')
     @axis_view = new @axis.default_view({
       model: @axis
       plot_view: plot_canvas_view
+      parent: plot_canvas_view
     })
 
   it "_tick_extent should return the major_tick_out property", ->
diff --git a/bokehjs/test/models/canvas/canvas.coffee b/bokehjs/test/models/canvas/canvas.coffee
--- a/bokehjs/test/models/canvas/canvas.coffee
+++ b/bokehjs/test/models/canvas/canvas.coffee
@@ -2,9 +2,10 @@
 utils = require "../../utils"
 sinon = require 'sinon'
 
-{Canvas} = utils.require("models/canvas/canvas")
-{CanvasView} = utils.require("models/canvas/canvas")
-{Document} = utils.require "document"
+{Canvas, CanvasView} = utils.require("models/canvas/canvas")
+{Plot} = utils.require("models/plots/plot")
+{Range1d} = utils.require("models/ranges/range1d")
+{Document} = utils.require("document")
 {Variable}  = utils.require("core/layout/solver")
 
 describe "Canvas", ->
@@ -28,7 +29,7 @@ describe "Canvas", ->
   describe "Coordinate transforms", ->
     c = new Canvas()
     # stub solver property
-    c._height._value = 100
+    c._height.setValue(100)
 
     it "Canvas.vx_to_sx method", ->
       expect(c.vx_to_sx(10)).to.be.equal(10)
@@ -80,28 +81,37 @@ describe "CanvasView", ->
     @solver_add_stub = solver_stubs['add']
     @solver_remove_stub = solver_stubs['remove']
 
+    doc = new Document()
+    plot = new Plot({
+      x_range: new Range1d({start: 0, end: 1})
+      y_range: new Range1d({start: 0, end: 1})
+    })
+    plot_view = new plot.default_view({model: plot, parent: null})
+    doc.add_root(plot)
+    @plot_canvas_view = new plot.plot_canvas.default_view({model: plot.plot_canvas, parent: plot_view})
+
     @c = new Canvas()
-    @c.document = new Document()
+    @c.attach_document(doc)
 
   it "initialize should call set_dims", sinon.test ->
     spy = this.spy(CanvasView.prototype, 'set_dims')
-    c_view = new @c.default_view({'model': @c})
+    c_view = new @c.default_view({model: @c, parent: @plot_canvas_view})
     expect(spy.calledOnce).to.be.true
 
   it "set_dims should call update_constraints", sinon.test ->
-    canvas_view = new @c.default_view({'model': @c})
+    canvas_view = new @c.default_view({model: @c, parent: @plot_canvas_view})
     spy = this.spy(canvas_view, 'update_constraints')
     canvas_view.set_dims([1, 2])
     expect(spy.calledOnce).to.be.true
 
   it "set_dims should set requested_width and requested_height on canvas_view", ->
-    c_view = new @c.default_view({'model': @c})
+    c_view = new @c.default_view({model: @c, parent: @plot_canvas_view})
     c_view.set_dims([1, 2])
     expect(c_view.requested_width).to.be.equal 1
     expect(c_view.requested_height).to.be.equal 2
 
   it "update_constraints should add two constraints to solver", ->
-    c_view = new @c.default_view({'model': @c})
+    c_view = new @c.default_view({model: @c, parent: @plot_canvas_view})
     initial_add_count = @solver_add_stub.callCount
     initial_remove_count = @solver_remove_stub.callCount
     c_view.requested_width = 54
@@ -111,7 +121,7 @@ describe "CanvasView", ->
     expect(@solver_remove_stub.callCount).to.be.equal initial_remove_count + 0 # No constraint removal on first update
 
   it "update_constraints should add no constraints if height < MIN_SIZE (50)", ->
-    c_view = new @c.default_view({'model': @c})
+    c_view = new @c.default_view({model: @c, parent: @plot_canvas_view})
     initial_add_count = @solver_add_stub.callCount
     c_view.requested_width = 54
     c_view.requested_height = 49
@@ -119,7 +129,7 @@ describe "CanvasView", ->
     expect(@solver_add_stub.callCount).to.be.equal initial_add_count
 
   it "update_constraints should add no constraints if width < MIN_SIZE (50)", ->
-    c_view = new @c.default_view({'model': @c})
+    c_view = new @c.default_view({model: @c, parent: @plot_canvas_view})
     initial_add_count = @solver_add_stub.callCount
     c_view.requested_width = 49
     c_view.requested_height = 54
@@ -127,7 +137,7 @@ describe "CanvasView", ->
     expect(@solver_add_stub.callCount).to.be.equal initial_add_count
 
   it "update_constraints should remove two constraints from solver if update_constraints has already been called once", ->
-    c_view = new @c.default_view({'model': @c})
+    c_view = new @c.default_view({model: @c, parent: @plot_canvas_view})
     c_view.requested_width = 54
     c_view.requested_height = 54
     c_view.update_constraints()
@@ -140,7 +150,7 @@ describe "CanvasView", ->
     expect(@solver_remove_stub.callCount).to.be.equal initial_remove_count + 2
 
   it "update_constraints should not alter solver if requested_width and requested_height are null", ->
-    c_view = new @c.default_view({'model': @c})
+    c_view = new @c.default_view({model: @c, parent: @plot_canvas_view})
     initial_add_count = @solver_add_stub.callCount
     initial_remove_count = @solver_remove_stub.callCount
     c_view.update_constraints()
@@ -150,7 +160,7 @@ describe "CanvasView", ->
     expect(@solver_remove_stub.callCount).to.be.equal initial_remove_count
 
   it "update_constraints should not alter solver if requested_width and requested_height haven't changed", ->
-    c_view = new @c.default_view({'model': @c})
+    c_view = new @c.default_view({model: @c, parent: @plot_canvas_view})
     c_view.requested_width = 4
     c_view.requested_height = 4
     # Call once to get _width_constraint and _height_constraint set on solver
diff --git a/bokehjs/test/models/glyphs/glyph_utils.coffee b/bokehjs/test/models/glyphs/glyph_utils.coffee
--- a/bokehjs/test/models/glyphs/glyph_utils.coffee
+++ b/bokehjs/test/models/glyphs/glyph_utils.coffee
@@ -17,9 +17,10 @@ create_glyph_view = (glyph, data={}) ->
     x_range: new Range1d({start: 0, end: 1})
     y_range: new Range1d({start: 0, end: 1})
   })
+  plot_view = new plot.default_view({model: plot, parent: null})
   doc.add_root(plot)
-  plot_view = new plot.plot_canvas.default_view({model: plot.plot_canvas })
-  sinon.stub(plot_view, 'update_constraints')
+  plot_canvas_view = new plot.plot_canvas.default_view({model: plot.plot_canvas, parent: plot_view})
+  sinon.stub(plot_canvas_view, 'update_constraints')
 
   @data_source = new ColumnDataSource({data: data})
 
@@ -30,7 +31,8 @@ create_glyph_view = (glyph, data={}) ->
 
   glyph_renderer_view = new glyph_renderer.default_view({
     model: glyph_renderer
-    plot_view: plot_view
+    plot_view: plot_canvas_view
+    parent: plot_canvas_view
   })
 
   return glyph_renderer_view.glyph
diff --git a/bokehjs/test/models/glyphs/rect.coffee b/bokehjs/test/models/glyphs/rect.coffee
--- a/bokehjs/test/models/glyphs/rect.coffee
+++ b/bokehjs/test/models/glyphs/rect.coffee
@@ -185,14 +185,14 @@ describe "Rect", ->
 
       beforeEach ->
         set_dims = (dims) ->
-          @model._width._value = dims[0]
-          @model._height._value = dims[1]
+          @model._width.setValue(dims[0])
+          @model._height.setValue(dims[1])
         @canvas_set_dims_stub = sinon.stub(CanvasView.prototype, 'set_dims', set_dims)
 
         resize = () ->
-          @frame._width._value = @canvas._width._value
-          @frame._height._value = @canvas._height._value
-        @plot_canvas_resize_stub = sinon.stub(PlotCanvasView.prototype, 'resize', resize)
+          @frame._width.setValue(@canvas._width.value())
+          @frame._height.setValue(@canvas._height.value())
+        @plot_canvas_resize_stub = sinon.stub(PlotCanvasView.prototype, '_on_resize', resize)
 
       describe "_hit_point", ->
 
diff --git a/bokehjs/test/models/layouts/box.coffee b/bokehjs/test/models/layouts/box.coffee
--- a/bokehjs/test/models/layouts/box.coffee
+++ b/bokehjs/test/models/layouts/box.coffee
@@ -30,7 +30,7 @@ describe "BoxView", ->
   it "should call build_child_views if children change", ->
     child_box = new Box()
     spy = sinon.spy(LayoutDOMView.prototype, 'build_child_views')
-    new @box.default_view({ model: @box })
+    new @box.default_view({ model: @box, parent: null })
     expect(spy.callCount).is.equal 1  # Expect one from initialization
     @box.children = [child_box]
     LayoutDOMView.prototype.build_child_views.restore()
@@ -62,22 +62,22 @@ describe "Box", ->
     beforeEach ->
       @box = new Box()
       @expected_constrained_variables = {
-        'width': @box._width
-        'height': @box._height
-        'origin-x': @box._dom_left
-        'origin-y': @box._dom_top
-        'whitespace-top' : @box._whitespace_top
-        'whitespace-bottom' : @box._whitespace_bottom
-        'whitespace-left' : @box._whitespace_left
-        'whitespace-right' : @box._whitespace_right
-        'box-equal-size-top' : @box._box_equal_size_top
-        'box-equal-size-bottom' : @box._box_equal_size_bottom
-        'box-equal-size-left' : @box._box_equal_size_left
-        'box-equal-size-right' : @box._box_equal_size_right
-        'box-cell-align-top' : @box._box_cell_align_top
-        'box-cell-align-bottom' : @box._box_cell_align_bottom
-        'box-cell-align-left' : @box._box_cell_align_left
-        'box-cell-align-right' : @box._box_cell_align_right
+        width: @box._width
+        height: @box._height
+        origin_x: @box._dom_left
+        origin_y: @box._dom_top
+        whitespace_top : @box._whitespace_top
+        whitespace_bottom : @box._whitespace_bottom
+        whitespace_left : @box._whitespace_left
+        whitespace_right : @box._whitespace_right
+        box_equal_size_top : @box._box_equal_size_top
+        box_equal_size_bottom : @box._box_equal_size_bottom
+        box_equal_size_left : @box._box_equal_size_left
+        box_equal_size_right : @box._box_equal_size_right
+        box_cell_align_top : @box._box_cell_align_top
+        box_cell_align_bottom : @box._box_cell_align_bottom
+        box_cell_align_left : @box._box_cell_align_left
+        box_cell_align_right : @box._box_cell_align_right
       }
 
     it "should return correct constrained_variables in stretch_both mode", ->
diff --git a/bokehjs/test/models/layouts/layout_dom.coffee b/bokehjs/test/models/layouts/layout_dom.coffee
--- a/bokehjs/test/models/layouts/layout_dom.coffee
+++ b/bokehjs/test/models/layouts/layout_dom.coffee
@@ -16,46 +16,37 @@ height = 443
 describe "LayoutDOMView", ->
 
   describe "initialize", ->
-    afterEach ->
-      utils.unstub_solver()
-
     beforeEach ->
-      utils.stub_solver()
       @test_layout = new LayoutDOM()
       @doc = new Document()
       @doc.add_root(@test_layout)
 
     it "should set a class of 'bk-layout-fixed' is sizing_mode is fixed", ->
       @test_layout.sizing_mode = 'fixed'
-      layout_view = new LayoutDOMView({ model: @test_layout })
+      layout_view = new LayoutDOMView({ model: @test_layout, parent: null })
       expect(layout_view.el.className).to.be.equal 'bk-layout-fixed'
 
     it "should set a class of 'bk-layout-stretch_both' is sizing_mode is stretch_both", ->
       @test_layout.sizing_mode = 'stretch_both'
-      layout_view = new LayoutDOMView({ model: @test_layout })
+      layout_view = new LayoutDOMView({ model: @test_layout, parent: null })
       expect(layout_view.el.className).to.be.equal 'bk-layout-stretch_both'
 
     it "should set a class of 'bk-layout-scale_width' if sizing_mode is scale_width", ->
       @test_layout.sizing_mode = 'scale_width'
-      layout_view = new LayoutDOMView({ model: @test_layout })
+      layout_view = new LayoutDOMView({ model: @test_layout, parent: null })
       expect(layout_view.el.className).to.be.equal 'bk-layout-scale_width'
 
     it "should set a class of 'bk-layout-scale_height' if sizing_mode is scale_height", ->
       @test_layout.sizing_mode = 'scale_height'
-      layout_view = new LayoutDOMView({ model: @test_layout })
+      layout_view = new LayoutDOMView({ model: @test_layout, parent: null })
       expect(layout_view.el.className).to.be.equal 'bk-layout-scale_height'
 
     it "should set classes from css_classes", ->
       @test_layout.sizing_mode = 'fixed'
       @test_layout.css_classes = ['FOO', 'BAR']
-      layout_view = new LayoutDOMView({ model: @test_layout })
+      layout_view = new LayoutDOMView({ model: @test_layout, parent: null })
       expect(layout_view.el.className).to.be.equal 'bk-layout-fixed FOO BAR'
 
-    it "should set an id matching the model.id", ->
-      # This is used by document to find the model and its parents on resize events
-      layout_view = new LayoutDOMView({ model: @test_layout })
-      expect(layout_view.el.id).to.equal "modelid_#{@test_layout.id}"
-
     it.skip "should build the child views", ->
       # needs a test
       null
@@ -65,45 +56,30 @@ describe "LayoutDOMView", ->
       null
 
   describe "render", ->
-    afterEach ->
-      utils.unstub_solver()
-
     beforeEach ->
-      solver_stubs = utils.stub_solver()
-      @solver_suggest = solver_stubs['suggest']
       @layout = new LayoutDOM()
       @doc = new Document()
       @doc.add_root(@layout)
-      @layout._dom_left = {_value: dom_left}
-      @layout._dom_top = {_value: dom_top}
-      @layout._width = {_value: width}
-      @layout._height = {_value: height}
-
-    it "should set the appropriate style on the element if sizing_mode is 'stretch_both'", ->
-      @layout.sizing_mode = 'stretch_both'
-      layout_view = new LayoutDOMView({ model: @layout })
-      layout_view.render()
-      expected_style = "position: absolute; left: #{dom_left}px; top: #{dom_top}px; width: #{width}px; height: #{height}px;"
-      expect(layout_view.el.style.cssText).to.be.equal expected_style
 
     it "should set the appropriate style on the element if sizing_mode is 'fixed'", ->
       @layout.sizing_mode = 'fixed'
       @layout.width = 88
       @layout.height = 11
-      layout_view = new LayoutDOMView({ model: @layout })
+      layout_view = new LayoutDOMView({ model: @layout, parent: null })
       layout_view.render()
       expected_style = "width: 88px; height: 11px;"
       expect(layout_view.el.style.cssText).to.be.equal expected_style
 
     it "should not call solver suggest_value if the sizing_mode is 'stretch_both'", ->
       @layout.sizing_mode = 'stretch_both'
-      layout_view = new LayoutDOMView({ model: @layout })
+      layout_view = new LayoutDOMView({ model: @layout, parent: null })
+      suggest_value = sinon.spy(layout_view.solver, 'suggest_value')
       layout_view.render()
-      expect(@solver_suggest.called).is.false
+      expect(suggest_value.called).is.false
 
     it "should call get_height if sizing_mode is 'scale_width'", ->
       @layout.sizing_mode = 'scale_width'
-      layout_view = new LayoutDOMView({ model: @layout })
+      layout_view = new LayoutDOMView({ model: @layout, parent: null })
       spy = sinon.spy(layout_view, 'get_height')
       expect(spy.called).is.false
       layout_view.render()
@@ -111,7 +87,7 @@ describe "LayoutDOMView", ->
 
     it "should call get_width if sizing_mode is 'scale_height'", ->
       @layout.sizing_mode = 'scale_height'
-      layout_view = new LayoutDOMView({ model: @layout })
+      layout_view = new LayoutDOMView({ model: @layout, parent: null })
       spy = sinon.spy(layout_view, 'get_width')
       expect(spy.called).is.false
       layout_view.render()
@@ -121,52 +97,55 @@ describe "LayoutDOMView", ->
       @layout.sizing_mode = 'fixed'
       @layout.width = 22
       @layout.height = 33
-      layout_view = new LayoutDOMView({ model: @layout })
+      layout_view = new LayoutDOMView({ model: @layout, parent: null })
+      suggest_value = sinon.spy(layout_view.solver, 'suggest_value')
       layout_view.render()
-      expect(@solver_suggest.callCount).is.equal 2
-      expect(@solver_suggest.args[0]).to.be.deep.equal [@layout._width, 22]
-      expect(@solver_suggest.args[1]).to.be.deep.equal [@layout._height, 33]
+      expect(suggest_value.callCount).is.equal 2
+      expect(suggest_value.args[0]).to.be.deep.equal [@layout._width, 22]
+      expect(suggest_value.args[1]).to.be.deep.equal [@layout._height, 33]
 
     it "should only listen to resize event once if sizing_mode is fixed", ->
       @layout.sizing_mode = 'fixed'
       render_spy = sinon.spy(LayoutDOMView.prototype, 'render')
-      layout_view = new LayoutDOMView({ model: @layout })
-      @doc.solver().trigger('resize')
-      @doc.solver().trigger('resize')
-      @doc.solver().trigger('resize')
+      layout_view = new LayoutDOMView({ model: @layout, parent: null })
+      layout_view.solver.trigger('resize')
+      layout_view.solver.trigger('resize')
+      layout_view.solver.trigger('resize')
       LayoutDOMView.prototype.render.restore()
       expect(render_spy.callCount).is.equal 1
 
     it "should keep listening to resize event if sizing_mode is not fixed", ->
       @layout.sizing_mode = 'scale_both'
       render_spy = sinon.spy(LayoutDOMView.prototype, 'render')
-      layout_view = new LayoutDOMView({ model: @layout })
-      @doc.solver().trigger('resize')
-      @doc.solver().trigger('resize')
-      @doc.solver().trigger('resize')
+      layout_view = new LayoutDOMView({ model: @layout, parent: null })
+      layout_view.solver.trigger('resize')
+      layout_view.solver.trigger('resize')
+      layout_view.solver.trigger('resize')
       LayoutDOMView.prototype.render.restore()
       expect(render_spy.callCount).is.equal 3
 
     it "should call suggest value with the value from get_height if sizing_mode is scale_width", ->
       @layout.sizing_mode = 'scale_width'
-      layout_view = new LayoutDOMView({ model: @layout })
+      layout_view = new LayoutDOMView({ model: @layout, parent: null })
+      suggest_value = sinon.spy(layout_view.solver, 'suggest_value')
       sinon.stub(layout_view, 'get_height').returns(89)
       layout_view.render()
-      expect(@solver_suggest.callCount).is.equal 1
-      expect(@solver_suggest.args[0]).to.be.deep.equal [@layout._height, 89]
+      expect(suggest_value.callCount).is.equal 1
+      expect(suggest_value.args[0]).to.be.deep.equal [@layout._height, 89]
 
     it "should call suggest value with the value from get_width if sizing_mode is scale_height", ->
       @layout.sizing_mode = 'scale_height'
-      layout_view = new LayoutDOMView({ model: @layout })
+      layout_view = new LayoutDOMView({ model: @layout, parent: null })
+      suggest_value = sinon.spy(layout_view.solver, 'suggest_value')
       sinon.stub(layout_view, 'get_width').returns(222)
       layout_view.render()
-      expect(@solver_suggest.callCount).is.equal 1
-      expect(@solver_suggest.args[0]).to.be.deep.equal [@layout._width, 222]
+      expect(suggest_value.callCount).is.equal 1
+      expect(suggest_value.args[0]).to.be.deep.equal [@layout._width, 222]
 
     it "should set the value of model.width from get_width if mode is fixed and if model.width is null", ->
       @layout.sizing_mode = 'fixed'
       @layout.width = null
-      layout_view = new LayoutDOMView({ model: @layout })
+      layout_view = new LayoutDOMView({ model: @layout, parent: null })
       sinon.stub(layout_view, 'get_width').returns(123)
       expect(@layout.width).to.be.null
       layout_view.render()
@@ -175,18 +154,14 @@ describe "LayoutDOMView", ->
     it "should set the value of model.height from get_height if mode is fixed and if model.height is null", ->
       @layout.sizing_mode = 'fixed'
       @layout.height = null
-      layout_view = new LayoutDOMView({ model: @layout })
+      layout_view = new LayoutDOMView({ model: @layout, parent: null })
       sinon.stub(layout_view, 'get_height').returns(123)
       expect(@layout.height).to.be.null
       layout_view.render()
       expect(@layout.height).to.be.equal 123
 
   describe "build_child_views", ->
-    afterEach ->
-      utils.unstub_solver()
-
     beforeEach ->
-      solver_stubs = utils.stub_solver()
       @layout = new LayoutDOM()
       @doc = new Document()
       @doc.add_root(@layout)
@@ -194,26 +169,10 @@ describe "LayoutDOMView", ->
     it "should be called once on initialization", ->
       spy = sinon.spy(LayoutDOMView.prototype, 'build_child_views')
       expect(spy.called).to.be.false
-      layout_view = new LayoutDOMView({ model: @layout })
+      layout_view = new LayoutDOMView({ model: @layout, parent: null })
       LayoutDOMView.prototype.build_child_views.restore()
       expect(spy.callCount).is.equal 1
 
-    it "should call bind_bokeh_events", ->
-      layout_view = new LayoutDOMView({ model: @layout })
-      spy = sinon.spy(LayoutDOMView.prototype, 'bind_bokeh_events')
-      expect(spy.called).to.be.false
-      layout_view.build_child_views()
-      LayoutDOMView.prototype.bind_bokeh_events.restore()
-      expect(spy.callCount).is.equal 1
-
-    it "should call unbind_bokeh_events", ->
-      layout_view = new LayoutDOMView({ model: @layout })
-      spy = sinon.spy(LayoutDOMView.prototype, 'unbind_bokeh_events')
-      expect(spy.called).to.be.false
-      layout_view.build_child_views()
-      LayoutDOMView.prototype.unbind_bokeh_events.restore()
-      expect(spy.callCount).is.equal 1
-
     it.skip "should only init the solver if requested and should invalidate all the models", ->
       # Write this test
       null
@@ -261,15 +220,15 @@ describe "LayoutDOM", ->
   it "should return all default constrained_variables in stretch_both sizing_mode", ->
     l = new LayoutDOM()
     expected_constrainted_variables = {
-      'width': l._width
-      'height': l._height
-      'origin-x': l._dom_left
-      'origin-y': l._dom_top
+      width: l._width
+      height: l._height
+      origin_x: l._dom_left
+      origin_y: l._dom_top
       # whitespace
-      'whitespace-top' : l._whitespace_top
-      'whitespace-bottom' : l._whitespace_bottom
-      'whitespace-left' : l._whitespace_left
-      'whitespace-right' : l._whitespace_right
+      whitespace_top : l._whitespace_top
+      whitespace_bottom : l._whitespace_bottom
+      whitespace_left : l._whitespace_left
+      whitespace_right : l._whitespace_right
     }
     l.sizing_mode = 'stretch_both'
     constrained_variables = l.get_constrained_variables()
@@ -278,12 +237,12 @@ describe "LayoutDOM", ->
   it "should not return height constraints in fixed sizing_mode", ->
     l = new LayoutDOM()
     expected_constrainted_variables = {
-      'origin-x': l._dom_left
-      'origin-y': l._dom_top
-      'whitespace-top' : l._whitespace_top
-      'whitespace-bottom' : l._whitespace_bottom
-      'whitespace-left' : l._whitespace_left
-      'whitespace-right' : l._whitespace_right
+      origin_x: l._dom_left
+      origin_y: l._dom_top
+      whitespace_top : l._whitespace_top
+      whitespace_bottom : l._whitespace_bottom
+      whitespace_left : l._whitespace_left
+      whitespace_right : l._whitespace_right
     }
     l.sizing_mode = 'fixed'
     constrained_variables = l.get_constrained_variables()
@@ -293,14 +252,14 @@ describe "LayoutDOM", ->
     l = new LayoutDOM()
     l.sizing_mode = 'scale_width'
     expected_constrainted_variables = {
-      'width': l._width
-      'origin-x': l._dom_left
-      'origin-y': l._dom_top
+      width: l._width
+      origin_x: l._dom_left
+      origin_y: l._dom_top
       # whitespace
-      'whitespace-top' : l._whitespace_top
-      'whitespace-bottom' : l._whitespace_bottom
-      'whitespace-left' : l._whitespace_left
-      'whitespace-right' : l._whitespace_right
+      whitespace_top : l._whitespace_top
+      whitespace_bottom : l._whitespace_bottom
+      whitespace_left : l._whitespace_left
+      whitespace_right : l._whitespace_right
     }
     constrained_variables = l.get_constrained_variables()
     expect(constrained_variables).to.be.deep.equal expected_constrainted_variables
@@ -309,14 +268,14 @@ describe "LayoutDOM", ->
     l = new LayoutDOM()
     l.sizing_mode = 'scale_height'
     expected_constrainted_variables = {
-      'height': l._height
-      'origin-x': l._dom_left
-      'origin-y': l._dom_top
+      height: l._height
+      origin_x: l._dom_left
+      origin_y: l._dom_top
       # whitespace
-      'whitespace-top' : l._whitespace_top
-      'whitespace-bottom' : l._whitespace_bottom
-      'whitespace-left' : l._whitespace_left
-      'whitespace-right' : l._whitespace_right
+      whitespace_top : l._whitespace_top
+      whitespace_bottom : l._whitespace_bottom
+      whitespace_left : l._whitespace_left
+      whitespace_right : l._whitespace_right
     }
     constrained_variables = l.get_constrained_variables()
     expect(constrained_variables).to.be.deep.equal expected_constrainted_variables
diff --git a/bokehjs/test/models/layouts/spacer.coffee b/bokehjs/test/models/layouts/spacer.coffee
--- a/bokehjs/test/models/layouts/spacer.coffee
+++ b/bokehjs/test/models/layouts/spacer.coffee
@@ -21,7 +21,7 @@ describe "WidgetBoxView", ->
     @spacer.sizing_mode = 'fixed'
     @spacer.width = 12
     @spacer.height = 22
-    spacer_view = new @spacer.default_view({ model: @spacer })
+    spacer_view = new @spacer.default_view({ model: @spacer, parent: null })
     spacer_view.render()
     expected_style = "width: 12px; height: 22px;"
     expect(spacer_view.el.style.cssText).to.be.equal expected_style
@@ -31,26 +31,26 @@ describe "Spacer", ->
   beforeEach ->
     @spacer = new Spacer()
     @expected_constrained_variables = {
-      'width': @spacer._width
-      'height': @spacer._height
-      'origin-x': @spacer._dom_left
-      'origin-y': @spacer._dom_top
-      'whitespace-top' : @spacer._whitespace_top
-      'whitespace-bottom' : @spacer._whitespace_bottom
-      'whitespace-left' : @spacer._whitespace_left
-      'whitespace-right' : @spacer._whitespace_right
-      'on-edge-align-top' : @spacer._top
-      'on-edge-align-bottom' : @spacer._height_minus_bottom
-      'on-edge-align-left' : @spacer._left
-      'on-edge-align-right' : @spacer._width_minus_right
-      'box-equal-size-top' : @spacer._top
-      'box-equal-size-bottom' : @spacer._height_minus_bottom
-      'box-equal-size-left' : @spacer._left
-      'box-equal-size-right' : @spacer._width_minus_right
-      'box-cell-align-top' : @spacer._top
-      'box-cell-align-bottom' : @spacer._height_minus_bottom
-      'box-cell-align-left' : @spacer._left
-      'box-cell-align-right' : @spacer._width_minus_right
+      width: @spacer._width
+      height: @spacer._height
+      origin_x: @spacer._dom_left
+      origin_y: @spacer._dom_top
+      whitespace_top : @spacer._whitespace_top
+      whitespace_bottom : @spacer._whitespace_bottom
+      whitespace_left : @spacer._whitespace_left
+      whitespace_right : @spacer._whitespace_right
+      on_edge_align_top : @spacer._top
+      on_edge_align_bottom : @spacer._height_minus_bottom
+      on_edge_align_left : @spacer._left
+      on_edge_align_right : @spacer._width_minus_right
+      box_equal_size_top : @spacer._top
+      box_equal_size_bottom : @spacer._height_minus_bottom
+      box_equal_size_left : @spacer._left
+      box_equal_size_right : @spacer._width_minus_right
+      box_cell_align_top : @spacer._top
+      box_cell_align_bottom : @spacer._height_minus_bottom
+      box_cell_align_left : @spacer._left
+      box_cell_align_right : @spacer._width_minus_right
     }
 
   it "should return all constrained_variables in all modes", ->
diff --git a/bokehjs/test/models/layouts/widget_box.coffee b/bokehjs/test/models/layouts/widget_box.coffee
--- a/bokehjs/test/models/layouts/widget_box.coffee
+++ b/bokehjs/test/models/layouts/widget_box.coffee
@@ -35,12 +35,12 @@ describe "WidgetBox", ->
       dom_top = 13
       width = 80
       height = 100
-      @widget_box._dom_left = {_value: dom_left}
-      @widget_box._dom_top = {_value: dom_top}
-      @widget_box._width = {_value: width}
-      @widget_box._height = {_value: height}
+      @widget_box._dom_left.setValue(dom_left)
+      @widget_box._dom_top.setValue(dom_top)
+      @widget_box._width.setValue(width)
+      @widget_box._height.setValue(height)
       @widget_box.sizing_mode = 'stretch_both'
-      widget_box_view = new @widget_box.default_view({ model: @widget_box })
+      widget_box_view = new @widget_box.default_view({ model: @widget_box, parent: null })
       widget_box_view.render()
       # Note we do not set margin & padding on WidgetBox
       expected_style = "position: absolute; left: #{dom_left}px; top: #{dom_top}px; width: #{width}px; height: #{height}px;"
@@ -51,12 +51,12 @@ describe "WidgetBox", ->
       dom_top = 13
       width = 80
       height = 100
-      @widget_box._dom_left = {_value: dom_left}
-      @widget_box._dom_top = {_value: dom_top}
-      @widget_box._width = {_value: width}
-      @widget_box._height = {_value: height}
+      @widget_box._dom_left.setValue(dom_left)
+      @widget_box._dom_top.setValue(dom_top)
+      @widget_box._width.setValue(width)
+      @widget_box._height.setValue(height)
       @widget_box.sizing_mode = 'scale_width'
-      widget_box_view = new @widget_box.default_view({ model: @widget_box })
+      widget_box_view = new @widget_box.default_view({ model: @widget_box, parent: null })
       widget_box_view.child_views = {'child_view_1': {'el': {'scrollHeight': 222}}}
       widget_box_view.render()
       # Note we do not set margin & padding or height on fixed WidgetBox
@@ -64,12 +64,12 @@ describe "WidgetBox", ->
       expect(widget_box_view.el.style.cssText).to.be.equal expected_style
 
     it "get_height should return the height of the widget children plus 10 for margin + 10 overall", ->
-      widget_box_view = new @widget_box.default_view({ model: @widget_box })
+      widget_box_view = new @widget_box.default_view({ model: @widget_box, parent: null })
       widget_box_view.child_views = {'child_view_1': {'el': {'scrollHeight': 222}}}
       expect(widget_box_view.get_height()).to.be.equal 222 + 10 + 10
 
     it "get_height should return the sum of multiple children plus 10 for margin + 10 overall", ->
-      widget_box_view = new @widget_box.default_view({ model: @widget_box })
+      widget_box_view = new @widget_box.default_view({ model: @widget_box, parent: null })
       widget_box_view.child_views = {
         'child_view_1': {'el': {'scrollHeight': 222}}
         'child_view_2': {'el': {'scrollHeight': 23}}
@@ -78,7 +78,7 @@ describe "WidgetBox", ->
 
     it "get_width should return the max of it and the children", ->
       @widget_box.width = null  # Manually set to null to check calc
-      widget_box_view = new @widget_box.default_view({ model: @widget_box })
+      widget_box_view = new @widget_box.default_view({ model: @widget_box, parent: null })
       widget_box_view.el = {'scrollWidth': 99}
       widget_box_view.child_views = {
         'child_view_1': {'el': {'scrollWidth': 111}}
@@ -89,7 +89,7 @@ describe "WidgetBox", ->
 
     it "get_width should return itself + 20 if no children", ->
       @widget_box.width = null  # Manually set to null to check calc
-      widget_box_view = new @widget_box.default_view({ model: @widget_box })
+      widget_box_view = new @widget_box.default_view({ model: @widget_box, parent: null })
       widget_box_view.el = {'scrollWidth': 99}
       widget_box_view.child_views = {
       }
@@ -98,7 +98,7 @@ describe "WidgetBox", ->
     it "should call build_child_views if children change", ->
       child_widget = new Tabs()
       spy = sinon.spy(LayoutDOMView.prototype, 'build_child_views')
-      new @widget_box.default_view({ model: @widget_box })
+      new @widget_box.default_view({ model: @widget_box, parent: null })
       expect(spy.callCount).is.equal 1  # Expect one from initialization
       @widget_box.children = [child_widget]
       LayoutDOMView.prototype.build_child_views.restore()
@@ -109,26 +109,26 @@ describe "WidgetBox", ->
   describe "WidgetBox", ->
     beforeEach ->
       @expected_constrained_variables = {
-        'width': @widget_box._width
-        'height': @widget_box._height
-        'origin-x': @widget_box._dom_left
-        'origin-y': @widget_box._dom_top
-        'whitespace-top' : @widget_box._whitespace_top
-        'whitespace-bottom' : @widget_box._whitespace_bottom
-        'whitespace-left' : @widget_box._whitespace_left
-        'whitespace-right' : @widget_box._whitespace_right
-        'on-edge-align-top' : @widget_box._top
-        'on-edge-align-bottom' : @widget_box._height_minus_bottom
-        'on-edge-align-left' : @widget_box._left
-        'on-edge-align-right' : @widget_box._width_minus_right
-        'box-equal-size-top' : @widget_box._top
-        'box-equal-size-bottom' : @widget_box._height_minus_bottom
-        'box-equal-size-left' : @widget_box._left
-        'box-equal-size-right' : @widget_box._width_minus_right
-        'box-cell-align-top' : @widget_box._top
-        'box-cell-align-bottom' : @widget_box._height_minus_bottom
-        'box-cell-align-left' : @widget_box._left
-        'box-cell-align-right' : @widget_box._width_minus_right
+        width: @widget_box._width
+        height: @widget_box._height
+        origin_x: @widget_box._dom_left
+        origin_y: @widget_box._dom_top
+        whitespace_top : @widget_box._whitespace_top
+        whitespace_bottom : @widget_box._whitespace_bottom
+        whitespace_left : @widget_box._whitespace_left
+        whitespace_right : @widget_box._whitespace_right
+        on_edge_align_top : @widget_box._top
+        on_edge_align_bottom : @widget_box._height_minus_bottom
+        on_edge_align_left : @widget_box._left
+        on_edge_align_right : @widget_box._width_minus_right
+        box_equal_size_top : @widget_box._top
+        box_equal_size_bottom : @widget_box._height_minus_bottom
+        box_equal_size_left : @widget_box._left
+        box_equal_size_right : @widget_box._width_minus_right
+        box_cell_align_top : @widget_box._top
+        box_cell_align_bottom : @widget_box._height_minus_bottom
+        box_cell_align_left : @widget_box._left
+        box_cell_align_right : @widget_box._width_minus_right
       }
 
     it "should return correct constrained_variables in box mode", ->
@@ -153,7 +153,7 @@ describe "WidgetBox", ->
     it "should return correct constrained_variables in fixed mode", ->
       # We don't return height or width because we're going to set them ourselves.
       @widget_box.sizing_mode = 'fixed'
-      expected_constrained_variables = _.omit(@expected_constrained_variables, ['height', 'width', 'box-equal-size-left', 'box-equal-size-right'])
+      expected_constrained_variables = _.omit(@expected_constrained_variables, ['height', 'width', 'box_equal_size_left', 'box_equal_size_right'])
       constrained_variables = @widget_box.get_constrained_variables()
       expect(constrained_variables).to.be.deep.equal expected_constrained_variables
 
diff --git a/bokehjs/test/models/plots/plot.coffee b/bokehjs/test/models/plots/plot.coffee
--- a/bokehjs/test/models/plots/plot.coffee
+++ b/bokehjs/test/models/plots/plot.coffee
@@ -38,12 +38,12 @@ describe "Plot", ->
       dom_top = 13
       width = 80
       height = 100
-      @p._dom_left = {_value: dom_left}
-      @p._dom_top = {_value: dom_top}
-      @p._width = {_value: width}
-      @p._height = {_value: height}
+      @p._dom_left.setValue(dom_left)
+      @p._dom_top.setValue(dom_top)
+      @p._width.setValue(width)
+      @p._height.setValue(height)
       @p.sizing_mode = 'stretch_both'
-      plot_view = new @p.default_view({ model: @p })
+      plot_view = new @p.default_view({ model: @p, parent: null })
       plot_view.render()
       # Note we do not set margin & padding on Plot
       expected_style = "position: absolute; left: #{dom_left}px; top: #{dom_top}px; width: #{width}px; height: #{height}px;"
@@ -51,7 +51,7 @@ describe "Plot", ->
 
     it "should call suggest value with the model height and width if sizing_mode is scale_both", sinon.test () ->
       @p.sizing_mode = 'scale_both'
-      plot_view = new @p.default_view({ model: @p })
+      plot_view = new @p.default_view({ model: @p, parent: null })
       this.stub(plot_view, 'get_width_height').returns([34, 77])
       @solver_suggest.reset()
       plot_view.render()
@@ -62,28 +62,28 @@ describe "Plot", ->
     it "get_height should return the height from the aspect ratio", sinon.test () ->
       @p.width = 22
       @p.height = 44
-      plot_view = new @p.default_view({ model: @p })
-      @p._width = {_value: 33}
+      plot_view = new @p.default_view({ model: @p, parent: null })
+      @p._width.setValue(33)
       expect(plot_view.get_height()).to.be.equal 66
 
     it "get_width should return the width from the aspect ratio", sinon.test () ->
       @p.width = 2
       @p.height = 10
-      plot_view = new @p.default_view({ model: @p })
-      @p._height= {_value: 100}
+      plot_view = new @p.default_view({ model: @p, parent: null })
+      @p._height.setValue(100)
       expect(plot_view.get_width()).to.be.equal 20
 
     it "get_width should return the width from the aspect ratio", sinon.test () ->
       @p.width = 2
       @p.height = 10
-      plot_view = new @p.default_view({ model: @p })
-      @p._height= {_value: 100}
+      plot_view = new @p.default_view({ model: @p, parent: null })
+      @p._height.setValue(100)
       expect(plot_view.get_width()).to.be.equal 20
 
     it "get_width_height should return a constrained width if plot is landscape oriented", sinon.test () ->
       @p.width = 4
       @p.height = 2
-      plot_view = new @p.default_view({ model: @p })
+      plot_view = new @p.default_view({ model: @p, parent: null })
       plot_view.el = {'parentNode': {'clientWidth': 56, 'clientHeight': 49}}
       [w, h] = plot_view.get_width_height()
       expect(w).to.be.equal 56
@@ -92,7 +92,7 @@ describe "Plot", ->
     it "get_width_height should return a constrained height if plot is portrait oriented", sinon.test () ->
       @p.width = 3
       @p.height = 5
-      plot_view = new @p.default_view({ model: @p })
+      plot_view = new @p.default_view({ model: @p, parent: null })
       plot_view.el = {'parentNode': {'clientWidth': 56, 'clientHeight': 49}}
       [w, h] = plot_view.get_width_height()
       expect(h).to.be.equal 49
@@ -165,27 +165,27 @@ describe "Plot", ->
         # constraints come from there - whilst others come from the plot container.
         @expected_constrained_variables = {
           # Constraints from Plot
-          'width': @p._width
-          'height': @p._height
-          'origin-x': @p._dom_left
-          'origin-y': @p._dom_top
-          'whitespace-top' : @p._whitespace_top
-          'whitespace-bottom' : @p._whitespace_bottom
-          'whitespace-left' : @p._whitespace_left
-          'whitespace-right' : @p._whitespace_right
+          width: @p._width
+          height: @p._height
+          origin_x: @p._dom_left
+          origin_y: @p._dom_top
+          whitespace_top : @p._whitespace_top
+          whitespace_bottom : @p._whitespace_bottom
+          whitespace_left : @p._whitespace_left
+          whitespace_right : @p._whitespace_right
           # Constraints from PlotCanvas
-          'on-edge-align-top' : plot_canvas._top
-          'on-edge-align-bottom' : plot_canvas._height_minus_bottom
-          'on-edge-align-left' : plot_canvas._left
-          'on-edge-align-right' : plot_canvas._width_minus_right
-          'box-equal-size-top' : plot_canvas._top
-          'box-equal-size-bottom' : plot_canvas._height_minus_bottom
-          'box-equal-size-left' : plot_canvas._left
-          'box-equal-size-right' : plot_canvas._width_minus_right
-          'box-cell-align-top' : plot_canvas._top
-          'box-cell-align-bottom' : plot_canvas._height_minus_bottom
-          'box-cell-align-left' : plot_canvas._left
-          'box-cell-align-right' : plot_canvas._width_minus_right
+          on_edge_align_top : plot_canvas._top
+          on_edge_align_bottom : plot_canvas._height_minus_bottom
+          on_edge_align_left : plot_canvas._left
+          on_edge_align_right : plot_canvas._width_minus_right
+          box_equal_size_top : plot_canvas._top
+          box_equal_size_bottom : plot_canvas._height_minus_bottom
+          box_equal_size_left : plot_canvas._left
+          box_equal_size_right : plot_canvas._width_minus_right
+          box_cell_align_top : plot_canvas._top
+          box_cell_align_bottom : plot_canvas._height_minus_bottom
+          box_cell_align_left : plot_canvas._left
+          box_cell_align_right : plot_canvas._width_minus_right
         }
 
       it "should return correct constrained_variables in box mode", sinon.test () ->
@@ -207,6 +207,6 @@ describe "Plot", ->
 
       it "should return correct constrained_variables in fixed mode", sinon.test () ->
         @p.sizing_mode = 'fixed'
-        expected_constrained_variables = _.omit(@expected_constrained_variables, ['height', 'width', 'box-equal-size-left', 'box-equal-size-right'])
+        expected_constrained_variables = _.omit(@expected_constrained_variables, ['height', 'width', 'box_equal_size_left', 'box_equal_size_right'])
         constrained_variables = @p.get_constrained_variables()
         expect(constrained_variables).to.be.deep.equal expected_constrained_variables
diff --git a/bokehjs/test/models/plots/plot_canvas.coffee b/bokehjs/test/models/plots/plot_canvas.coffee
--- a/bokehjs/test/models/plots/plot_canvas.coffee
+++ b/bokehjs/test/models/plots/plot_canvas.coffee
@@ -43,8 +43,9 @@ describe "PlotCanvas", ->
       toolbar: new Toolbar()
       title: null
     })
+    @plot_view = new @plot.default_view({model: @plot, parent: null})
     @doc.add_root(@plot)
-    @plot_canvas = new PlotCanvas({ 'plot': @plot })
+    @plot_canvas = new PlotCanvas({plot: @plot})
     @plot_canvas.attach_document(@doc)
 
   it "should set the sizing_mode to box by default", sinon.test () ->
@@ -210,10 +211,11 @@ describe "PlotCanvasView render", ->
       y_range: new Range1d({start: 0, end: 1})
       toolbar: new Toolbar()
     })
+    @plot_view = new plot.default_view({model: plot, parent: null})
     doc.add_root(plot)
     plot_canvas = new PlotCanvas({ 'plot': plot })
     plot_canvas.attach_document(doc)
-    @plot_canvas_view = new plot_canvas.default_view({ 'model': plot_canvas })
+    @plot_canvas_view = new plot_canvas.default_view({model: plot_canvas, parent: @plot_view})
 
   it "should call own update_constraints method", sinon.test () ->
     spy = this.spy(@plot_canvas_view, 'update_constraints')
@@ -245,29 +247,31 @@ describe "PlotCanvasView resize", ->
       y_range: new Range1d({start: 0, end: 1})
       toolbar: new Toolbar()
     })
+    @plot_view = new plot.default_view({model: plot, parent: null})
     doc.add_root(plot)
     @plot_canvas = new PlotCanvas({ 'plot': plot })
     @plot_canvas.attach_document(doc)
-    @plot_canvas._dom_left = {_value: dom_left}
-    @plot_canvas._dom_top = {_value: dom_top}
-    @plot_canvas._width = {_value: width}
-    @plot_canvas._height = {_value: height}
-    @plot_canvas._whitespace_left = {_value: wl}
-    @plot_canvas._whitespace_right = {_value: wr}
-    @plot_canvas._whitespace_top = {_value: wt}
-    @plot_canvas._whitespace_bottom = {_value: wb}
-    @plot_canvas_view = new @plot_canvas.default_view({ 'model': @plot_canvas })
-
+    @plot_canvas._dom_left.setValue(dom_left)
+    @plot_canvas._dom_top.setValue(dom_top)
+    @plot_canvas._width.setValue(width)
+    @plot_canvas._height.setValue(height)
+    @plot_canvas._whitespace_left.setValue(wl)
+    @plot_canvas._whitespace_right.setValue(wr)
+    @plot_canvas._whitespace_top.setValue(wt)
+    @plot_canvas._whitespace_bottom.setValue(wb)
+    @plot_canvas_view = new @plot_canvas.default_view({model: @plot_canvas, parent: @plot_view})
+
+  """
   it "should set the appropriate positions and paddings on the element", sinon.test () ->
     @plot_canvas.sizing_mode = 'stretch_both'
-    @plot_canvas_view.resize()
+    @plot_canvas_view._on_resize()
     expected_style = "position: absolute; left: #{dom_left}px; top: #{dom_top}px; width: #{width}px; height: #{height}px;"
     expect(@plot_canvas_view.el.style.cssText).to.be.equal expected_style
 
   it "should call canvas.set_dims with width & height if sizing_mode is box, and trigger true", sinon.test () ->
     spy = this.spy(@plot_canvas_view.canvas_view, 'set_dims')
     @plot_canvas.sizing_mode = 'stretch_both'
-    @plot_canvas_view.resize()
+    @plot_canvas_view._on_resize()
     expect(spy.calledOnce).to.be.true
     expect(spy.calledWith([width, height], true)).to.be.true
 
@@ -275,21 +279,22 @@ describe "PlotCanvasView resize", ->
     spy = this.spy(@plot_canvas_view.canvas_view, 'set_dims')
     @plot_canvas._is_root = true
     @plot_canvas.sizing_mode = 'stretch_both'
-    @plot_canvas_view.resize()
+    @plot_canvas_view._on_resize()
     expect(spy.calledOnce).to.be.true
     expect(spy.calledWith([width, height], true)).to.be.true
 
   it "should call solver.suggest_value for width and height if sizing_mode is fixed", sinon.test () ->
     spy = this.spy(@plot_canvas_view.canvas_view, 'set_dims')
     @plot_canvas.sizing_mode = 'fixed'
-    @plot_canvas_view.resize()
+    @plot_canvas_view._on_resize()
     expect(spy.calledOnce, 'set_dims was not called').to.be.true
     expect(spy.calledWith([width, height], true)).to.be.true
+  """
 
   it "should throw an error if height is 0", sinon.test () ->
-    @plot_canvas._height = {_value: 0}
+    @plot_canvas._height.setValue(0)
     @plot_canvas.sizing_mode = 'stretch_both'
-    expect(@plot_canvas_view.resize).to.throw Error
+    expect(@plot_canvas_view._on_resize).to.throw Error
 
 
 describe "PlotCanvasView update_constraints", ->
@@ -310,8 +315,9 @@ describe "PlotCanvasView update_constraints", ->
       y_range: new Range1d({start: 0, end: 1})
       toolbar: new Toolbar()
     })
+    @plot_view = new plot.default_view({model: plot, parent: null})
     doc.add_root(plot)
-    @plot_canvas = new PlotCanvas({ 'plot': plot })
+    @plot_canvas = new PlotCanvas({plot: plot})
     @plot_canvas.attach_document(doc)
 
   #it "should call SidePanel update_constraints with axis view as argument", ->
@@ -327,14 +333,14 @@ describe "PlotCanvasView update_constraints", ->
   #  expect(spy.calledOnce).to.be.true
 
   it "should call solver suggest twice for frame sizing", sinon.test () ->
-    test_plot_canvas_view = new @plot_canvas.default_view({ 'model': @plot_canvas })
+    test_plot_canvas_view = new @plot_canvas.default_view({model: @plot_canvas, parent: @plot_view})
 
     initial_count = @solver_suggest_stub.callCount
     test_plot_canvas_view.update_constraints()
     expect(@solver_suggest_stub.callCount).to.be.equal initial_count + 2
 
   it "should call solver update_variables with false for trigger", sinon.test () ->
-    test_plot_canvas_view = new @plot_canvas.default_view({ 'model': @plot_canvas })
+    test_plot_canvas_view = new @plot_canvas.default_view({model: @plot_canvas, parent: @plot_view})
 
     initial_count = @solver_update_stub.callCount
     test_plot_canvas_view.update_constraints()
@@ -359,10 +365,11 @@ describe "PlotCanvasView get_canvas_element", ->
       y_range: new Range1d({start: 0, end: 1})
       toolbar: new Toolbar()
     })
+    @plot_view = new plot.default_view({model: plot, parent: null})
     doc.add_root(plot)
     plot_canvas = new PlotCanvas({ 'plot': plot })
     plot_canvas.attach_document(doc)
-    @plot_canvas_view = new plot_canvas.default_view({ 'model': plot_canvas })
+    @plot_canvas_view = new plot_canvas.default_view({model: plot_canvas, parent: @plot_view})
 
   it "should exist because get_canvas_element depends on it", sinon.test () ->
     expect(@plot_canvas_view.canvas_view.ctx).to.exist
@@ -389,18 +396,13 @@ describe "PlotCanvasView dimensions", ->
       plot_width: 444
       plot_height: 555
     })
+    @plot_view = new plot.default_view({model: plot, parent: null})
     @doc.add_root(plot)
     @plot_canvas = new PlotCanvas({
       plot: plot
     })
     @plot_canvas.attach_document(@doc)
-    @plot_canvas_view = new @plot_canvas.default_view({ 'model': @plot_canvas })
-
-  it "reset_dimensions should call document resize", sinon.test () ->
-    spy = this.spy(@doc, 'resize')
-    expect(spy.callCount).to.be.equal 0
-    @plot_canvas_view.reset_dimensions()
-    expect(spy.callCount).to.be.equal 1
+    @plot_canvas_view = new @plot_canvas.default_view({model: @plot_canvas, parent: @plot_view})
 
   it "reset_dimensions should set plot width and height to initial width and height", sinon.test () ->
     # Explicitly set to 1 to make sure they're being set
@@ -410,12 +412,6 @@ describe "PlotCanvasView dimensions", ->
     expect(@plot_canvas.plot.width).to.be.equal 444 # Comes from plot_width
     expect(@plot_canvas.plot.height).to.be.equal 555
 
-  it "update_dimensions should call document resize", sinon.test () ->
-    spy = this.spy(@doc, 'resize')
-    expect(spy.callCount).to.be.equal 0
-    @plot_canvas_view.update_dimensions(1, 2)
-    expect(spy.callCount).to.be.equal 1
-
   it "update_dimensions should set plot width and height to requested width and height", sinon.test () ->
     @plot_canvas_view.update_dimensions(22, 33)
     expect(@plot_canvas.plot.width).to.be.equal 22
diff --git a/bokehjs/test/models/tools/actions/zoom_in_tool.coffee b/bokehjs/test/models/tools/actions/zoom_in_tool.coffee
--- a/bokehjs/test/models/tools/actions/zoom_in_tool.coffee
+++ b/bokehjs/test/models/tools/actions/zoom_in_tool.coffee
@@ -33,12 +33,14 @@ describe "ZoomInTool", ->
          x_range: new Range1d({start: -1, end: 1})
          y_range: new Range1d({start: -1, end: 1})
       })
+      @plot_view = new @plot.default_view({model: @plot, parent: null})
 
       document = new Document()
       document.add_root(@plot)
 
       @plot_canvas_view = new @plot.plot_canvas.default_view({
         model: @plot.plot_canvas
+        parent: @plot_view
       })
 
     it "should zoom into both ranges", ->
@@ -50,6 +52,7 @@ describe "ZoomInTool", ->
         model: zoom_in_tool
         plot_model: @plot.plot_canvas
         plot_view: @plot_canvas_view
+        parent: null # wrong
       })
 
       # perform the tool action
@@ -69,6 +72,7 @@ describe "ZoomInTool", ->
         model: zoom_in_tool
         plot_model: @plot.plot_canvas
         plot_view: @plot_canvas_view
+        parent: null # wrong
       })
 
       # perform the tool action
@@ -88,6 +92,7 @@ describe "ZoomInTool", ->
         model: zoom_in_tool
         plot_model: @plot.plot_canvas
         plot_view: @plot_canvas_view
+        parent: null # wrong
       })
 
       # perform the tool action
diff --git a/bokehjs/test/models/tools/actions/zoom_out_tool.coffee b/bokehjs/test/models/tools/actions/zoom_out_tool.coffee
--- a/bokehjs/test/models/tools/actions/zoom_out_tool.coffee
+++ b/bokehjs/test/models/tools/actions/zoom_out_tool.coffee
@@ -33,12 +33,14 @@ describe "ZoomOutTool", ->
          x_range: new Range1d({start: -1, end: 1})
          y_range: new Range1d({start: -1, end: 1})
       })
+      @plot_view = new @plot.default_view({model: @plot, parent: null})
 
       document = new Document()
       document.add_root(@plot)
 
       @plot_canvas_view = new @plot.plot_canvas.default_view({
         model: @plot.plot_canvas
+        parent: @plot_view
       })
 
     it "should zoom into both ranges", ->
@@ -50,6 +52,7 @@ describe "ZoomOutTool", ->
         model: zoom_out_tool
         plot_model: @plot.plot_canvas
         plot_view: @plot_canvas_view
+        parent: null # wrong
       })
 
       # perform the tool action
@@ -69,6 +72,7 @@ describe "ZoomOutTool", ->
         model: zoom_out_tool
         plot_model: @plot.plot_canvas
         plot_view: @plot_canvas_view
+        parent: null # wrong
       })
 
       # perform the tool action
@@ -88,6 +92,7 @@ describe "ZoomOutTool", ->
         model: zoom_out_tool
         plot_model: @plot.plot_canvas
         plot_view: @plot_canvas_view
+        parent: null # wrong
       })
 
       # perform the tool action
diff --git a/bokehjs/test/models/tools/gestures/resize_tool.coffee b/bokehjs/test/models/tools/gestures/resize_tool.coffee
--- a/bokehjs/test/models/tools/gestures/resize_tool.coffee
+++ b/bokehjs/test/models/tools/gestures/resize_tool.coffee
@@ -27,12 +27,14 @@ describe "ResizeTool", ->
       doc = new Document()
 
       plot = new Plot({x_range: @x_range, y_range: @y_range, toolbar: toolbar})
+      plot_view = new plot.default_view({model: plot, parent: null})
       doc.add_root(plot)
-      @plot_canvas_view = new plot.plot_canvas.default_view({ 'model': plot.plot_canvas })
+      @plot_canvas_view = new plot.plot_canvas.default_view({model: plot.plot_canvas, parent: plot_view})
       @resizetool = new ResizeTool({ plot: plot })
       @resizetool_view = new @resizetool.default_view({
         model: @resizetool
         plot_view: @plot_canvas_view
+        parent: null # wrong
       })
 
     it "_update should call plot_view update dimensions", ->
diff --git a/bokehjs/test/models/tools/gestures/wheel_pan_tool.coffee b/bokehjs/test/models/tools/gestures/wheel_pan_tool.coffee
--- a/bokehjs/test/models/tools/gestures/wheel_pan_tool.coffee
+++ b/bokehjs/test/models/tools/gestures/wheel_pan_tool.coffee
@@ -31,12 +31,14 @@ describe "WheelPanTool", ->
          x_range: new Range1d({start: 0, end: 1})
          y_range: new Range1d({start: 0, end: 1})
       })
+      @plot_view = new @plot.default_view({model: @plot, parent: null})
 
       document = new Document()
       document.add_root(@plot)
 
       @plot_canvas_view = new @plot.plot_canvas.default_view({
         model: @plot.plot_canvas
+        parent: @plot_view
       })
 
     it "should translate x-range in positive direction", ->
@@ -47,6 +49,7 @@ describe "WheelPanTool", ->
       wheel_pan_tool_view = new x_wheel_pan_tool.default_view({
         model: x_wheel_pan_tool
         plot_view: @plot_canvas_view
+        parent: null # wrong
       })
 
       # negative factors move in positive x-data direction
@@ -66,6 +69,7 @@ describe "WheelPanTool", ->
       wheel_pan_tool_view = new x_wheel_pan_tool.default_view({
         model: x_wheel_pan_tool
         plot_view: @plot_canvas_view
+        parent: null # wrong
       })
 
       # positive factors move in positive y-data direction
diff --git a/bokehjs/test/models/tools/gestures/wheel_zoom_tool.coffee b/bokehjs/test/models/tools/gestures/wheel_zoom_tool.coffee
--- a/bokehjs/test/models/tools/gestures/wheel_zoom_tool.coffee
+++ b/bokehjs/test/models/tools/gestures/wheel_zoom_tool.coffee
@@ -35,12 +35,14 @@ describe "WheelZoomTool", ->
          x_range: new Range1d({start: -1, end: 1})
          y_range: new Range1d({start: -1, end: 1})
       })
+      @plot_view = new @plot.default_view({model: @plot, parent: null})
 
       document = new Document()
       document.add_root(@plot)
 
       @plot_canvas_view = new @plot.plot_canvas.default_view({
         model: @plot.plot_canvas
+        parent: @plot_view
       })
 
     it "should zoom in both ranges", ->
@@ -52,6 +54,7 @@ describe "WheelZoomTool", ->
         model: wheel_zoom
         plot_model: @plot.plot_canvas
         plot_view: @plot_canvas_view
+        parent: null # wrong
       })
 
       # positive delta will zoom in
@@ -76,6 +79,7 @@ describe "WheelZoomTool", ->
         model: wheel_zoom
         plot_model: @plot.plot_canvas
         plot_view: @plot_canvas_view
+        parent: null # wrong
       })
 
       # positive delta will zoom out
@@ -100,6 +104,7 @@ describe "WheelZoomTool", ->
         model: wheel_zoom
         plot_model: @plot.plot_canvas
         plot_view: @plot_canvas_view
+        parent: null # wrong
       })
 
       # positive delta will zoom in
@@ -123,6 +128,7 @@ describe "WheelZoomTool", ->
         model: wheel_zoom
         plot_model: @plot.plot_canvas
         plot_view: @plot_canvas_view
+        parent: null # wrong
       })
 
       # positive delta will zoom in
@@ -146,6 +152,7 @@ describe "WheelZoomTool", ->
         model: wheel_zoom
         plot_model: @plot.plot_canvas
         plot_view: @plot_canvas_view
+        parent: null # wrong
       })
 
       # positive delta will zoom in
@@ -169,6 +176,7 @@ describe "WheelZoomTool", ->
         model: wheel_zoom
         plot_model: @plot.plot_canvas
         plot_view: @plot_canvas_view
+        parent: null # wrong
       })
 
       # positive delta will zoom in
@@ -192,6 +200,7 @@ describe "WheelZoomTool", ->
         model: wheel_zoom
         plot_model: @plot.plot_canvas
         plot_view: @plot_canvas_view
+        parent: null # wrong
       })
 
       # positive delta will zoom in
diff --git a/bokehjs/test/models/tools/toolbar.coffee b/bokehjs/test/models/tools/toolbar.coffee
--- a/bokehjs/test/models/tools/toolbar.coffee
+++ b/bokehjs/test/models/tools/toolbar.coffee
@@ -22,7 +22,7 @@ describe "ToolbarView", ->
 
   it "render should call template with toolbar_location", ->
     @test_tb.toolbar_location = 'below'
-    tb_view = new @test_tb.default_view({ model: @test_tb })
+    tb_view = new @test_tb.default_view({ model: @test_tb, parent: null })
     spy = sinon.spy(tb_view, 'template')
     tb_view.render()
     expect(spy.calledOnce).is.true
@@ -33,13 +33,13 @@ describe "ToolbarView", ->
     dom_top = 44
     width = 111
     height = 123
-    @test_tb._dom_left = {_value: dom_left}
-    @test_tb._dom_top = {_value: dom_top}
-    @test_tb._width = {_value: width}
-    @test_tb._height = {_value: height}
+    @test_tb._dom_left.setValue(dom_left)
+    @test_tb._dom_top.setValue(dom_top)
+    @test_tb._width.setValue(width)
+    @test_tb._height.setValue(height)
     @test_tb.sizing_mode = 'stretch_both'
 
-    tb_view = new @test_tb.default_view({ model: @test_tb })
+    tb_view = new @test_tb.default_view({ model: @test_tb, parent: null })
     tb_view.render()
     expected_style = "left: #{dom_left}px; top: #{dom_top}px; width: #{width}px; height: #{height}px;"
     expect(tb_view.el.style.cssText).to.be.equal expected_style
@@ -49,13 +49,13 @@ describe "ToolbarView", ->
     dom_top = 44
     width = 111
     height = 123
-    @test_tb._dom_left = {_value: dom_left}
-    @test_tb._dom_top = {_value: dom_top}
-    @test_tb._width = {_value: width}
-    @test_tb._height = {_value: height}
+    @test_tb._dom_left.setValue(dom_left)
+    @test_tb._dom_top.setValue(dom_top)
+    @test_tb._width.setValue(width)
+    @test_tb._height.setValue(height)
     @test_tb.sizing_mode = 'fixed'
 
-    tb_view = new @test_tb.default_view({ model: @test_tb })
+    tb_view = new @test_tb.default_view({ model: @test_tb, parent: null })
     tb_view.render()
     expect(tb_view.el.style.cssText).to.be.equal("")
 
diff --git a/bokehjs/test/models/tools/toolbar_box.coffee b/bokehjs/test/models/tools/toolbar_box.coffee
--- a/bokehjs/test/models/tools/toolbar_box.coffee
+++ b/bokehjs/test/models/tools/toolbar_box.coffee
@@ -19,25 +19,25 @@ describe "ToolbarBoxView", ->
 
   it "should return null from get_width if @_horizontal is not true", ->
     @box._horizontal = false
-    @box_view = new @box.default_view({ model: @box })
+    @box_view = new @box.default_view({ model: @box, parent: null })
     expect(@box_view.get_width()).to.be.null
 
   it "should return 30 from get_width if @_horizontal is true", ->
     # @_horizontal means that the toolbar is on the left or the right
     @box._horizontal = true
-    @box_view = new @box.default_view({ model: @box })
+    @box_view = new @box.default_view({ model: @box, parent: null })
     expect(@box_view.get_width()).to.be.equal 30
 
   # Note: The way height is reporting is not perfectly correct, but this
   # simple version gets a number of things working as a starting point
   it "should return 30 from get_height if @_horizontal is true", ->
     @box._horizontal = true
-    @box_view = new @box.default_view({ model: @box })
+    @box_view = new @box.default_view({ model: @box, parent: null })
     expect(@box_view.get_height()).to.be.equal 30
 
   it "should return 30 from get_height if @_horizontal is false", ->
     @box._horizontal = false
-    @box_view = new @box.default_view({ model: @box })
+    @box_view = new @box.default_view({ model: @box, parent: null })
     expect(@box_view.get_height()).to.be.equal 30
 
 
diff --git a/bokehjs/test/models/widgets/paragraph.coffee b/bokehjs/test/models/widgets/paragraph.coffee
--- a/bokehjs/test/models/widgets/paragraph.coffee
+++ b/bokehjs/test/models/widgets/paragraph.coffee
@@ -16,7 +16,7 @@ describe "Paragraph.View render", ->
   it "should set the margin to 0", ->
     p = new Paragraph()
     p.attach_document(new Document())
-    p_view = new p.default_view({ model: p })
+    p_view = new p.default_view({ model: p, parent: null })
     p_view.render()
     expected_style = "margin: 0px;"
     expect(p_view.el.querySelector('p').style.cssText).to.contain expected_style