Repository: bokeh/bokeh

Issue:
Custom context arguments for the jinja template
I have a bokeh server app with custom `templates/index.hml`, and I'd like to pass custom arguments to the `render()` method of jinja. I see that I can access the jinja template with `curdoc().template`, but the [doc](http://jinja.pocoo.org/docs/dev/api/#jinja2.Template) says this is an immutable object.

`embed._html_page_for_render_items` already has an argument `template_variables` but it seems to be unused for the server. Can we make this available to the server app?


Discussion:
Yes, it would amount to:

* modifying `embed.server_html_page_for_session` to accept a `template_variables` argument that it passes to `_html_page_for_render_items` (the parameter should defaultsto `None` and pass an empty dict to `_html_page_for_render_items`in that case)
* pull `.template_variables` (or whatever) off of the document, and passing them to `server_html_page_for_session` [in this code for the server]( https://github.com/bokeh/bokeh/blob/master/bokeh/server/views/doc_handler.py#L33)
* make `Document` add an attribute `template_vars` that defaults to an empty dict, on initialization

@bkueng would you be interested in working up a PR for this?
Seems doable. Yes, I'll take a shot at it.
@bkueng great! Please let me know if I can help in any way, or answer any questions. 

Resolving patch:
diff --git a/bokeh/document.py b/bokeh/document.py
--- a/bokeh/document.py
+++ b/bokeh/document.py
@@ -301,6 +301,7 @@ def __init__(self, **kwargs):
         self._session_callbacks = {}
         self._session_context = None
         self._modules = []
+        self._template_variables = {}
 
     def __del__(self):
         for module in self._modules:
@@ -408,6 +409,10 @@ def template(self, template):
             raise ValueError("Document templates must be Jinja2 Templates")
         self._template = template
 
+    @property
+    def template_variables(self):
+        return self._template_variables
+
     @property
     def theme(self):
         """ Get the current Theme instance affecting models in this Document. Never returns None."""
diff --git a/bokeh/embed.py b/bokeh/embed.py
--- a/bokeh/embed.py
+++ b/bokeh/embed.py
@@ -616,7 +616,8 @@ def server_html_page_for_models(session_id, model_ids, resources, title, websock
     bundle = _bundle_for_objs_and_resources(None, resources)
     return _html_page_for_render_items(bundle, {}, render_items, title, template=template, websocket_url=websocket_url)
 
-def server_html_page_for_session(session_id, resources, title, websocket_url, template=FILE):
+def server_html_page_for_session(session_id, resources, title, websocket_url, template=FILE,
+                                 template_variables=None):
     elementid = make_id()
     render_items = [{
         'sessionid' : session_id,
@@ -625,5 +626,9 @@ def server_html_page_for_session(session_id, resources, title, websocket_url, te
         # no 'modelid' implies the entire session document
     }]
 
+    if template_variables is None:
+        template_variables = {}
+
     bundle = _bundle_for_objs_and_resources(None, resources)
-    return _html_page_for_render_items(bundle, {}, render_items, title, template=template, websocket_url=websocket_url)
+    return _html_page_for_render_items(bundle, {}, render_items, title, template=template,
+            websocket_url=websocket_url, template_variables=template_variables)
diff --git a/bokeh/server/views/doc_handler.py b/bokeh/server/views/doc_handler.py
--- a/bokeh/server/views/doc_handler.py
+++ b/bokeh/server/views/doc_handler.py
@@ -30,7 +30,8 @@ def get(self, *args, **kwargs):
         page = server_html_page_for_session(session.id, self.application.resources(self.request),
                                             title=session.document.title,
                                             template=session.document.template,
-                                            websocket_url=websocket_url)
+                                            websocket_url=websocket_url,
+                                            template_variables=session.document.template_variables)
 
         self.set_header("Content-Type", 'text/html')
         self.write(page)


Test patch:
diff --git a/bokeh/tests/test_document.py b/bokeh/tests/test_document.py
--- a/bokeh/tests/test_document.py
+++ b/bokeh/tests/test_document.py
@@ -30,6 +30,11 @@ def test_empty(self):
         d = document.Document()
         assert not d.roots
 
+    def test_default_template_vars(self):
+        d = document.Document()
+        assert not d.roots
+        assert d.template_variables == {}
+
     def test_add_roots(self):
         d = document.Document()
         assert not d.roots