如何编写代码片段#

用户从示例中学习。因此,无论您是编写docstring还是用户指南,都应包含说明相关API的示例。您的示例应该可以直接运行,以便用户可以复制并根据自己的需要进行修改。

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

注意

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

示例类型#

示例共有三种类型:doctest风格代码输出风格字面包含(literalinclude)

doctest风格示例#

doctest风格示例模拟交互式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

提示

如果您正在编写docstrings,请排除.. doctest::以简化代码。

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

代码输出风格示例#

代码输出风格示例包含普通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的风格。

提示

如果您不确定使用哪种风格,请使用代码输出风格

何时使用doctest风格#

如果您正在编写一个强调对象表示的小示例,或者您想打印中间对象,请使用doctest风格

.. 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}]

何时使用代码输出风格#

如果您正在编写一个较长的示例,或者对象表示与您的示例不相关,请使用代码输出风格

.. 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风格示例#

要跳过doctest风格示例,请在您的Python代码中添加# doctest: +SKIP

.. doctest::

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

跳过代码输出风格示例#

要跳过代码输出风格示例,请在testcode块中添加: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风格输出#

要忽略doctest风格输出的部分内容,请用省略号替换有问题的部分。

>>> 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

如何本地测试示例#

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

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

然后,对模块、docstring或用户指南运行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