From d54ed564af30392d2abd5192332fba9ed7f0f8c6 Mon Sep 17 00:00:00 2001 From: Nicholas Bollweg Date: Thu, 10 Mar 2016 13:44:50 -0500 Subject: [PATCH] initial crack at documentation for new-wave extension stuff --- ...upyter Extensions as Python Packages.ipynb | 251 ++++++++++++++++++ 1 file changed, 251 insertions(+) create mode 100644 docs/source/examples/Notebook/Distributing Jupyter Extensions as Python Packages.ipynb diff --git a/docs/source/examples/Notebook/Distributing Jupyter Extensions as Python Packages.ipynb b/docs/source/examples/Notebook/Distributing Jupyter Extensions as Python Packages.ipynb new file mode 100644 index 000000000..22a40b05b --- /dev/null +++ b/docs/source/examples/Notebook/Distributing Jupyter Extensions as Python Packages.ipynb @@ -0,0 +1,251 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Distributing Jupyter Extensions as Python Packages" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## How can the notebook be extended?\n", + "The Jupyter Notebook server and client application are both deeply customizable. Their behavior can be extended by, respectively:\n", + "\n", + "- nbextension:\n", + " - a single JS file, or directory of JavaScript, Cascading StyleSheets, etc. that contain at least\n", + " - a JavaScript module packaged as an [AMD modules](https://en.wikipedia.org/wiki/Asynchronous_module_definition)\n", + " - that exports a function `load_ipython_extension`\n", + "- server extension: an importable Python module\n", + " - that implements `load_jupyter_server_extension`\n", + "\n", + "Since it is somewhat rare to have a server extension that does not have any frontend components, for convenience ad consistency, all these assets can be versioned together, with a few simple commands to make installing them easy and less error-prone for the user. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install a Python Package with Jupyter Extensions\n", + "There are many ways someone may get the enclosing python package:\n", + "```shell\n", + "pip install some_package\n", + "# or\n", + "conda install some_package\n", + "# or\n", + "apt-get install some_package\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Enable a Server Extension\n", + "\n", + "For the simplest case, a server extension with no frontend components, a `pip` user that wants their configuration stored in their home directory would type:\n", + "```shell\n", + "jupyter serverextension enable --py some_package --user\n", + "```\n", + "\n", + "A `virtualenv` or `conda` user can pass `--sys-prefix` insted of `--user` to keep their environment reproducible.\n", + "```shell\n", + "[source] activate my-environment\n", + "jupyter serverextension enable --py some_package --sys-prefix\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install the nbextension assets" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In any event, if a package also has frontend assets that must be available (but not neccessarily enabled by default):\n", + "```shell\n", + "jupyter nbextension install --py some_package --user # or --sys-prefix\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Enable nbextension assets" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, if a package has extensions that need to be required in the browser without user interactions,\n", + "```shell\n", + "jupyter nbextension enable --py some_package --user # or --sys-prefix\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Did it work?\n", + "After running some extension install steps, one can list what is presently known about, whether it's enabled, etc.\n", + "\n", + "```shell\n", + "jupyter nbextension list\n", + "jupyter serverextension list\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> Of course, in addition to the files listed, there are number of other files one needs to build a proper package. Here are some good resources:\n", + "- [The Hitchhiker's Guide to Packaging](http://the-hitchhikers-guide-to-packaging.readthedocs.org/en/latest/quickstart.html)\n", + "- [Repository Structure and Python](http://www.kennethreitz.org/essays/repository-structure-and-python) by Kenneth Reitz\n", + "\n", + "> How you distribute them, too, is important:\n", + "- [Packaging and Distributing Projects](http://python-packaging-user-guide.readthedocs.org/en/latest/distributing/)\n", + "- [conda: Building packages](http://conda.pydata.org/docs/building/build.html)\n", + "\n", + "> Here are some tools to get you started:\n", + "- [generator-nbextension](https://github.com/Anaconda-Server/generator-nbextension)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implementing Python-wrapped extensions" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here is an example of a python module which contains a server extension directly on itself. It has this directory structure\n", + "```\n", + "- setup.py\n", + "- MANIFEST.in\n", + "- my_module/\n", + " - __init__.py\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `my_module/__init__.py`\n", + "\n", + "```python\n", + "def _jupyter_server_extension_paths():\n", + " return [{\n", + " \"module\": \"my_module\"\n", + " }]\n", + "\n", + "\n", + "def load_jupyter_server_extension(nbapp):\n", + " nbapp.log.info(\"my module enabled!\")\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Which a user can install with:\n", + "```\n", + "jupyter serverextension enable --py my_module [--sys-prefix|--user]\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here is another server extension, with a front-end module. It assumes this directory structure:\n", + "\n", + "```\n", + "- setup.py\n", + "- MANIFEST.in\n", + "- my_fancy_module/\n", + " - __init__.py\n", + " - static/\n", + " index.js\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "### `my_fancy_module/__init__.py`\n", + "\n", + "```python\n", + "def _jupyter_server_extension_paths():\n", + " return [{\n", + " \"module\": \"my_fancy_module\"\n", + " }]\n", + "\n", + "# Jupyter Extension points\n", + "def _jupyter_nbextension_paths():\n", + " return [dict(\n", + " section=\"notebook\",\n", + " # the path is relative to the `my_fancy_module` directory\n", + " src=\"static\",\n", + " # directory in the `nbextension/` namespace\n", + " dest=\"my_fancy_module\",\n", + " # _also_ in the `nbextension/` namespace\n", + " require=\"my_fancy_module/index\")]\n", + "\n", + "def load_jupyter_server_extension(nbapp):\n", + " nbapp.log.info(\"my module enabled!\")\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Which a user can install with:\n", + "```\n", + "jupyter serverextension install --py my_fancy_module [--sys-prefix|--user]\n", + "jupyter nbextension install --py my_fancy_module [--sys-prefix|--user]\n", + "jupyter nbextension enable --py my_fancy_module [--sys-prefix|--user]\n", + "```" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.5.1" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +}