为 Ray 文档做贡献#

有许多方式可以为 Ray 文档做出贡献,我们一直在寻找新的贡献者。即使你只是想修正一个错别字或扩展一个部分,请随时这样做!

本文档将引导您完成开始所需的一切。

编辑风格#

我们遵循 Google 开发者文档风格指南。以下是一些亮点:

编辑风格在CI中通过Vale强制执行。更多信息,请参见如何使用Vale

构建 Ray 文档#

如果你想为 Ray 文档做贡献,你需要一种构建它的方法。不要在你计划用于构建文档的环境中安装 Ray。文档构建系统的要求通常与你运行 Ray 本身所需的要求不兼容。

按照以下说明构建文档:

Fork Ray#

  1. Fork the Ray repository

  2. 克隆分叉的仓库到您的本地机器

接下来,切换到 ray/doc 目录:

cd ray/doc

安装依赖项#

如果你还没有这样做,创建一个与用于构建和运行 Ray 的 Python 环境分开的 Python 环境,最好使用最新版本的 Python。例如,如果你使用 conda

conda create -n docs python=3.12

接下来,激活你正在使用的 Python 环境(例如,venv、conda 等)。使用 conda 的话,操作如下:

conda activate docs

使用以下命令安装文档依赖项:

pip install -r requirements-doc.txt

在此步骤中不要使用 -U。你不希望升级依赖项,因为 requirements-doc.txt 固定了构建文档所需的精确版本。

构建文档#

在构建之前,首先通过运行以下命令清理您的环境:

make clean

从以下2个选项中选择以在本地构建文档:

  • 增量构建

  • 完整构建

1. Incremental build with global cache and live rendering#

要使用此选项,您可以运行:

make local

如果你需要频繁进行简单的更改,推荐使用此选项。

在这种方法中,Sphinx 只构建你在分支中相对于上次从上游主分支拉取所做的更改。其余的文档通过从你上次从上游提交的预构建文档页面进行缓存(每次向 Ray 推送新提交时,CI 都会从该提交构建所有文档页面,并将它们存储在 S3 上作为缓存)。

构建首先追踪你的提交树,以找到CI已经在S3上缓存的最新提交。一旦构建找到该提交,它会从S3获取相应的缓存并将其解压到doc/目录中。同时,CI会追踪从该提交到当前HEAD的所有更改文件,包括任何未暂存的更改。

Sphinx 然后只重新构建受您更改影响的页面,其余部分从缓存中保持不变。

当构建完成后,文档页面会自动在您的浏览器中弹出。如果在 doc/ 目录中进行了任何更改,Sphinx 会自动重新构建并重新加载您的文档页面。您可以通过按 Ctrl+C 中断来停止它。

2. Full build from scratch#

在完整构建选项中,Sphinx 会重新构建 doc/ 目录中的所有文件,忽略所有缓存和保存的环境。由于这种行为,你会得到一个非常干净的构建,但速度要慢得多。

make develop

_build 目录中找到文档构建。构建完成后,您可以简单地在浏览器中打开 _build/html/index.html 文件。检查构建的输出以确保一切按预期工作被认为是良好的实践。

在提交任何更改之前,请确保从 doc 文件夹中运行 linter ,使用 ../scripts/format.sh ,以确保您的更改格式正确。

代码补全和其他开发者工具#

如果你经常处理文档工作,你可能会发现 esbonio 语言服务器很有用。Esbonio 为 RST 文档提供了上下文感知的语法补全、定义、诊断、文档链接和其他信息。如果你不熟悉 语言服务器,它们是现代开发者工具包中的重要部分;如果你之前使用过 pylancepython-lsp-server,你会知道这些工具有多么有用。

Esbonio 还提供了一个包含实时预览的 vscode 扩展。只需安装 esbonio vscode 扩展即可开始使用该工具:

esbonio

作为 Esbonio 自动补全功能的一个例子,你可以输入 .. 来调出所有 RST 指令的自动补全菜单:

完成

Esbonio 也可以与 neovim 一起使用 - 查看 lspconfig 仓库获取安装说明

我们的构建系统基础#

Ray 文档是使用 sphinx 构建系统构建的。我们使用 PyData Sphinx Theme 作为文档的主题。

我们使用 myst-parser 来允许你使用 Sphinx 的原生 reStructuredText (rST)Markedly Structured Text (MyST) 编写 Ray 文档。这两种格式可以相互转换,因此选择权在你手中。尽管如此,重要的是要知道 MyST 是 common markdown 兼容的。过去的经验表明,大多数开发者熟悉 md 语法,因此如果你打算添加新文档,我们建议从 .md 文件开始。

Ray 文档也完全支持 Jupyter Notebooks 等可执行格式。我们的许多示例都是包含 MyST markdown 单元格 的笔记本。

贡献什么?#

以 Ray Tune 为例,你可以看到我们的文档由几种不同类型的文档组成,所有这些你都可以贡献:

这种结构在 Ray 文档源代码 中也有体现,因此你应该不会有任何问题找到你想要的内容。所有其他 Ray 项目共享类似的结构,但根据项目的不同可能会有细微的差异。

上述每种文档类型都有其各自的用途,但最终我们的文档归结为 两种类型 的文档:

  • 标记文档,使用 MyST 或 rST 编写。如果你没有很多(可执行的)代码要贡献,或者使用更复杂的功能,如 选项卡内容块,这是正确的选择。Ray Tune 中的大多数文档都是以这种方式编写的,例如 关键概念API 文档

  • Notebooks,以 .ipynb 格式编写。所有 Tune 示例都以 notebooks 形式编写。这些 notebooks 在浏览器中的渲染方式类似于 .md.rst 文件,但它们增加了一个好处,即在文档顶部添加启动按钮,以便用户可以在 Binder 或 Google Colab 中自行运行代码。

修复拼写错误并改进解释#

如果你在任何文档中发现拼写错误,或者认为某个解释不够清晰,请考虑提交一个拉取请求。在这种情况下,只需按照上述说明运行linter,然后提交你的拉取请求。

添加API参考#

我们使用 Sphinx 的 autodoc 扩展 从我们的源代码生成 API 文档。如果我们遗漏了对某个函数或类的引用,请考虑将其添加到相关文档中。

例如,以下是如何使用 autofunctionautoclass 添加函数或类引用:

.. autofunction:: ray.tune.integration.docker.DockerSyncer

.. autoclass:: ray.tune.integration.keras.TuneReportCallback

上面的代码片段摘自 Tune API 文档,你可以参考该文档。

如果你想更改API文档的内容,你需要直接编辑源代码中的相应函数或类签名。例如,在上面的 autofunction 调用中,要更改 ray.tune.integration.docker.DockerSyncer 的API参考,你需要 更改以下源文件

为了展示API的使用,在API文档中嵌入小的使用示例是很重要的。这些示例应该是自包含的,并且开箱即用,这样用户可以将它们复制粘贴到Python解释器中并进行试验(例如,如果适用,它们应该指向示例数据)。用户经常依赖这些示例来构建他们的应用程序。要了解更多关于编写示例的信息,请阅读如何编写代码片段

.rST.md 文件添加代码#

修改现有文档文件中的文本很容易,但在添加代码时需要小心。原因是我们要确保文档中的每个代码片段都经过测试。这要求我们有一个在文档中包含和测试代码片段的流程。要学习如何编写可测试的代码片段,请阅读 如何编写代码片段

from ray import train


def objective(x, a, b):  # Define an objective function.
    return a * (x ** 0.5) + b


def trainable(config):  # Pass a "config" dictionary into your trainable.

    for x in range(20):  # "Train" for 20 iterations and compute intermediate scores.
        score = objective(x, config["a"], config["b"])

        train.report({"score": score})  # Send the score to Tune.

此代码由 literalinclude 从名为 doc_code/key_concepts.py 的文件中导入。doc_code 目录中的每个 Python 文件都将由我们的 CI 系统自动测试,但请确保先在本地运行您更改(或新添加)的脚本。您不需要在本地运行测试框架。

在极少数情况下,当你添加 明显 的伪代码来演示一个概念时,可以将其直接添加到你的 .rST.md 文件中,例如使用 .. code-cell:: python 指令。但如果你的代码是应该运行的,那么它需要经过测试。

从头开始创建新文档#

有时你可能想为 Ray 文档添加一个全新的文档,比如添加一个新的用户指南或一个新的示例。

为了使其生效,您需要确保将新文档明确添加到父文档的 toctree 中,这决定了 Ray 文档的结构。更多信息请参见 Sphinx 文档

根据您添加的文档类型,您可能还需要对现有的概览页面进行更改,该页面会整理相关文档列表。例如,对于 Ray Tune,每个用户指南都会作为一个面板添加到 用户指南概览页面,同样的情况也适用于 所有 Tune 示例。始终检查您正在处理的 Ray 子项目的结构,以了解如何在现有结构中整合它。在某些情况下,您可能需要为面板选择一张图片。图片位于 doc/source/images

创建一个笔记本示例#

要在 Ray 文档中添加一个新的可执行示例,您可以从我们的 MyST 笔记本模板Jupyter 笔记本模板 开始。您也可以直接下载您正在阅读的文档(点击本页顶部的相应下载按钮以获取 .ipynb 文件)并开始修改它。Ray Tune 中的所有示例笔记本都会由我们的 CI 系统自动测试,前提是您将它们放置在 examples 文件夹 中。如果您在为其他 Ray 子项目贡献时对如何测试您的笔记本有疑问,请确保在 Ray 社区 Slack 中提问,或在提交拉取请求时直接在 GitHub 上提问。

要基于现有示例进行工作,您还可以查看 Ray Tune Hyperopt 示例(.ipynbRay Serve 文本分类指南(.md。我们建议您从 .md 文件开始,并在过程结束时将您的文件转换为 .ipynb 笔记本。我们将在下面带您完成这个过程。

这些笔记本与其他文档的不同之处在于,它们将代码和文本结合在一个文档中,并且可以在浏览器中启动。我们还确保在将它们添加到我们的文档之前,它们已经通过了我们的CI系统的测试。为了实现这一点,笔记本需要定义一个 内核规范 ,以告诉笔记本服务器如何解释和运行代码。例如,以下是一个Python笔记本的内核规范:

---
jupytext:
    text_representation:
        extension: .md
        format_name: myst
kernelspec:
    display_name: Python 3
    language: python
    name: python3
---

如果你在 .md 格式中编写笔记本,你需要在文件顶部添加这个 YAML 前言。要在你的笔记本中添加代码,你可以使用 code-cell 指令。以下是一个示例:

```python

import ray
import ray.rllib.agents.ppo as ppo
from ray import serve

def train_ppo_model():
    trainer = ppo.PPOTrainer(
        config={"framework": "torch", "num_workers": 0},
        env="CartPole-v0",
    )
    # Train for one iteration
    trainer.train()
    trainer.save("/tmp/rllib_checkpoint")
    return "/tmp/rllib_checkpoint/checkpoint_000001/checkpoint-1"


checkpoint_path = train_ppo_model()
```

将此Markdown块放入文档中,将在浏览器中呈现如下:

import ray
import ray.rllib.agents.ppo as ppo
from ray import serve

def train_ppo_model():
    trainer = ppo.PPOTrainer(
        config={"framework": "torch", "num_workers": 0},
        env="CartPole-v0",
    )
    # Train for one iteration
    trainer.train()
    trainer.save("/tmp/rllib_checkpoint")
    return "/tmp/rllib_checkpoint/checkpoint_000001/checkpoint-1"


checkpoint_path = train_ppo_model()

笔记本标签#

使这项工作生效的是 code-cell 中的 :tags: [hide-cell] 指令。我们建议从 .md 文件开始的原因是,正如你刚刚看到的,向它们添加标签要容易得多。你也可以向 .ipynb 文件添加标签,但首先需要启动一个笔记本服务器,这可能不是你想要为贡献一份文档而做的事情。

除了 hide-cell,你还有 hide-inputhide-output 标签,它们可以隐藏单元格的输入和输出。此外,如果你需要笔记本中执行的代码,但不想在文档中显示,你可以同样使用 remove-cellremove-inputremove-output 标签。

测试笔记本#

删除单元格对于计算密集型的笔记本来说特别有趣。我们希望你贡献的笔记本使用 真实 的值,而不仅仅是玩具示例。同时,我们希望我们的笔记本能被CI系统测试,并且运行它们不应花费太长时间。你可以做的是,首先让用户看到带有你希望他们看到的参数的笔记本单元格:

```{code-cell} python3
num_workers = 8
num_gpus = 2
```

在浏览器中将呈现如下:

num_workers = 8
num_gpus = 2

但在你的笔记本中,你随后跟了一个 removed 单元格,它不会被渲染,但具有更小的值并使笔记本运行更快:

```{code-cell} python3
:tags: [remove-cell]
num_workers = 0
num_gpus = 0
```

将Markdown笔记本转换为ipynb#

完成示例编写后,您可以使用 jupytext 将其转换为 .ipynb 笔记本:

jupytext your-example.md --to ipynb

同样地,你可以使用 --to myst.ipynb 笔记本转换为 .md 笔记本。如果你想将你的笔记本转换为 Python 文件,例如测试你的整个脚本是否能在没有错误的情况下运行,你可以使用 --to py 代替。

如何使用 Vale#

什么是 Vale?#

Vale 检查您的写作是否符合 Google 开发者文档风格指南。它仅在 Ray Data 文档中强制执行。

Vale 捕捉拼写和语法错误。它还强制执行风格规则,如“使用缩写”和“使用第二人称”。有关规则的完整列表,请参阅 Ray 仓库中的配置

如何运行 Vale?#

如何使用 VSCode 扩展#

  1. 安装 Vale。如果你使用 macOS,使用 Homebrew。

    brew install vale
    

    否则,使用 PyPI。

    pip install vale
    

    有关安装的更多信息,请参阅 Vale 文档

  2. 按照这些安装说明安装Vale VSCode扩展。

  3. VSCode 应在您的代码编辑器和“问题”面板中显示警告。

    Vale

如何在命令行中运行 Vale#

  1. 安装 Vale。如果你使用 macOS,使用 Homebrew。

    brew install vale
    

    否则,使用 PyPI。

    pip install vale
    

    有关安装的更多信息,请参阅 Vale 文档

  2. 在终端中运行 Vale

    vale doc/source/data/overview.rst
    
  3. Vale 应在您的终端中显示警告。

    ❯ vale doc/source/data/overview.rst
    
        doc/source/data/overview.rst
        18:1   warning     Try to avoid using              Google.We
                        first-person plural like 'We'.
        18:46  error       Did you really mean             Vale.Spelling
                        'distrbuted'?
        24:10  suggestion  In general, use active voice    Google.Passive
                        instead of passive voice ('is
                        built').
        28:14  warning     Use 'doesn't' instead of 'does  Google.Contractions
                        not'.
    
    ✖ 1 error, 2 warnings and 1 suggestion in 1 file.
    

如何处理错误的 Vale.Spelling 错误#

要添加自定义术语,请完成以下步骤:

  1. 如果目录还不存在,请在 .vale/styles/Vocab 中为您的团队创建一个目录。例如,.vale/styles/Vocab/Data

  2. 如果尚不存在,请创建一个名为 accept.txt 的文本文件。例如,.vale/styles/Vocab/Data/accept.txt

  3. 将您的术语添加到 accept.txt 中。Vale 接受正则表达式。

更多信息,请参阅 Vale 文档中的 词汇表

如何处理虚假的 Google.WordList 错误#

如果你使用了一个不在 Google 的词汇表 中的单词,Vale 会报错。

 304:52   error       Use 'select' instead of         Google.WordList
                      'check'.

如果你想无论如何都要使用这个词,请修改 WordList 配置 中的相应字段。

故障排除#

如果在构建文档时遇到问题,按照以下步骤可以帮助隔离或解决大多数问题:

  1. 清理构建产物。 使用 make clean 清理工作目录中的文档构建产物。Sphinx 使用缓存来避免重复工作,这有时会导致问题。特别是在你构建文档后,执行 git pull origin master 拉取最新更改,然后再次尝试构建文档时,这种情况尤为明显。

  2. 检查你的环境。 使用 pip list 检查已安装的依赖项。将它们与 doc/requirements-doc.txt 进行比较。文档构建系统与 Ray 的依赖要求不同。你不需要运行机器学习模型或在分布式系统上执行代码来构建文档。事实上,最好使用一个完全独立的文档构建环境,而不是你用来运行 Ray 的环境,以避免依赖冲突。安装要求时,执行 pip install -r doc/requirements-doc.txt。不要使用 -U,因为在安装过程中你不希望升级任何依赖项。

  3. 确保使用现代版本的Python。 文档构建系统并不保持与Ray相同的依赖和Python版本要求。在构建文档时,请使用现代版本的Python。较新的Python版本可能比之前的版本快得多。有关最新版本支持信息,请参阅 https://endoflife.date/python

  4. 在 Sphinx 中启用断点。在 doc/Makefile 中向 SPHINXOPTS 添加 -P,以告诉 sphinx 在遇到断点时停止,并移除 -j auto 以禁用并行构建。现在你可以在你尝试导入的模块中,或者在 sphinx 代码本身中设置断点,这有助于隔离顽固的构建问题。

  5. [增量构建] 侧边导航栏不反映新页面 如果你在添加新页面,它们应该总是显示在索引页面的侧边导航栏中。然而,使用 make local 的增量构建会跳过重建许多其他页面,因此 Sphinx 不会更新这些页面上的侧边导航栏。要在所有页面上构建带有正确侧边导航栏的文档,请考虑使用 make develop

接下来去哪里?#

除了文档之外,还有许多其他方式可以为 Ray 做出贡献。更多信息请参见 我们的贡献者指南