Repository: bokeh/bokeh

Issue:
push_notebook regression in 0.12.11
The code at https://stackoverflow.com/questions/47583601/update-a-bokeh-span-with-an-interact-element-in-jupyter-notebook works with 0.12.10 but not 0.12.11

Showing anything at all in the notebook seems to generate this error:

<img width="1064" alt="screen shot 2017-12-01 at 10 13 36" src="https://user-images.githubusercontent.com/1078448/33491603-5bdca884-d680-11e7-8cf9-b1aae5904024.png">

The plot will still show, but things like notebook comms do not function. 

cc @mattpap @philippjfr 



Discussion:
I forgot to check `examples/howto/notebook_comms` manually before release. 
@mattpap my guess is maybe https://github.com/bokeh/bokeh/pull/7203 since I can't think of anything else offhand in 0.12.11 that touched this area but I have not verified yet. 
`dev3` works and `rc1` does not, so definitely think https://github.com/bokeh/bokeh/pull/7203 is the culprit.
For reference the diff for those tags is here https://github.com/bokeh/bokeh/compare/0.12.11dev3...0.12.11rc1
@mattpap this `defer` appears to be the problem:

https://github.com/bokeh/bokeh/compare/0.12.11dev3...0.12.11rc1#diff-04078835a8fb40a2aae8c6f755938800R169

The comm message is coming in and being handled by jupyter before the comm is set up.  Why is this `defer` needed?

The `clearOutput` error I originally reported is unrelated I think, it just needs some defensive code possibly to ignore things when there is nothing to clear.
`defer()` is there to detach expensive computations that follow from the initial processing (loading scripts, parsing HTML, etc.). This allows the browser to finish loading document before it will be stuck with expensive computations, and allows GC to catch a breath. This increases performance significantly and allows for better utilization of memory.

It's definitively easier to program stuff without it, but it must be there. As a temporary measure, you could use the non-deferred version in notebook. Though in the long term, notebook code must be able do deal with deferred code.
> Though in the long term, notebook code must be able do deal with deferred code.

I not sure that is possible. We have no control over when the jupyter python side sends comms messages. AFAICT They are expected to be set up immediately and ready to go as soon as the cell publish message completes. Which means the documents associated with the comms have to be set up then as well. 
OK,  working on a PR to split the notebook embed codepath, there's too much optional arg checking due to partial case overlap anyway. 

Resolving patch:
diff --git a/bokeh/core/templates.py b/bokeh/core/templates.py
--- a/bokeh/core/templates.py
+++ b/bokeh/core/templates.py
@@ -1,11 +1,12 @@
-''' Provide Jinja2 templates used by Bokeh to embed Bokeh models
-(e.g. plots, widgets, layouts) in various ways.
+''' Provide Jinja2 templates used by Bokeh to embed Bokeh documents and
+models in various ways.
 
 .. bokeh-jinja:: bokeh.core.templates.AUTOLOAD_JS
 .. bokeh-jinja:: bokeh.core.templates.AUTOLOAD_NB_JS
 .. bokeh-jinja:: bokeh.core.templates.AUTOLOAD_TAG
 .. bokeh-jinja:: bokeh.core.templates.CSS_RESOURCES
 .. bokeh-jinja:: bokeh.core.templates.DOC_JS
+.. bokeh-jinja:: bokeh.core.templates.DOC_NB_JS
 .. bokeh-jinja:: bokeh.core.templates.FILE
 .. bokeh-jinja:: bokeh.core.templates.JS_RESOURCES
 .. bokeh-jinja:: bokeh.core.templates.NOTEBOOK_LOAD
@@ -32,6 +33,8 @@
 
 DOC_JS = _env.get_template("doc_js.js")
 
+DOC_NB_JS = _env.get_template("doc_nb_js.js")
+
 FILE = _env.get_template("file.html")
 
 NOTEBOOK_LOAD = _env.get_template("notebook_load.html")
diff --git a/bokeh/embed/notebook.py b/bokeh/embed/notebook.py
--- a/bokeh/embed/notebook.py
+++ b/bokeh/embed/notebook.py
@@ -29,7 +29,7 @@
 # External imports
 
 # Bokeh imports
-from ..core.templates import DOC_JS
+from ..core.templates import DOC_NB_JS
 from ..core.json_encoder import serialize_json
 from ..settings import settings
 from ..util.string import encode_utf8
@@ -90,7 +90,7 @@ def notebook_content(model, notebook_comms_target=None, theme=FromCurdoc):
     else:
         notebook_comms_target = ''
 
-    script = DOC_JS.render(
+    script = DOC_NB_JS.render(
         docs_json=serialize_json(docs_json),
         render_items=serialize_json(render_items)
     )


Test patch:
diff --git a/bokeh/embed/tests/test_notebook.py b/bokeh/embed/tests/test_notebook.py
--- a/bokeh/embed/tests/test_notebook.py
+++ b/bokeh/embed/tests/test_notebook.py
@@ -26,7 +26,7 @@
 # External imports
 
 # Bokeh imports
-from bokeh.core.templates import DOC_JS, PLOT_DIV
+from bokeh.core.templates import DOC_NB_JS, PLOT_DIV
 from bokeh.core.json_encoder import serialize_json
 
 # Module under test
@@ -72,7 +72,7 @@ def test_notebook_content(self, mock_sdjari, test_plot):
         (docs_json, render_items) = ("DOC_JSON", [dict(docid="foo", elementid="bar", modelid="bat")])
         mock_sdjari.return_value = (docs_json, render_items)
 
-        expected_script = DOC_JS.render(docs_json=serialize_json(docs_json),
+        expected_script = DOC_NB_JS.render(docs_json=serialize_json(docs_json),
                                         render_items=serialize_json(render_items))
         expected_div = PLOT_DIV.render(elementid=render_items[0]['elementid'])
 
@@ -93,7 +93,7 @@ def test_notebook_content_with_notebook_comms_target(self, mock_sdjari, test_plo
         assert 'notebook_comms_target' in render_items[0]
 
         ## assert that NOTEBOOK_COMMS_TARGET ends up in generated script
-        expected_script = DOC_JS.render(docs_json=serialize_json(docs_json),
+        expected_script = DOC_NB_JS.render(docs_json=serialize_json(docs_json),
                                         render_items=serialize_json(render_items))
 
         assert script == expected_script