JupyterLab 是一个基于web的交互式开发环境,比较方便基于 web 界面来开发、调试 python 等应用程序,在数据科学、科学计算和机器学习领域有广泛的应用。它的主要 github 仓库在这里。
JupyterLab 本身是一个非常复杂的 web 项目,通过模块化的理念进行开发,方便新增各类插件,本文对 JupyterLab 的架构和插件开发做一个梳理。
整体启动流程
一般我们通过 jupyter-lab
或者 jupyter lab
来启动 JupyterLab,如果是前者,会调用到 python 环境下的 bin/jupyter-lab
,如果是后者的方式启动,即先调用到 jupyter_core
,然后其实际上也会通过命令行调用到 jupyter-lab
,脚本中的代码非常简单:
1 | # -*- coding: utf-8 -*- |
jupyterlab.labapp
是基于 tornado 构建的 web 服务器。
实际上 jupyterlab
本身的内容并不多,其内部依赖了 jupyter_server
和 jupyter_core
,对于前端页面部分,其通过将产物目录配置成静态目录的方式提供服务。
labextension
对于大多数开发阶段的命令,都是 jupyter labextension
开头的,这部分实际上是调用到了 jupyterlab.labextensions
:
1 | #!/Users/aircloud/work2/myPythonEnv/venv/bin/python |
实际上,最终的 build 指令会走到 builder/src/build-labextension.ts
这里,这里会调用 webpack 的 js 接口来进行构建。
lumino
lumino 提供了一些构建交互式 web 应用的组件,也在 jupyter 这个组织里面,虽然 jupyterlab 使用了它,但是它也可以脱离 jupyter 使用。
lumio 里面提供了一些示例,包括面板、数据表格、数据存储、dock模式的数据面板等,可以让我们初步了解它所做的事情。
代码主流程
所有插件会被收归到 dev_mode/static/index.out.js
这里。
最后被调用到 node_modules/@lumino/application/src/index.ts
的 registerPlugins
函数。
然后 index.out.js
会调用 lab.start({ ignorePlugins });
,这个 start 实际上就是 node_modules/@lumino/application/src/index.ts
这里的方法,start 阶段主要做的一个事情是 activatePlugin
。
- 自定义的组件如何完成?
通过渲染的时候在 html 注入 page_config
的方式:
1 | {% set page_config_full = page_config.copy() %} |
其中的 federated_extensions
字段是有关自定义插件的信息:
1 | extension: "./extension" |
page_config
的注入逻辑,在 jupyterlab_server/handlers.py
渲染到 html 中,具体找插件的逻辑实际上是从路径中寻找的,这部分代码在 jupyterlab_server/config.py
的 get_federated_extensions
。
- 如何实现懒加载?
利用 webpack 打包生成模块,主要的构建配置的示例:
1 | "library": { |
然后代码在在一开始就加载进来:
1 | // dev_mode/bootstrap.js |
加载代码之后初始化模块的示例:
1 | // dev_mode/index.js |
dev_mode 下面的几个文件的关系:
bootstrap.js
被配置为 webpack 的 entry。index.js
会经过模版替换变成index.out.js
,后者被bootstrap.js
引用。
jupyterhub
最基本的可以看官方的 getstart
https://jupyterhub.readthedocs.io/en/latest/getting-started/index.html
这篇讲的是基本的部署,讲的还可以的:
https://ojerk.cn/Jupyterhub%E6%9C%8D%E5%8A%A1%E5%99%A8%E9%83%A8%E7%BD%B2%E4%B8%8D%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8C%97/
jupyterhub 默认采用 PAM 进行鉴权,因此如果你有系统的用户和权限,才能在 jupyterhub 进行登录。
server 插件
的确是直接 import 进来的
1 | // jupyter_server/extension/manager.py |
所以我们使用这种类似 python path 的方式应该还是管用的:
1 | export PYTHONPATH=$PYTHONPATH:/Users/aircloud/work2/myPythonEnv/test_python_path/path1:/Users/aircloud/work2/myPythonEnv/test_python_path/path2 && jupyter-lab |
client 插件,默认路径
1 | if os.name == 'nt': |