贡献#

如果您正在阅读本节,您可能对贡献 JupyterLab 感兴趣。欢迎您,感谢您对贡献的兴趣!

请查看贡献者文档,熟悉使用 JupyterLab,并向社区介绍自己(在 聊天 和/或 论坛 上),并分享您感兴趣的项目领域。另请参阅 Jupyter 社区指南.

您可以通过以下方式帮助改进它

我们已将一些问题标记为 好的第一个问题需要帮助,我们认为这些问题是小型、独立更改的良好示例。我们鼓励那些不熟悉代码库的人实施和/或询问有关这些问题的问题。您不需要请求权限来处理此类问题,但如果您这样做并且在 48 小时内没有得到回复,请假设没有人正在处理它(即使有人以前自愿),并打开一个包含建议实现的拉取请求。如果您不确定实现,建议使用草稿拉取请求。

如果您认为您在 JupyterLab 或任何 Jupyter 项目中发现了安全漏洞,请将其报告给 security@ipython.org。如果您希望加密您的安全报告,您可以使用 此 PGP 公钥.

贡献的一般指南#

有关为 Jupyter 项目做出贡献的一般文档,请参阅 Project Jupyter Contributor Documentation行为准则.

向后兼容性、版本和重大更改#

新版本的 JupyterLab 可能会破坏与扩展和其他 Jupyter 自定义的向后兼容性。重大更改尽可能保持在最低限度。JupyterLab 的开发和发布周期遵循 语义版本控制,因此当需要重大更改时,它们会通过版本编号方案进行传达。简而言之,这意味着对于 JupyterLab 版本 X.Y.Z

  • 主版本 (X) 编号更改表示重大更改(不向后兼容)

  • 次要版本号 (Y) 的更改表示向后兼容的新功能添加。

  • 补丁版本号 (Z) 的更改表示向后兼容的错误修复。

对 JupyterLab 扩展和其他自定义的贡献应计划可能出现的重大更改。请考虑在这些项目中向用户记录您的维护计划。您可能还希望考虑在开发扩展时固定 JupyterLab 的主要版本(在您的包元数据中)。

我们在**继任者首次发布后的一年内**维护一个主要版本的 JupyterLab。有关详细信息,请参阅版本生命周期。JupyterLab v4 于 2023 年 5 月 15 日发布,因此 JupyterLab v3 将维护到 2024 年 5 月 15 日。JupyterLab v1 和 v2 不再维护。强烈建议所有 JupyterLab v2 和 v3 用户尽快升级。

语言、工具和流程#

所有源代码均使用TypeScript编写。请参阅样式指南

所有非 Python 源代码均使用prettier格式化,Python 源代码均使用ruff格式化。当代码被修改并提交时,所有暂存文件将使用 pre-commit git 钩子(借助pre-commit)自动格式化。使用像prettierruff这样的代码格式化程序的好处是,它在审查拉取请求时消除了代码风格的话题,从而加快了审查过程。

只要您的代码有效,pre-commit 钩子就会处理它的外观。当您运行pip install -e ".[dev,test]"时,pre-commit及其关联的钩子将自动安装。

要手动安装pre-commit,请运行以下命令:

pip install pre-commit
pre-commit install

您可以随时手动调用 pre-commit 钩子,方法是:

pre-commit run

这应该对您的代码运行任何自动格式化,并告诉您它无法自动修复的任何错误。您也可以将ruff 集成安装到您的文本编辑器中,以便自动格式化代码。

如果您在使用pre-commit install设置 pre-commit 钩子之前已经提交了文件,则可以使用pre-commit run --all-files修复所有内容。之后,您需要自己进行修复提交。

您也可以使用 prettier npm 脚本(例如npm run prettieryarn prettierjlpm prettier)来格式化整个代码库。我们建议您为您的代码编辑器安装一个 prettier 扩展,并将其配置为使用键盘快捷键或自动保存来格式化您的代码。

提交拉取请求贡献#

通常,在打开拉取请求之前,应该打开一个问题来描述一段提议的工作以及它解决的问题。三方人员将确保您的问题符合我们的就绪定义,然后我们才能合并任何与之相关的拉取请求。

拉取请求必须针对开发分支(= main),即使它旨在解决稳定版本中发现的问题。一旦拉取请求在开发分支上合并,它将使用机器人操作(如果机器人操作失败,则手动)回溯到稳定分支。

注意

不要犹豫在 PR 描述中提及目标版本。维护者将相应地设置里程碑。

问题管理#

打开一个问题可以让社区成员参与设计讨论,让其他人了解正在进行的工作,并为富有成效的社区互动奠定基础。当您打开一个新的错误或增强请求时,请在问题模板中提供所有请求的信息,以便响应者能够及时地对您的错误进行分类。

拉取请求应该引用它要解决的问题。一旦拉取请求被合并,与之相关的 issue 也会被关闭。如果在实现方面有额外的讨论,问题可能会被重新打开。如果 30 天内没有额外的讨论,lock bot 将锁定该 issue。如果需要额外的讨论,或者拉取请求没有完全解决锁定的 issue,请打开一个新的 issue,引用锁定的 issue。

新 issue 会被进行分类。具有分类权限的开发者(分类者)将执行以下操作

  1. 阅读 issue

  2. 搜索现有的 issue,并在必要时将其标记为重复

  3. 如果需要更多信息,添加一条评论请求信息

  4. 如果 issue 已准备好进行处理,将其分配到一个里程碑

  5. 对 issue 应用适当的标签(参见下面的示例)

开发者可以在 issue 提交后立即开始处理。如果分类者对你的 issue 有任何疑问,请与他们合作,以便你的更改能够及时合并。

准备就绪定义#

分类的主要目标之一是将 issue 变成准备就绪的状态,以便有人可以处理。一旦分类者确认 issue 符合以下定义,他们将从 issue 中删除 status:Needs Triage 标签。我们不会合并仍然需要分类的 issue 的拉取请求。

分类者还应确保 issue 具有适当的标签来描述它,例如,对于影响一个或多个包的 issue,使用带有 pkg: 前缀的标签。

提供所有请求的信息(如果适用)。 来自 JupyterLab 的 issue 模板

对于错误

  • 描述,最好包括屏幕截图

  • 重现步骤

  • 预期行为

  • 上下文,例如操作系统、浏览器、JupyterLab 版本以及输出或日志摘录

对于功能请求

  • 问题的描述

  • 提出的解决方案的描述

  • 其他上下文

issue 应该代表真实、相关、可行的工作。 简而言之,如果一个有经验的人被分配到这个 issue,他们应该能够在合理的努力和帮助下完成它,并且它能促进 Jupyter 项目的目标。

  • issue 应该具有唯一性;分类是识别重复项的最佳时机。

  • 错误代表对使用 Jupyter 产品和服务的合理预期。

  • 对安全、性能、可访问性和本地化的期望与使用 Jupyter 产品的社区中普遍接受的规范相匹配。

  • issue 代表一个开发者可以承诺拥有的工作,即使他们与其他开发者合作以获得反馈。过大的 issue 应该拆分成多个 issue,每个 issue 都单独进行分类,或者拆分成 team-compass issue 以讨论更实质性的更改。

分类者使用的标签#

所有新的错误和增强请求都具有 status:Needs Triage 标签。

定期地,Jupyter 贡献者(分类审核者或分类者)会审查标记为 status:Needs Triage 的 JupyterLab issue,从最旧的开始,并确定它们是否符合准备就绪的定义。

一旦分类,如果 issue 准备就绪,审核者将删除 status:Needs Triage 标签;不需要额外的标签。如果提交的 issue 中没有足够的信息,分类审核者将应用 status:Needs Info 标签,并将 status:Needs Triage 保持在原位。如果一个 issue 在 status:Needs Info 中停留超过 14 天,并且没有后续沟通,审核者应该应用 status:Blocked。如果在另外 14 天内没有回复解除阻塞,则应关闭阻塞的 issue。

我们期望每个新问题在创建后的一周内得到审查。

分类人员应将更容易/复杂度较低的问题标记为 good first issue,以方便初学者贡献。一个好的第一个问题应该具有

  • 清晰易懂的描述,包含屏幕截图和期望,不需要对项目有太多了解

  • 链接,无论是描述中还是评论中,都指向与问题相关的文档和源代码文件

  • 推荐的联系方式,无论是通过 GitHub 用户名还是其他论坛(Discourse 等),贡献者可以在那里获得帮助

除非问题是时间敏感的,例如它是即将发布的版本阻塞器,否则经验丰富的 Jupyter 贡献者应避免使用 good first issue 标签来获取最近的问题。

使用标签标记问题#

没有 JupyterLab 存储库提交权限的用户可以使用 @meeseeksdev 机器人使用标签标记问题。例如:要将标签 foobar baz 应用于问题,请在问题上评论 @meeseeksdev tag foo "bar baz"

从浏览器内贡献#

无需设置本地环境,即可直接从 Web 浏览器贡献 JupyterLab 代码库

  • GitHub 的 codespace 可用(免费帐户有 每月有限的资源)。

  • GitHub 的 内置编辑器 适合贡献非常小的修复,

  • 更高级的 github.dev 编辑器可以通过在 JupyterLab GitHub 存储库中按点 (.) 键来访问,

  • Gitpod 集成已启用,但没有积极维护,

  • jupyterlab-playground 允许从 JupyterLab 内部原型 JupyterLab 扩展,并且可以使用 Binder 在浏览器中运行而无需安装。

使用 Binder,您也可以在浏览器中测试当前主分支和您的更改。我们建议您至少有 8 GB 的 RAM。要构建和启动最新 JupyterLab 主分支的实例,请在新标签页中打开 此链接。构建大约需要 7 分钟才能完成。

要测试您在 GitHub 上托管的自己的分支,请在 https://mybinder.org 上输入它。如果一切顺利,填写表格大约需要 2 分钟,构建大约还需要 7 分钟。

设置本地开发环境#

注意

查看 自动开发环境 部分,了解一些设置本地开发环境的自动化方法。

本节说明如何设置本地开发环境。我们假设您使用 GNU/Linux、macOS 或 Windows Subsystem for Linux。如果使用 Windows,我们建议安装 Anaconda for windows,然后使用 Anaconda 命令提示符执行所有安装步骤。

安装 Node.js 和 jlpm#

从其 GitHub 源代码构建 JupyterLab 需要 Node.js。开发版本需要 Node.js 版本 20+,如 dev_mode/package.json 中的 engines 规范中所定义。

如果您使用 conda,您可以使用以下命令获取它

conda install -c conda-forge nodejs=20

如果您在 macOS 上使用 Homebrew

brew install node

您也可以使用 Node.js 网站上的安装程序。

要检查安装了哪个版本的 Node.js

node -v

使用自动化设置本地开发环境#

虽然按照上述步骤学习有很多东西,但可以将其自动化以节省时间。使用自动化的主要优点是:减少环境启动时间,减少重建环境的时间,更好的标准化(“基线”,可重现的环境)。本节将展示如何使用 VS Code 开发容器、Docker 和 Vagrant 来实现。

VS Code 设置#

要使用 VS Code 开发容器启动 JupyterLab 的本地开发环境,您需要

  1. 安装 VS Code Dev Containers 扩展

  2. Fork JupyterLab 仓库

  3. 将您的 fork 克隆到本地

git clone https://github.com/<your-github-username>/jupyterlab.git
  1. 使用 VS Code 打开本地克隆。

  2. 在容器中打开仓库。VS Code 应该会弹出一个提示您执行此操作的窗口。如果它没有,您可以点击左下角的图标 ><。然后选择在容器中重新打开

注意

第一次运行需要相当长的时间。

使用 Docker 设置#

要在安装了 docker 的 UNIX 系统中启动 JupyterLab 开发容器

  1. Fork JupyterLab 仓库

  2. 启动容器

git clone https://github.com/<your-github-username>/jupyterlab.git
cd jupyterlab
bash docker/start.sh

上面的命令将在不存在的情况下构建 docker 镜像,然后启动容器,并在监视模式下运行 JupyterLab。端口 8888 被暴露,当前的 JupyterLab 仓库被挂载到容器中。然后,您可以使用您喜欢的 IDE 开始开发 JupyterLab,JupyterLab 将会即时重建。

其他可用命令

bash docker/start.sh dev 4567 # Start JupyterLab dev container at port 4567
bash docker/start.sh stop  # Stop the running container
bash docker/start.sh clean  # Remove the docker image
bash docker/start.sh build  # Rebuild the docker image

# Log into the container's shell with the JupyterLab environment activated.
# It's useful to run the tests or install dependencies.
bash docker/start.sh shell

要向项目添加 TypeScript 依赖项,您需要登录到容器的 shell,安装依赖项以更新 package.json 和 yarn.lock 文件,然后重建 docker 镜像。

bash docker/start.sh shell
# In the container shell
jlpm add ...
exit
# Back to host shell
bash docker/start.sh build

使用 Vagrant 设置#

一个实际的例子可以在 这里找到,它包含一个 Vagrantfile、引导文件和额外的文档。

安装 JupyterLab#

Fork JupyterLab 仓库

然后使用以下步骤

git clone https://github.com/<your-github-username>/jupyterlab.git
cd jupyterlab
pip install -e ".[dev,test]"
jlpm install
jlpm run build  # Build the dev mode assets (optional)

此外,您可能希望执行以下可选命令

# Build the core mode assets (optional)
jlpm run build:core

# Build the app dir assets (optional)
jupyter lab build

常见问题#

重要

在 Windows 上,对于 Python 版本 3.8 或更高版本,需要在 Windows 10 或更高版本上激活符号链接,方法是激活“开发者模式”。这可能不被您的管理员允许。有关说明,请参见 在 Windows 上激活开发者模式

  • 一些脚本将运行“python”。如果您的目标 python 被称为其他名称(例如“python3”),那么构建的某些部分将失败。您可能希望在 conda 环境中构建,或创建一个别名。

  • 命令 jlpm 是 JupyterLab 提供的、锁定版本的 yarn 包管理器。如果您已经安装了 yarn,您可以在开发时使用 yarn 命令,它将在仓库或构建的应用程序目录中运行时使用 jupyterlab/yarn.js 中的 yarn 的本地版本。

  • 如果您决定使用 jlpm 命令并遇到 jlpm: command not found 错误,请尝试将用户级 bin 目录添加到您的 PATH 环境变量中。您已经在之前的命令中安装了 jlpm 以及 JupyterLab,但由于 PATH 环境变量相关问题,jlpm 可能无法访问。如果您使用的是 Unix 派生系统(FreeBSD、GNU/Linux、OS X),您可以使用 export PATH="$HOME/.local/bin:$PATH" 命令来实现这一点。

  • 有时,可能需要使用命令 npm run clean:slate 清理本地仓库。这将清理仓库,并重新安装和重建。

  • 如果 pip 给出 VersionConflict 错误,通常意味着已安装的 jupyterlab_server 版本已过时。运行 pip install --upgrade jupyterlab_server 以获取最新版本。

  • 要为单个 conda/虚拟环境独立安装 JupyterLab,您可以在上面的扩展激活中添加 --sys-prefix 标志;这将把安装绑定到您环境的 sys.prefix 位置,而不会在您的用户范围设置区域(对所有环境可见)中写入任何内容。

  • 您可以运行 jlpm run build:dev:prod 来构建更准确的源映射,这些源映射在调试时会显示原始 Typescript 代码。但是,构建源代码需要更长的时间,因此默认情况下仅用于构建生产环境。

有关希望编写文档的贡献者的安装说明,请参阅 编写文档

运行 JupyterLab#

在开发模式下启动 JupyterLab

jupyter lab --dev-mode

开发模式确保您正在运行在开发安装的 Python 包中构建的 JavaScript 资产。请注意,在开发模式下运行时,扩展默认情况下不会被激活 - 请参考 扩展开发文档 以了解更多信息。

在开发模式下运行时,页面顶部会出现一条红色条带;这是为了指示正在运行未发布的版本。

如果您想更改 TypeScript 代码并在运行时重建(每次重建后都需要刷新页面)

jupyter lab --dev-mode --watch

构建并运行测试#

jlpm run build:testutils
jlpm test

您可以通过更改到相应的包文件夹来运行单个包的测试

cd packages/notebook
jlpm run build:test
jlpm test --runInBand

注意

--runInBand 选项将在当前进程中按顺序运行所有测试。我们建议使用它,因为某些测试正在运行一个不喜欢并行执行的 Jupyter Server。

我们对所有测试使用 jest,因此标准的 jest 工作流程适用。测试可以在 VSCode 或 Chrome 中调试。在调试时,将 it.only 添加到特定测试中可能会有所帮助。每个包中的所有 test* 脚本都接受 jest cli 选项

VSCode 调试#

要在 VSCode 中调试,请在 VSCode 中打开一个包文件夹。我们在每个包文件夹中提供了一个启动配置。在终端中,运行 jlpm test:debug:watch。在 VSCode 中,从“运行”侧边栏中选择“附加到 Jest”以开始调试。有关更多详细信息,请参阅 VSCode 调试文档

Chrome 调试#

要在 Chrome 中调试,请在终端中运行 jlpm test:debug:watch。打开 Chrome 并转到 chrome://inspect/。选择远程设备并开始调试。

测试工具#

testutils(这是一个名为 @jupyterlab/testutils 的公共 npm 包)中有一些辅助函数,许多测试都使用这些函数。

对于依赖于 @jupyterlab/services(启动内核、与文件交互等)的测试,有两种选择。如果需要简单的交互,testutils 公开的 Mock 命名空间包含许多模拟实现(参见 testutils/src/mock.ts)。如果需要完整的服务器交互,请使用 JupyterServer 类。

我们有一个名为 testEmission 的辅助函数,可以帮助编写使用 Lumino 信号的测试,以及一个 framePromise 函数,用于获取 requestAnimationFramePromise。有时我们必须在 Promise 中设置一个哨兵值,然后检查哨兵是否已设置,如果我们需要一个不阻塞的 promise 运行。

国际化#

可翻译字符串更新#

可翻译字符串更新不能在补丁版本中进行。它们必须延迟到次要版本或主要版本。

性能测试#

JupyterLab 的基准测试使用 Playwright 完成。测量的操作包括

  • 打开文件

  • 从文件切换到一个简单的文本文件

  • 切换回文件

  • 关闭文件

测试了两个文件:一个包含许多代码单元格的笔记本,另一个包含许多 Markdown 单元格。

测试在 CI 上运行,通过比较 PR 分支开始时的提交结果和同一 CI 作业上的 PR 分支头来运行,以确保使用相同的硬件。基准测试作业在以下情况下触发:

  • 已批准的 PR 审查

  • 包含句子 please run benchmark 的 PR 审查

测试位于子文件夹 galata/test/benchmark 中。可以使用以下命令执行它们

jlpm run test:benchmark

将在 benchmark-results 文件夹中生成一份特殊报告,其中包含 4 个文件

  • lab-benchmark.json:测试的执行时间和一些元数据。

  • lab-benchmark.md:一份 Markdown 报告

  • lab-benchmark.png:执行时间分布的比较

  • lab-benchmark.vl.json:用于生成 PNG 文件的 Vega-Lite 描述。

标记为 expected 的参考存储在 lab-benchmark-expected.json 中。可以使用 Playwright 的 -u 选项创建它;例如 jlpm run test:benchmark -u

基准测试参数#

可以使用以下环境变量自定义基准测试

  • BENCHMARK_NUMBER_SAMPLES: 用于计算执行时间分布的样本数量;默认值为 20。

  • BENCHMARK_OUTPUTFILE: 基准测试结果输出文件;默认值为 benchmark.json。它在 playwright-benchmark.config.js 中被覆盖。

  • BENCHMARK_REFERENCE: 数据的参考名称;默认值为 actual 用于当前数据,expected 用于参考。

可以在 JupyterLab 分支上手动进行更多测试,并在 jupyterlab/benchmarks 存储库的默认分支上每周运行一次。

视觉回归和 UI 测试#

作为 JupyterLab CI 工作流程的一部分,UI 测试将与视觉回归检查一起运行。 Galata 用于 UI 测试。Galata 提供 Playwright 助手以编程方式控制和检查 JupyterLab UI。

对于 PR 或直接提交到 JupyterLab 项目中的每个提交,都会运行 UI 测试。代码更改有时会导致 UI 测试因各种原因而失败。在每次测试运行后,Galata 会生成一个用户友好的测试结果报告,可用于检查失败的 UI 测试。结果报告显示了失败原因、直至失败的调用堆栈以及有关视觉回归问题的详细信息。对于视觉回归错误,报告中提供了参考图像和测试捕获图像,以及比较期间生成的差异图像。您可以使用这些信息来调试失败的测试。Galata 测试报告可以从 GitHub Actions 页面下载,用于 UI 测试运行。测试工件名为 galata-report,解压缩后,可以通过启动服务器来提供文件 python -m http.server -d <path-to-extracted-report> 来访问报告。然后使用您的 Web 浏览器打开 http://localhost:8000

UI 测试失败的主要原因是

  1. 代码更改导致的视觉回归:

    有时,对项目源代码的修改会引入无意的 UI 更改。视觉回归测试的目的是检测这种 UI 更改。如果您的 PR/提交导致视觉回归,请调试并修复导致的回归。您可以本地运行和调试 UI 测试以修复视觉回归。要调试您的测试,您可以运行 PWDEBUG=1 jlpm playwright test <path-to-test-file>。修复后,您可以将更改推送到您的 GitHub 分支并使用 GitHub Actions 进行测试。

  2. 对用户界面的预期更新:

    如果您的代码更改引入了对 UI 的更新,导致现有的 UI 测试失败,则需要更新失败测试的参考图像。为此,您可以在您的 PR 上发布以下内容的评论

    • please update galata snapshots: 机器人会将一个新的提交推送到您的 PR,更新 galata 测试快照。

    • please update documentation snapshots: 机器人会将一个新的提交推送到您的 PR,更新文档测试快照。

    • please update snapshots: 结合前两个评论的效果。

    机器人会用 +1 表情符号做出反应,表示运行已开始,并在运行结束后回复评论。

有关 UI 测试的更多信息,请阅读 UI 测试开发者文档Playwright 文档.

集成测试的最佳实践#

以下是编写集成测试时应遵循的一些最佳实践

  • 不要在同一个测试中比较多个屏幕截图;如果第一个比较失败,则需要多次运行 CI 工作流程才能修复所有测试。

为调试前端做出贡献#

要对调试器扩展进行更改,需要一个支持调试的内核。

查看用户文档以了解如何安装此内核:调试器

然后刷新页面,调试器侧边栏应该出现在右侧区域。

调试器适配器协议#

下图说明了 JupyterLab 扩展和内核之间发送的消息类型。

UML sequence diagram illustrating the interaction between a user, JupyterLab, and the kernel. From top to bottom, the timeline starts with opening the notebook and includes annotations where the debugger is started and stopped. Specific interactions and message types are discussed in the subsequent text.

在 VS Code 中检查调试消息#

检查 VS Code 中的调试消息有助于了解何时发出调试请求(例如,由 UI 操作触发),以及比较 JupyterLab 调试器与 VS Code 中的 Python 调试器的行为。

第一步是创建一个测试文件和一个调试配置(launch.json

An editor showing the menu for creating a debug configuration.
{
   "version": "0.2.0",
   "configurations": [
      {
         "name": "Python: Current File",
         "type": "python",
         "request": "launch",
         "program": "${file}",
         "console": "integratedTerminal",
         "env": { "DEBUGPY_LOG_DIR": "/path/to/logs/folder" }
      }
   ]
}

然后启动调试器

A started debugging session in the editor. There are additional buttons in the upper right for navigating the session.

日志文件的内容如下所示

...

D00000.032: IDE --> {
               "command": "initialize",
               "arguments": {
                  "clientID": "vscode",
                  "clientName": "Visual Studio Code",
                  "adapterID": "python",
                  "pathFormat": "path",
                  "linesStartAt1": true,
                  "columnsStartAt1": true,
                  "supportsVariableType": true,
                  "supportsVariablePaging": true,
                  "supportsRunInTerminalRequest": true,
                  "locale": "en-us"
               },
               "type": "request",
               "seq": 1
            }

...

其中

  • IDE = VS Code

  • PYD = pydev 调试器

  • 消息遵循 DAP

参考资料#

构建和运行独立示例#

要安装和构建 examples 目录中的示例,请执行以下操作

jlpm run build:examples

要运行特定示例,请更改到示例目录(例如 examples/filebrowser)并输入

python main.py

在浏览器中调试#

所有构建 JupyterLab 的方法都会生成源映射。源映射应该在浏览器开发工具的源文件视图中,位于 webpack:// 标题下。

在正常运行 JupyterLab 时,展开 ~ 标题以查看各个包的源映射。

--dev-mode 模式下运行时,核心包位于 packages/ 下,而第三方库位于 ~ 下。注意:建议在调试时使用 jupyter lab --watch --dev-mode

在运行测试时,包将位于顶层(例如 application/src),当前测试文件集位于 /src 下。注意:建议在调试测试选项时在测试文件夹中使用 jlpm run watch。有关更多信息,请参见 上面


高级架构#

JupyterLab 应用程序由两个主要部分组成

  • 一个 npm 包

  • 一个 Jupyter 服务器扩展(Python 包)

每个部分都命名为 jupyterlab开发者教程文档 提供了额外的架构信息。

NPM 包#

该存储库包含许多使用 lerna 构建工具管理的 npm 包。npm 包源文件位于 packages/ 子目录中。

从源代码构建 NPM 包#

git clone https://github.com/jupyterlab/jupyterlab.git
cd jupyterlab
pip install -e .
jlpm
jlpm run build:packages

重建

jlpm run clean
jlpm run build:packages

编写文档#

文档是用 Markdown 和 reStructuredText 编写的。特别是,我们 Read the Docs 页面上的文档是用 reStructuredText 编写的。为了确保 Read the Docs 页面构建成功,您需要使用 pip 安装文档依赖项

pip install -e ".[docs]"

要测试文档,请运行

python -m pytest --check-links -k .md . || python -m pytest --check-links -k .md --lf .

可以使用 make 构建 Read the Docs 页面

cd docs
make html

或者使用 jlpm

jlpm run docs

写作风格#

  • 以第二人称撰写文档,将读者称为“您”。 不要使用第一人称复数“我们”。 文档的作者并不坐在用户旁边,因此使用“我们”可能会导致当事情无法按预期工作时感到沮丧。

  • 避免使用诸如“简单”或“仅仅”之类的词语来淡化使用 JupyterLab 的意义。 开发人员认为简单或容易的任务,对于用户来说可能并非如此。

  • 使用主动语态。 例如,“拖动笔记本单元格……”而不是“笔记本单元格可以被拖动……”。

  • 每个部分的开头应以简短的(1-2 句话)关于主题、功能或组件的高级描述开始。

  • 使用“启用”而不是“允许”来指示 JupyterLab 为用户提供了哪些可能性。 使用“允许”意味着我们正在给予他们许可,而“启用”意味着赋予他们权力。

用户界面命名约定#

文档、文件和活动#

根据上下文,将文件称为文件或文档。

文档更以人为中心。 如果人类查看、解释或交互是体验的重要组成部分,请使用“文档”一词。 例如,笔记本和 Markdown 文件通常被称为文档,除非是在文件系统上下文中(例如,笔记本文件名)。

在不太以人为中心的上下文中使用文件一词。 例如,在与文件系统或文件名相关的上下文中,请引用文件。

活动是指已打开的文档或与文件无关的其他 UI 面板,例如终端、控制台或检查器。

笔记本单元格#

笔记本包含单元格,每个单元格都有输入和一个或多个输出。 当用户运行单元格时,内核会读取并执行输入,并生成输出。 然后,笔记本会显示单元格的输出。 术语输出描述了运行单元格的多个结果之一。 单元格输出描述了单个单元格的集体输出。 使用所有单元格的输出来描述所有单元格的所有输出。

命令名称#

命令名称出现在菜单、命令面板和工具栏按钮中(名称通常在悬停时显示)。

  • 保持命令名称简短、简洁且明确。

  • 在任何需要更多选项的命令名称后添加省略号(…)。 这告诉用户在执行命令之前,他们应该期望出现一个弹出窗口。

  • 命令应使用祈使式动词。 不要在名词前使用冠词。 例如,写“清除单元格”,而不是“清除单元格”或“清除单元格”。

元素名称#

  • 带选项卡的 UI 的通用内容区域是面板。 使用其最具体的名称引用面板,例如“文件浏览器”。 选项卡栏具有选项卡,允许用户查看不同的面板。

  • 菜单栏包含菜单项,这些菜单项有自己的子菜单

  • 主要工作区域称为工作区域,前提是名称是明确的。

  • 在描述 UI 中的元素时,优先使用口语名称而不是技术名称。 例如,使用“文件浏览器”而不是“文件面板”。

将大多数元素名称写成小写。 这些名称包括

  • 选项卡

  • 面板

  • 菜单栏

  • 侧边栏

  • 文件

  • 文档

  • 活动

  • 选项卡栏

  • 主要工作区域

  • 文件浏览器

  • 命令面板

  • 单元格检查器

  • 代码控制台

将用户界面的以下部分写成一个或多个首字母大写,反映其在 UI 中的使用方式

  • 活动栏

  • 文件菜单

  • 文件选项卡

  • 运行面板

  • 选项卡面板

  • 简单界面模式

有关 UI 中元素的描述,请参见 JupyterLab 界面

Jupyter 服务器扩展#

Jupyter 服务器扩展源文件位于 jupyterlab/ 子目录中。 要使用此扩展,请确保已安装 Jupyter Notebook 服务器版本 4.3 或更高版本。

构建 JupyterLab 服务器扩展#

当您对 JupyterLab npm 包源文件进行更改时,请运行

jlpm run build

以构建更改,然后刷新浏览器以查看更改。

要让系统在每次源文件更改后构建,请运行

jupyter lab --dev-mode --watch

构建工具#

有一系列构建工具用于维护存储库。要获取库的建议版本,请使用 jlpm run get:dependency foo。要更新存储库中库的版本,请使用 jlpm run update:dependency foo ^latest。要删除不需要的依赖项,请使用 jlpm run remove:dependency foo

关键工具是 jlpm run integrity,它确保存储库中包的完整性。它将

  • 确保核心包版本依赖项在所有地方都匹配。

  • 确保导入的包与依赖项匹配。

  • 确保所有包的版本一致。

  • 管理元包。

packages/metapackage 包用于一次构建存储库中的所有 TypeScript,而不是 50 多个单独的构建。

完整性脚本还允许您通过在 TypeScript 文件中导入包来自动添加包的依赖项,然后从存储库根目录运行:jlpm run integrity

我们还有用于在 packages/ 中创建和删除包的脚本,jlpm run create:packagejlpm run remove:package。在创建包时,如果它应该包含在核心捆绑包中,请将 jupyterlab: { coreDependency: true } 元数据添加到 package.json 中。具有 extensionmimeExtension 元数据的包被认为是核心依赖项,除非它们被明确标记为其他。

测试对外部包的更改#

将包链接/取消链接到 JupyterLab#

如果您想对 JupyterLab 的外部包(例如,Lumino)进行更改并针对您的 JupyterLab 副本进行测试,您可以使用 link 命令轻松地做到这一点。

  1. 进行更改,然后构建外部包。

  2. 将 JupyterLab 链接到修改后的包。

    • 导航到 JupyterLab 存储库的顶层,然后运行 jlpm link <path-to-external-repo> --all

3. 然后您可以(重新)构建 JupyterLab(例如 jlpm run build),您的更改应该会被构建过程拾取。

要将 JupyterLab 还原到其原始状态,您可以使用 unlink 命令。

  1. 取消链接 JupyterLab 和修改后的包。

    • 导航到 JupyterLab 存储库的顶层,然后运行 jlpm unlink <path-to-external-repo> --all

  2. 在 JupyterLab 中重新安装外部包的原始版本。

    • 运行 jlpm install --check-files

3. 然后您可以(重新)构建 JupyterLab,一切都应该恢复到默认状态。

可能的链接陷阱#

如果您正在进行一个包含多个包的外部项目,您可能需要链接项目中所有包的副本,包括您没有修改的包。如果不这样做可能会导致与共享状态重复相关的問題。

具体来说,在使用 Lumino 时,您可能需要链接您自己的 "@lumino/messaging" 包的副本(除了您实际修改的包)。这是由于 messaging 包提供的 MessageLoop 命名空间中包含的对象可能重复。

键盘快捷键#

键盘快捷键的排版如下

  • 等宽字体,单个键之间用空格隔开:Shift Enter

  • 对于修饰键,使用描述键的平台无关词语:Shift

  • 对于 Accel 键,使用短语:Command/Ctrl

  • 不要使用平台特定的修饰键图标,因为它们很难在 Sphinx/RTD 上以平台特定的方式显示。

屏幕截图和动画#

我们的文档应该包含屏幕截图和动画,以说明和演示软件。以下是一些准备它们的指南

  • 确保屏幕截图不包含版权材料(最好),或者许可证允许在我们的文档中使用,并且明确说明。

  • 对于屏幕截图,您应该优先创建视觉测试。这允许动态更新它们。这些测试定义在 galata/test/documentation 文件夹中。

  • 如果要拍摄 png 屏幕截图,请使用 Firefox 或 Chrome 开发者工具执行以下操作

    • 将浏览器视窗设置为 1280x720 像素

    • 将设备像素比设置为 1:1(即非 hidpi,非视网膜)

    • 使用浏览器开发者工具截取整个视窗的屏幕截图。屏幕截图不应包含任何浏览器元素,例如浏览器地址栏、浏览器标题栏等,也不应包含任何桌面背景。

  • 如果要创建电影,请按照上述设置(1280x720 视窗分辨率,非 hidpi)进行调整,并使用您选择的屏幕截图工具仅捕获浏览器视窗。

  • 对于 PNG,使用 pngquant --speed 1 <filename> 减少其大小。生成的文件名将附加 -fs8,因此请确保重命名它并使用生成的 文件。将优化的 png 文件提交到主存储库。每个 png 文件的大小不应超过几百 KB。

  • 对于电影,请将它们上传到 IPython/Jupyter YouTube 频道,并将它们添加到 jupyterlab-media 存储库中。要在文档中嵌入电影,请使用 www.youtube-nocookie.com 网站,该网站可以通过点击 YouTube 分享对话框中的“隐私增强”嵌入选项找到。在 URL 末尾添加以下参数 ?rel=0&amp;showinfo=0。这将禁用视频标题和相关视频建议。

  • 屏幕截图或动画应以描述内容的句子开头,例如“要打开文件,请双击文件浏览器中的文件名:”。

  • 我们有自定义 CSS,它将添加框阴影,以及屏幕截图和嵌入式 YouTube 视频的适当大小。请参阅文档中的示例,了解如何嵌入这些资产。

为了帮助我们组织屏幕截图和动画,请使用与使用它们的源文件名称匹配的前缀命名文件

sourcefile.rst
sourcefile_filebrowser.png
sourcefile_editmenu.png

这将帮助我们跟踪文档内容演变时的图像。

备注#

  • 默认情况下,应用程序将从 JupyterLab 暂存目录加载(默认值为 <sys-prefix>/share/jupyter/lab/build)。如果您希望在 <git root>/jupyterlab/build 中运行核心应用程序,请运行 jupyter lab --core-mode。这是将要发布的核心应用程序。

  • 如果您正在使用扩展,请参阅 扩展文档

  • npm 模块与 Node/Babel/ES6/ES5 完全兼容。使用除 TypeScript 之外的语言时,只需省略类型声明。