sphinx.ext.doctest – 在文档中测试代码片段

在文档中包含代码片段并演示执行结果通常很有帮助。但务必确保文档与代码保持同步。

此扩展允许您以自然的方式在文档中测试此类代码片段。如果您像此处所示标记代码块,则 doctest 构建器将收集它们并将它们作为 doctest 测试运行。

在每个文档中,您可以将每个代码片段分配给一个。每个组由以下内容组成

  • 零个或多个设置代码块(例如,导入要测试的模块)

  • 一个或多个测试

使用 doctest 构建器构建文档时,将为每个文档收集组并按顺序运行,首先执行设置代码块,然后按它们在文件中出现的顺序执行测试块。

有两种类型的测试块

  • doctest 风格块通过交错 Python 代码(包括解释器提示符)和输出来模拟交互式会话。

  • 代码-输出风格块由一段普通的 Python 代码组成,并且可以选择性地包含该代码的输出。

指令

下面的 group 参数解释如下:如果为空,则该块分配给名为 default 的组。如果是 *,则该块分配给所有组(包括 default 组)。否则,它必须是以逗号分隔的组名列表。

.. testsetup:: [group]

设置代码块。此代码不会在其他构建器的输出中显示,但在其所属组的 doctest 之前执行。

选项

:skipif: condition (text)

如果 python 表达式 condition 为 True,则跳过该指令。请参阅 有条件地跳过测试

.. testcleanup:: [group]

清理代码块。此代码不会在其他构建器的输出中显示,但在其所属组的 doctest 之后执行。

1.1 版本新增。

选项

:skipif: condition (text)

如果 python 表达式 condition 为 True,则跳过该指令。请参阅 有条件地跳过测试

.. doctest:: [group]

doctest 风格的代码块。您可以使用标准的 doctest 标志来控制实际输出与您给出的输出的比较方式。默认标志集由 doctest_default_flags 配置变量指定。

选项

:hide:

在其他构建器中隐藏 doctest 块。默认情况下,它显示为突出显示的 doctest 块。

:options: doctest flags (comma separated list)

应用于测试中每个示例的以逗号分隔的 doctest 标志列表。(您仍然可以为每个示例提供显式标志,使用 doctest 注释,但它们也会显示在其他构建器中。)

或者,您可以提供内联 doctest 选项,例如在 doctest 中

>>> datetime.date.now()
datetime.date(2008, 1, 1)

当运行测试时,它们将被遵守,但默认情况下将从演示输出中删除。您可以使用选项 doctest:no-trim-doctest-flags 阻止删除。

:pyversion: (text)

指定要测试的示例所需的 Python 版本。例如,在以下情况下,示例将仅针对大于 3.12 的 Python 版本进行测试

.. doctest::
   :pyversion: > 3.12

支持以下操作数

  • ~=:兼容版本发布子句

  • ==:版本匹配子句

  • !=:版本排除子句

  • <=, >=:包含有序比较子句

  • <, >:独占有序比较子句

  • ===:任意相等子句。

pyversion 选项后跟 PEP-440:版本说明符

1.6 版本新增。

在 1.7 版本中更改: 支持 PEP-440 操作数和表示法

:trim-doctest-flags:
:no-trim-doctest-flags:

是否删除行尾的 doctest 标志(看起来像 # doctest: FLAG, ... 的注释)和单独的 <BLANKLINE> 标记。默认为 trim-doctest-flags

请注意,与标准 doctest 一样,您必须使用 <BLANKLINE> 来表示预期输出中的空行。构建演示输出(HTML、LaTeX 等)时,<BLANKLINE> 将被删除。

:skipif: condition (text)

如果 python 表达式 condition 为 True,则跳过该指令。请参阅 有条件地跳过测试

.. testcode:: [group]

用于代码-输出风格测试的代码块。

选项

:hide:

在其他构建器中隐藏代码块。默认情况下,它显示为突出显示的代码块。

:trim-doctest-flags:
:no-trim-doctest-flags:

是否删除行尾的 doctest 标志(看起来像 # doctest: FLAG, ... 的注释)和单独的 <BLANKLINE> 标记。默认为 trim-doctest-flags

:skipif: condition (text)

如果 python 表达式 condition 为 True,则跳过该指令。请参阅 有条件地跳过测试

注意

testcode 块中的代码始终一次性执行,无论它包含多少条语句。因此,裸表达式不会生成输出 – 请使用 print。示例

.. testcode::

   1+1         # this will give no output!
   print(2+2)  # this will give output

.. testoutput::

   4

另外,请注意,由于 doctest 模块不支持在同一代码片段中混合常规输出和异常消息,因此这也适用于 testcode/testoutput。

.. testoutput:: [group]

最后一个 testcode 块的相应输出或异常消息。

:hide:

在其他构建器中隐藏 doctest 块。默认情况下,它显示为突出显示的 doctest 块。

:options: doctest flags (comma separated list)

以逗号分隔的 doctest 标志列表。

:trim-doctest-flags:
:no-trim-doctest-flags:

是否删除行尾的 doctest 标志(看起来像 # doctest: FLAG, ... 的注释)和单独的 <BLANKLINE> 标记。默认为 trim-doctest-flags

:skipif: condition (text)

如果 python 表达式 condition 为 True,则跳过该指令。请参阅 有条件地跳过测试

示例

.. testcode::

   print('Output     text.')

.. testoutput::
   :hide:
   :options: -ELLIPSIS, +NORMALIZE_WHITESPACE

   Output text.

以下是指令用法的示例。通过 doctest 进行的测试以及通过 testcodetestoutput 进行的测试是等效的。

The parrot module
=================

.. testsetup:: *

   import parrot

The parrot module is a module about parrots.

Doctest example:

.. doctest::

   >>> parrot.voom(3000)
   This parrot wouldn't voom if you put 3000 volts through it!

Test-Output example:

.. testcode::

   parrot.voom(3000)

This would output:

.. testoutput::

   This parrot wouldn't voom if you put 3000 volts through it!

有条件地跳过测试

skipif,一个字符串选项,可用于有条件地跳过指令。当应该根据环境(硬件、网络/VPN、可选依赖项或不同版本的依赖项)运行不同的测试集时,这可能很有用。skipif 选项受所有 doctest 指令的支持。以下是 skipif 用于不同指令时的典型用例

  • testsetuptestcleanup

    • 有条件地跳过测试设置和/或清理

    • 自定义每个环境的设置/清理代码

  • doctest

    • 有条件地跳过测试及其输出验证

  • testcode

    • 有条件地跳过测试

    • 自定义每个环境的测试代码

  • testoutput

    • 有条件地跳过已跳过测试的输出断言

    • 期望根据环境的不同输出

skipif 选项的值被评估为 Python 表达式。如果结果为真值,则该指令将从测试运行中省略,就像它根本不存在于文件中一样。

可以使用 doctest_global_setup 配置选项,而不是重复表达式,将其分配给一个变量,然后可以使用该变量代替。

这是一个示例,如果未安装 Pandas,则跳过某些测试

conf.py
extensions = ['sphinx.ext.doctest']
doctest_global_setup = '''
try:
    import pandas as pd
except ImportError:
    pd = None
'''
contents.rst
.. testsetup::
   :skipif: pd is None

   data = pd.Series([42])

.. doctest::
   :skipif: pd is None

   >>> data.iloc[0]
   42

.. testcode::
   :skipif: pd is None

   print(data.iloc[-1])

.. testoutput::
   :skipif: pd is None

   42

配置

doctest 扩展使用以下配置值

doctest_default_flags
类型:
int
默认:
ELLIPSIS | IGNORE_EXCEPTION_DETAIL | DONT_ACCEPT_TRUE_FOR_1

默认情况下,启用以下选项

  • ELLIPSIS,允许您在预期输出中放置省略号,以匹配实际输出中的任何内容;

  • IGNORE_EXCEPTION_DETAIL,导致忽略异常名称中最左边的冒号和任何模块信息之后的所有内容;

  • DONT_ACCEPT_TRUE_FOR_1,拒绝输出中出现 “True” 而给出 “1” 的情况 – 接受此替换的默认行为是 Python 2.2 之前时代的遗物。

1.5 版本新增。

doctest_show_successes
类型:
bool
默认:
True

控制是否报告成功。

对于具有许多 doctest 的项目,将其设置为 False 可能有助于仅突出显示失败。

7.2 版本新增。

doctest_path
类型:
Sequence[str]
默认:
()

当使用 doctest 构建器时,将添加到 sys.path 的目录列表。(确保它包含绝对路径。)

doctest_global_setup
类型:
str
默认:
''

Python 代码,其行为就像它被放入每个被测试的文件和每个组的 testsetup 指令中一样。您可以使用它来例如导入您始终需要在 doctest 中使用的模块。

0.6 版本新增。

doctest_global_cleanup
类型:
str
默认:
''

Python 代码,其行为就像它被放入每个被测试的文件和每个组的 testcleanup 指令中一样。您可以使用它来例如删除测试留下的任何临时文件。

1.1 版本新增。

doctest_test_doctest_blocks
类型:
str
默认:
'default'

如果这是一个非空字符串,则标准的 reStructuredText doctest 块也将被测试。它们将被分配给给定的组名。

reStructuredText doctest 块只是 doctest 放入它们自己的段落中,如下所示

Some documentation text.

>>> print(1)
1

Some more documentation text.

(请注意,没有使用特殊的 :: 来引入 doctest 块;docutils 从前导 >>> 中识别它们。此外,没有使用额外的缩进,尽管它没有坏处。)

如果此值保留为其默认值,则 doctest 构建器将上述代码片段解释为与以下内容完全相同

Some documentation text.

.. doctest::

   >>> print(1)
   1

Some more documentation text.

此功能使您可以轻松测试包含在 autodoc 扩展中的文档字符串中的 doctest,而无需使用特殊指令标记它们。

但请注意,您不能在 reStructuredText doctest 块中包含空行。它们将被解释为一个块结束而另一个块开始。此外,删除 <BLANKLINE># doctest: 选项仅在 doctest 块中有效,尽管您可以设置 trim_doctest_flags 以在所有具有 Python 控制台内容的代码块中实现该目的。