如何编写代码片段#

用户通过示例学习。因此,无论您是在编写文档字符串还是用户指南,都应包含说明相关API的示例。您的示例应开箱即用,以便用户可以复制它们并根据自身需求进行调整。

本页描述如何编写代码片段,以便在CI中进行测试。

备注

本指南中的示例使用 reStructuredText。如果您正在编写 Markdown,请使用 MyST 语法。要了解更多信息,请阅读 MyST 文档

示例类型#

有三种类型的示例:doctest-stylecode-output-styleliteralinclude

doctest-style 示例#

doctest-style 示例模仿了交互式 Python 会话。

.. doctest::

    >>> def is_even(x):
    ...     return (x % 2) == 0
    >>> is_even(0)
    True
    >>> is_even(1)
    False

它们是这样渲染的:

>>> def is_even(x):
...     return (x % 2) == 0
>>> is_even(0)
True
>>> is_even(1)
False

小技巧

如果你在编写文档字符串,请排除 .. doctest:: 以简化你的代码。

Example:
    >>> def is_even(x):
    ...     return (x % 2) == 0
    >>> is_even(0)
    True
    >>> is_even(1)
    False

code-output-style 示例#

code-output-style 示例包含普通的 Python 代码。

.. testcode::

    def is_even(x):
        return (x % 2) == 0

    print(is_even(0))
    print(is_even(1))

.. testoutput::

    True
    False

它们是这样渲染的:

def is_even(x):
    return (x % 2) == 0

print(is_even(0))
print(is_even(1))
True
False

literalinclude 示例#

literalinclude 示例显示 Python 模块。

.. literalinclude:: ./doc_code/example_module.py
    :language: python
    :start-after: __is_even_begin__
    :end-before: __is_even_end__
# example_module.py

# fmt: off
# __is_even_begin__
def is_even(x):
    return (x % 2) == 0
# __is_even_end__
# fmt: on

它们是这样渲染的:

def is_even(x):
    return (x % 2) == 0

你应该写哪种类型的示例?#

关于应该使用哪种风格没有硬性规定。选择最能说明你的API的风格。

小技巧

如果你不确定使用哪种样式,请使用 code-block-style

何时使用 doctest-style#

如果你正在编写一个小示例来强调对象表示,或者如果你想打印中间对象,请使用 doctest-style。:

.. doctest::

    >>> import ray
    >>> ds = ray.data.range(100)
    >>> ds.schema()
    Column  Type
    ------  ----
    id      int64
    >>> ds.take(5)
    [{'id': 0}, {'id': 1}, {'id': 2}, {'id': 3}, {'id': 4}]

何时使用 代码块样式#

如果你正在写一个较长的示例,或者对象表示与你的示例无关,请使用 code-block-style。:

.. testcode::

    from typing import Dict
    import numpy as np
    import ray

    ds = ray.data.read_csv("s3://anonymous@air-example-data/iris.csv")

    # Compute a "petal area" attribute.
    def transform_batch(batch: Dict[str, np.ndarray]) -> Dict[str, np.ndarray]:
        vec_a = batch["petal length (cm)"]
        vec_b = batch["petal width (cm)"]
        batch["petal area (cm^2)"] = vec_a * vec_b
        return batch

    transformed_ds = ds.map_batches(transform_batch)
    print(transformed_ds.materialize())

.. testoutput::

    MaterializedDataset(
       num_blocks=...,
       num_rows=150,
       schema={
          sepal length (cm): double,
          sepal width (cm): double,
          petal length (cm): double,
          petal width (cm): double,
          target: int64,
          petal area (cm^2): double
       }
    )

何时使用 literalinclude#

如果你在编写端到端示例,并且你的示例不包含输出,请使用 literalinclude

如何处理难以测试的示例#

什么时候可以不测试一个示例?#

你不需要测试那些依赖于外部系统(如Weights and Biases)的示例。

跳过 doctest-style 示例#

要跳过一个 doctest-style 示例,请在您的 Python 代码后附加 # doctest: +SKIP

.. doctest::

    >>> import ray
    >>> ray.data.read_images("s3://private-bucket")  # doctest: +SKIP

跳过 代码块样式 示例#

要跳过一个 代码块样式 的示例,请在 testoutput 块中添加 :skipif: True

.. testcode::
    :skipif: True

    from ray.air.integrations.wandb import WandbLoggerCallback
    callback = WandbLoggerCallback(
        project="Optimization_Project",
        api_key_file=...,
        log_config=True
    )

如何处理长或不确定的输出#

如果你的 Python 代码是非确定性的,或者如果你的输出过长,你可能想要跳过全部或部分输出。

忽略 doctest-style 输出#

要忽略 doctest-style 输出的一部分,请将问题部分替换为省略号。:

>>> import ray
>>> ray.data.read_images("s3://anonymous@ray-example-data/image-datasets/simple")
Dataset(
   num_rows=...,
   schema={image: numpy.ndarray(shape=(32, 32, 3), dtype=uint8)}
)

要完全忽略一个输出,写一个 代码块风格 的片段。不要使用 # doctest: +SKIP

忽略 代码块样式 输出#

如果你的输出部分较长或不确定,请用省略号替换有问题的部分。

.. testcode::

    import ray
    ds = ray.data.read_images("s3://anonymous@ray-example-data/image-datasets/simple")
    print(ds)

.. testoutput::

    Dataset(
       num_rows=...,
       schema={image: numpy.ndarray(shape=(32, 32, 3), dtype=uint8)}
    )

如果你的输出是不确定的,并且你想显示一个示例输出,请添加 :options: +MOCK

.. testcode::

    import random
    print(random.random())

.. testoutput::
    :options: +MOCK

    0.969461416250246

如果你的输出难以测试,并且你不想显示示例输出,请排除 testoutput

.. testcode::

    print("This output is hidden and untested")

如何使用GPU测试示例#

要配置 Bazel 以在 GPU 上运行示例,请完成以下步骤:

  1. 打开相应的 BUILD 文件。如果你的示例在 doc/ 文件夹中,打开 doc/BUILD。如果你的示例在 python/ 文件夹中,打开类似 python/ray/train/BUILD 的文件。

  2. 找到 doctest 规则。它看起来像这样:

    doctest(
        files = glob(
            include=["source/**/*.rst"],
        ),
        size = "large",
        tags = ["team:none"]
    )
    
  3. 将包含示例的文件添加到排除文件列表中。

    doctest(
        files = glob(
            include=["source/**/*.rst"],
            exclude=["source/data/requires-gpus.rst"]
        ),
        tags = ["team:none"]
    )
    
  4. 如果尚不存在,创建一个 doctest 规则,并将 gpu 设置为 True

    doctest(
        files = [],
        tags = ["team:none"],
        gpu = True
    )
    
  5. 将包含示例的文件添加到GPU规则中。:

    doctest(
        files = ["source/data/requires-gpus.rst"]
        size = "large",
        tags = ["team:none"],
        gpu = True
    )
    

有关实际示例,请参见 doc/BUILDpython/ray/train/BUILD

如何在本地测试示例#

要在本地测试示例,请安装 pytest-sphinx 的 Ray 分支。

pip install git+https://github.com/ray-project/pytest-sphinx

然后,在模块、文档字符串或用户指南上运行 pytest。

pytest --doctest-modules python/ray/data/read_api.py
pytest --doctest-modules python/ray/data/read_api.py::ray.data.read_api.range
pytest --doctest-modules doc/source/data/getting-started.rst