Browse files

add nbstencilaproxy module and UI button, based on nuest@33b0aa6

  • Loading branch information...
nuest committed May 11, 2018
1 parent d0df78c commit 8e8f3676cd6b4616c4b5cd1bca7a40c6fe399613
Showing with 131 additions and 17 deletions.
  1. +8 −2 Dockerfile
  2. +28 −3
  3. +18 −0 nbstencilaproxy/
  4. +15 −12 → nbstencilaproxy/
  5. +45 −0 nbstencilaproxy/static/tree.js
  6. +17 −0
@@ -20,8 +20,14 @@ WORKDIR ${HOME}
ADD requirements.txt /tmp/requirements.txt
RUN pip install --no-cache -r /tmp/requirements.txt

RUN test -d ${HOME}/.jupyter/ || mkdir ${HOME}/.jupyter/
ADD ${HOME}/.jupyter/
ADD --chown=1000 /tmp/nbstencilaproxy/
ADD --chown=1000 nbstencilaproxy /tmp/nbstencilaproxy/nbstencilaproxy
RUN pip install /tmp/nbstencilaproxy && \
rm -r /tmp/nbstencilaproxy

RUN jupyter serverextension enable --sys-prefix --py nbstencilaproxy
RUN jupyter nbextension install --sys-prefix --py nbstencilaproxy
RUN jupyter nbextension enable --sys-prefix --py nbstencilaproxy

ADD --chown=1000 archive/kitchen-sink ${HOME}/kitchen-sink
ADD --chown=1000 archive/py-jupyter ${HOME}/py-jupyter
@@ -6,6 +6,11 @@

This project is part of the [eLife Innovation Sprint 2018]( and [Mozilla Global Sprint 2018]( (see [](

This project comprises two modules:

- a JavaScript package for installing and running Stencila (client/UI and services) in a Jupyter container
- a Python package for installing and running a proxy (based on [`nbserverproxy`]( to access the UI as well as services provided by Stencila; the package also extends the Jupyter UI to add a "New Stencila Session" button

## Team

- [@minrk](
@@ -27,7 +32,6 @@ Relevant path configurations comprise the local storage path _as well as_ the UR

The `Dockerfile` installs our helper npm package and adds + configures the `nbserverproxy` tool (see `requirements.txt` and ``).

### Connecting Stencila to Jupyter kernels

Stencila has "execution contexts" (the equivalent of Jupyter's "kernels") for R, Python, SQL, Javascript (in the browser), and Node.js. Execution contexts differ from kernels in a number of ways including local execution and dependency analysis of cells. Both of these are necessary for the reactive, functional execution model of Stencila Articles and Sheets.
@@ -36,6 +40,28 @@ We could install these execution contexts in the Docker image. However, Stencila

We have included the [`stencila-node`]( Node.js package in the Docker image which provides the `JupyterContext` as well as a `NodeContext` (for executing Javascript) and a `SqliteContext` (for executing SQL) .

### Making Stencila available via a Proxy

**nbstencilaproxy** provides Jupyter server and notebook extensions to proxy Stencila.
It is based on [**nbrsessionproxy**]( but does not include the support nbrsessionproxy has for JupyterLab.


Install package:

pip install git+

Install the extensions for all users on the system:

jupyter serverextension enable --py --sys-prefix nbstencilaproxy
jupyter nbextension install --py --sys-prefix nbstencilaproxy
jupyter nbextension enable --py --sys-prefix nbstencilaproxy

The Dockerfile contains an example installation on top of [jupyter/r-notebook](

## Development

@@ -53,8 +79,7 @@ docker run -p 8888:8888 jupyter-dar

- Login by visiting the tokenized URL displayed e.g. `http://localhost:8888/?token=99a7bc13...`

- Go to http://localhost:8888/stencila/

- Go to http://localhost:8888/stencila/ or click on the "New > Stencila Session" button on the Jupyter start page

## License

@@ -0,0 +1,18 @@
from nbstencilaproxy.handlers import setup_handlers

# Jupyter Extension points
def _jupyter_server_extension_paths():
return [{
'module': 'nbstencilaproxy',

def _jupyter_nbextension_paths():
return [{
"section": "tree",
"dest": "nbstencilaproxy",
"src": "static",
"require": "nbstencilaproxy/tree"

def load_jupyter_server_extension(nbapp):
@@ -1,8 +1,22 @@
import pipes
import sys

from tornado import web
from urllib.parse import urlunparse, urlparse

from notebook.utils import url_path_join as ujoin
from notebook.base.handlers import IPythonHandler

from nbserverproxy.handlers import SuperviseAndProxyHandler

class AddSlashHandler(IPythonHandler):
"""Handler for adding trailing slash to URLs that need them"""
def get(self, *args):
src = urlparse(self.request.uri)
dest = src._replace(path=src.path + '/')

# define our proxy handler for proxying the application

class StencilaProxyHandler(SuperviseAndProxyHandler):
@@ -37,7 +51,7 @@ def get_cmd(self):

def add_handlers(app):
def setup_handlers(app):
app.web_app.add_handlers('.*', [
app.base_url + 'stencila/(.*)',
@@ -56,14 +70,3 @@ def add_handlers(app):

# fake a module to load the proxy handler as an extension
module_name = '_myproxymod'
import types
mod = types.ModuleType(module_name)
sys.modules[module_name] = mod
mod.load_jupyter_server_extension = add_handlers
module_name: True,
@@ -0,0 +1,45 @@
define(function(require) {
var $ = require('jquery');
var Jupyter = require('base/js/namespace');
var utils = require('base/js/utils');

var base_url = utils.get_body_data('baseUrl');

function load() {
if (!Jupyter.notebook_list) return;

/* locate the right-side dropdown menu of apps and notebooks */
var menu = $('.tree-buttons').find('.dropdown-menu');

/* create a divider */
var divider = $('<li>')
.attr('role', 'presentation')

/* add the divider */

/* create our list item */
var stencilasession_item = $('<li>')
.attr('role', 'presentation')

/* create our list item's link */
var stencilasession_link = $('<a>')
.attr('role', 'menuitem')
.attr('tabindex', '-1')
.attr('href', base_url + 'stencila/')
.attr('target', '_blank')
.text('Stencila Session');

/* add the link to the item and
* the item to the menu */

return {
load_ipython_extension: load
@@ -0,0 +1,17 @@
import setuptools

author="Min RK, Daniel Nüst, Ryan Lovett",
description="Jupyter extension to proxy Stencila",
classifiers=['Framework :: Jupyter'],
'nbserverproxy >= 0.8.2'
package_data={'nbstencilaproxy': ['static/*']},

0 comments on commit 8e8f367

Please sign in to comment.