以python包的形式分发jupyter扩展

概述

如何扩展Notebook?

JupyterNotebook客户端和服务器应用程序都是可定制的。他们的行为可以通过分别创建:

  • Nbxtension:Notebook扩展

    • 一个JS文件或javascript目录、级联样式表等,其中至少包含一个打包为 AMD modules 导出函数 load_ipython_extension

  • 服务器扩展:可导入的python模块

    • 那工具 load_jupyter_server_extension

  • bundler扩展:一个可导入的python模块,带有生成的文件->下载为/部署为菜单项触发器

    • 那工具 bundle

为什么要为jupyter扩展创建一个python包?

由于很少有没有任何前端组件(NBextension)的服务器扩展,为了方便和一致性,所有这些客户机和服务器扩展及其资产都可以打包并版本化为包含几个简单命令的python包,或者从Notebook5.3开始,由包管理自动处理。R的选择。这使得用户更容易安装扩展包,也更不容易出错。

安装Jupyter扩展

安装包含jupyter扩展的python包

有几种方法可以获得包含jupyter扩展的python包。通常,您将为系统使用包管理器:

pip install helpful_package
# or
conda install helpful_package
# or
apt-get install helpful_package

# where 'helpful_package' is a Python package containing one or more Jupyter Extensions

自动安装和启用

Notebook5.3新增功能

最简单的情况根本不需要用户交互!配置正确,在安装了他们选择的包管理器之后,服务器和前端扩展可以在安装它们的环境中默认启用,即。 --sys-prefix . 见 setup.py 在下面的示例中。

启用服务器扩展

最简单的情况是启用没有前端组件的服务器扩展。

A pip 希望其配置存储在主目录中的用户将键入以下命令:

jupyter serverextension enable --py helpful_package

或者,a virtualenvconda 用户可以通过 --sys-prefix 使环境保持隔离和可重复性。例如:

# Make sure that your virtualenv or conda environment is activated
[source] activate my-environment

jupyter serverextension enable --py helpful_package --sys-prefix

安装NBextension资产

如果软件包还具有前端资产必须可用(但默认情况下不必启用)的NBextension,请使用以下命令安装这些资产:

jupyter nbextension install --py helpful_package # or --sys-prefix if using virtualenv or conda

启用NBextension资产

如果包中包含的资产应在每次在浏览器中加载Jupyter应用程序(例如lab、notebook、dashboard、terminal)时加载,则可以使用以下命令启用nbextension:

jupyter nbextension enable --py helpful_package # or --sys-prefix if using virtualenv or conda

它起作用了吗?通过列出jupyter扩展名进行检查。

在运行一个或多个扩展安装步骤之后,您可以列出关于nbextensions、服务器扩展或bundler扩展的当前已知内容。以下命令将列出哪些扩展可用、是否已启用以及其他扩展详细信息:

jupyter nbextension list
jupyter serverextension list
jupyter bundlerextension list

创建和分发包的附加资源

当然,除了列出的文件之外,还有许多其他文件需要构建一个适当的包。以下是一些很好的资源: The Hitchhiker’s Guide to Packaging - Repository Structure and Python 作者:Kenneth Reitz

示例-服务器扩展

使用服务器扩展名创建python包

下面是一个python模块的示例,该模块本身直接包含服务器扩展。它具有以下目录结构:

- setup.py
- MANIFEST.in
- my_module/
  - __init__.py

定义服务器扩展

此示例显示服务器扩展及其 load_jupyter_server_extension 函数定义在 __init__.py 文件。

my_module/__init__.py

def _jupyter_server_extension_paths():
    return [{
        "module": "my_module"
    }]


def load_jupyter_server_extension(nbapp):
    nbapp.log.info("my module enabled!")

安装并启用服务器扩展

用户可以通过以下方式安装:

jupyter serverextension enable --py my_module [--sys-prefix]

示例-服务器扩展和NBextension

使用服务器扩展名和nbextension创建python包

这是另一个服务器扩展,带有前端模块。它假定此目录结构:

- setup.py
- MANIFEST.in
- my_fancy_module/
  - __init__.py
  - static/
    index.js

定义服务器扩展和NBextension

此示例再次显示了服务器扩展及其 load_jupyter_server_extension 函数定义在 __init__.py 文件。这一次,还有一个函数 _jupyter_nbextension_paths 对于NBextension。

my_fancy_module/__init__.py

def _jupyter_server_extension_paths():
    return [{
        "module": "my_fancy_module"
    }]

# Jupyter Extension points
def _jupyter_nbextension_paths():
    return [dict(
        section="notebook",
        # the path is relative to the `my_fancy_module` directory
        src="static",
        # directory in the `nbextension/` namespace
        dest="my_fancy_module",
        # _also_ in the `nbextension/` namespace
        require="my_fancy_module/index")]

def load_jupyter_server_extension(nbapp):
    nbapp.log.info("my module enabled!")

安装并启用服务器扩展和NBextension

用户可以使用以下命令集安装和启用扩展:

jupyter nbextension install --py my_fancy_module [--sys-prefix|--user]
jupyter nbextension enable --py my_fancy_module [--sys-prefix|--system]
jupyter serverextension enable --py my_fancy_module [--sys-prefix|--system]

自动启用服务器扩展和NBextension

Notebook5.3新增功能

可以安装和启用服务器扩展和NBextensions,而无需任何用户干预或安装后脚本 <package manager> install <extension package name>

除了 my_fancy_module 文件树,假设:

jupyter-config/
├── jupyter_notebook_config.d/
│   └── my_fancy_module.json
└── nbconfig/
    └── notebook.d/
        └── my_fancy_module.json

jupyter-config/jupyter_notebook_config.d/my_fancy_module.json

{
  "NotebookApp": {
    "nbserver_extensions": {
      "my_fancy_module": true
    }
  }
}

jupyter-config/nbconfig/notebook.d/my_fancy_module.json

{
  "load_extensions": {
    "my_fancy_module/index": true
  }
}

通过以下方式将它们全部放置到位:

setup.py

import setuptools

setuptools.setup(
    name="MyFancyModule",
    ...
    include_package_data=True,
    data_files=[
        # like `jupyter nbextension install --sys-prefix`
        ("share/jupyter/nbextensions/my_fancy_module", [
            "my_fancy_module/static/index.js",
        ]),
        # like `jupyter nbextension enable --sys-prefix`
        ("etc/jupyter/nbconfig/notebook.d", [
            "jupyter-config/nbconfig/notebook.d/my_fancy_module.json"
        ]),
        # like `jupyter serverextension enable --sys-prefix`
        ("etc/jupyter/jupyter_notebook_config.d", [
            "jupyter-config/jupyter_notebook_config.d/my_fancy_module.json"
        ])
    ],
    ...
    zip_safe=False
)

最后,但不是最不重要的:

MANIFEST.in

recursive-include jupyter-config *.json
recursive-include my_fancy_module/static *.js

由于大多数包管理器将只修改其环境,最终的配置将如同用户键入了:

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

如果用户手动 disable 是一个扩展,该配置将覆盖捆绑包配置。

当自动安装失败时

注意,在某些情况下,在 pip ,需要手动使用 installenable 命令。

非特定于python的包管理器(例如 condaapt )可以选择不在 setup.py 级别,在构建时有更多的方法将数据文件放在不同的位置。

示例-Bundler扩展

使用bundlerextension创建python包

这是一个bundler扩展,它添加了 Download as -> Notebook Tarball (tar.gz) Notebook选项 File 菜单。它假定此目录结构:

- setup.py
- MANIFEST.in
- my_tarball_bundler/
  - __init__.py

定义bundler扩展

此示例显示bundler扩展及其 bundle 函数定义在 __init__.py 文件。

my_tarball_bundler/__init__.py

import tarfile
import io
import os
import nbformat

def _jupyter_bundlerextension_paths():
    """Declare bundler extensions provided by this package."""
    return [{
        # unique bundler name
        "name": "tarball_bundler",
        # module containing bundle function
        "module_name": "my_tarball_bundler",
        # human-readable menu item label
        "label" : "Notebook Tarball (tar.gz)",
        # group under 'deploy' or 'download' menu
        "group" : "download",
    }]


def bundle(handler, model):
    """Create a compressed tarball containing the notebook document.

    Parameters
    ----------
    handler : tornado.web.RequestHandler
        Handler that serviced the bundle request
    model : dict
        Notebook model from the configured ContentManager
    """
    notebook_filename = model['name']
    notebook_content = nbformat.writes(model['content']).encode('utf-8')
    notebook_name = os.path.splitext(notebook_filename)[0]
    tar_filename = '{}.tar.gz'.format(notebook_name)

    info = tarfile.TarInfo(notebook_filename)
    info.size = len(notebook_content)

    with io.BytesIO() as tar_buffer:
        with tarfile.open(tar_filename, "w:gz", fileobj=tar_buffer) as tar:
            tar.addfile(info, io.BytesIO(notebook_content))

        # Set headers to trigger browser download
        handler.set_header('Content-Disposition',
                           'attachment; filename="{}"'.format(tar_filename))
        handler.set_header('Content-Type', 'application/gzip')

        # Return the buffer value as the response
        handler.finish(tar_buffer.getvalue())

Extending the Notebook 有关编写Nbxtensions、服务器扩展和Bundler扩展的更多文档。