跳转到主要内容

具有高级doctest功能的pytest插件。

项目描述

Zenodo DOI CI Status

此包包含pytest框架的插件,该插件提供高级doctest支持和使各种文本文件(如reStructuredText(“.rst”),markdown(“.md”)和TeX(“.tex”))的测试成为可能。

动机

此插件为测试包含在Python文档字符串和独立文档文件中的示例Python代码提供了高级功能。

良好的开发者文档应包含示例代码。这既适用于独立的文档,也适用于与代码本身集成的文档。Python 提供了一种机制来测试在 Python 文档字符串中提供的代码片段。单元测试框架 pytest 提供了一种机制来运行针对源代码中的文档字符串和独立文档文件的 doctests。

此插件通过提供以下功能增强了 Python 和 pytest 提供的功能

  • 针对产生浮点结果的 doctests 进行近似浮点比较(请参阅 浮点比较

  • 在运行 doctests 时跳过特定的类、方法和函数(请参阅 跳过测试

  • 结合 pytest-remotedata 插件处理使用远程数据的 doctests(请参阅 远程数据

  • 可选地包含 *.rst 文件以进行 doctests(请参阅 设置和配置

  • 可选地将 doctests 包含在 Numpy ufunc 的文档字符串中

此外,pytest-doctestplus 支持编辑文件以修复不正确的文档字符串(请参阅 修复现有文档字符串)。

安装

pytest-doctestplus 插件可以使用 pip 安装

$ pip install pytest-doctestplus

还可以从源存储库安装最新开发版本

$ git clone https://github.com/scientific-python/pytest-doctestplus
$ cd pytest-doctestplus
$ pip install .

在两种情况下,插件都将自动注册以与 pytest 一起使用。

使用方法

注意:除 setup.cfg 外,还支持 pyproject.toml 配置;以下提到的 setup.cfg,请将语法替换为 TOML 等效语法。

设置和配置

此插件提供三个命令行选项:--doctest-plus 用于启用上述高级功能,--doctest-rst 用于将 *.rst 文件包含在 doctest 收集中,以及 --doctest-ufunc 用于将 doctests 包含在 Numpy ufunc 的文档字符串中。

还可以通过将 doctest_plus = enabled 添加到包的 setup.cfg 文件的 [tool:pytest] 部分来默认启用此插件。

此插件应用于 pytest 收集的所有目录和文件。这意味着在 setup.cfg 中配置 testpathsnorecursedirs 也会影响 pytest-doctestplus 将发现的文件。此外,此插件还提供了一个 doctest_norecursedirs 配置变量,它指示应被 pytest-doctestplus 忽略但不需要被其他 pytest 功能忽略的目录。

使用 pytest 内置的 --doctest-modules 选项将覆盖此插件的行为,即使 setup.cfg 中有 doctest_plus = enabled,也将导致使用默认的 doctest 插件。但是,如果由于某些原因同时提供了 --doctest-modules--doctest-plus,则无论 setup.cfg 的内容如何,都将使用 pytest-doctestplus 插件。

pytest-doctestplus 遵守 --doctest-continue-on-failure 标志。如果设置,doctest 将会报告所有失败的行,这有助于检测同一个 doctest 中的独立错误。然而,如果早期失败导致后续行访问的变量保持未设置或具有意外的值,这可能会生成假阳性。

此插件遵守内置 doctest 插件使用的 doctest 选项,并在 setup.cfg 中的 doctest_optionflags 中设置。默认情况下,使用 ELLIPSISNORMALIZE_WHITESPACE。有关所有 doctest 设置的描述,请参阅doctest 文档

在 Markdown 文件中运行测试

要运行 Markdown 文件中的 doctests,请在命令行中使用 --doctest-plus --doctest-glob '*.md' 选项调用 pytest。

如果您在 GitHub 风格的三重反引号代码块 中编写 doctests,那么为了使 pytest-doctest 能够找到并运行它们,您需要在代码块中包含一个额外的尾随换行符,如下所示

```pycon
>>> 1 + 2
2

```

Doctest 指令

pytest-doctestplus 插件定义了用于控制特定功能行为的 doctest 指令。有关指令及其使用的通用信息,请查阅文档。此插件定义的指令的具体内容在下文各节中描述。

Sphinx Doctest 指令

您可以在 Sphinx RST 中使用 testsetuptestcleanup 来运行在渲染文档中不可见的代码。然而,由于 pytest-doctestplus 的工作方式,需要在这些代码前面加上 >>>。例如

.. testsetup::

    >>> x = 42

.. testcleanup::

    >>> del x

浮点数比较

某些 doctests 可能会产生包含浮点数值字符串表示的输出。浮点数表示通常不是精确的,并且在最低有效位包含舍入误差。根据测试运行的平台(不同的 Python 版本、不同的操作系统等),显示的确切数字位数可能不同。由于 doctests 通过比较字符串来工作,这可能导致此类测试失败。

为了解决这个问题,pytest-doctestplus 插件提供了对 FLOAT_CMP 标志的支持,该标志可用于 doctests。例如

>>> 1.0 / 3.0  # doctest: +FLOAT_CMP
0.333333333333333311
>>> {'a': 1 / 3., 'b': 2 / 3.}  # doctest: +FLOAT_CMP
{'a': 0.333333, 'b': 0.666666}

当使用此标志时,预期的和实际的输出都被解析以查找字符串中的任何浮点值。然后,将它们转换为实际的 Python float 对象,并进行数值比较。这意味着舍入数字表示中的小差异将被 doctest 忽略。值的其他部分将被精确比较,因此更显著的(尽管可能是小的)差异仍会被这些测试捕获。

可以通过将其添加到 setup.cfg 中来全局启用此标志,如下所示

doctest_optionflags =
    NORMALIZE_WHITESPACE
    ELLIPSIS
    FLOAT_CMP

忽略警告

如果 doctest 中的代码发出警告,并且您想要确保该警告被静默处理,则可以使用 IGNORE_WARNINGS 标志。例如

>>> import numpy as np
>>> np.mean([])  # doctest: +IGNORE_WARNINGS
np.nan

显示警告

如果在doctest中的代码发出警告,并且您想确保显示该警告,则可以使用SHOW_WARNINGS标志。当pytest将警告转换为错误,并且默认情况下警告被打印到stderr时,这很有用。这与IGNORE_WARNINGS相反,因此显然不应同时使用这两个标志。例如

>>> import numpy as np
>>> np.mean([])  # doctest: +SHOW_WARNINGS
RuntimeWarning: Mean of empty slice.
RuntimeWarning: invalid value encountered in double_scalars
np.nan

跳过测试

Doctest提供了+SKIP指令,用于在测试文档时跳过不应执行的语句。

>>> open('file.txt') # doctest: +SKIP

在Sphinx .rst文档中,可以使用指令跳过整个代码示例块。

.. doctest-skip::

    >>> import asdf
    >>> asdf.open('file.asdf')

然而,通常能够跳过与特定函数、方法、类或整个文件关联的文档字符串非常有用。

跳过所有测试

还可以使用doctest-skip-all注释跳过以下某行以下的全部doctests。注意这里行尾没有::

.. doctest-skip-all

   >>> import non_existing
   >>> non_existing.write_pseudo_code()
   All the doctests are skipped in the file below

无条件跳过

pytest-doctestplus插件提供了一种方法来指示某些文档字符串应该完全跳过。这通过在每个应该跳过测试的模块中定义变量__doctest_skip__来配置。变量__doctest_skip__的值应该是一个通配符模式列表,这些模式对应于所有应该跳过doctests的函数/类。例如

__doctest_skip__ = ['myfunction', 'MyClass', 'MyClass.*']

跳过名为myfunction的函数中的doctests,跳过名为MyClass的类的doctests,以及MyClass的所有方法

模块文档字符串也可以包含doctests。要跳过模块级别的doctests

__doctest_skip__  = ['.', 'myfunction', 'MyClass']

要跳过一个模块中的所有doctests

__doctest_skip__ = ['*']

Doctest依赖项

还可以根据特定依赖项是否可用来跳过某些doctests。这通过在模块级别定义变量__doctest_requires__来配置。此变量的值是一个字典,表示运行与特定函数、类和方法关联的doctests所需的模块。

字典的键是上述描述的通配符模式,或通配符模式的元组,指示哪些文档字符串应被跳过。字典中的值是列表,表示为了执行给定的doctests,必须提供这些模块。

考虑以下示例

__doctest_requires__ = {('func1', 'func2'): ['scipy']}

拥有此模块级别变量将需要在模块中运行func1func2的doctests时导入scipy

同样,在Sphinx .rst文档中,如果依赖项不可用,则可以条件性地跳过整个代码示例块。

.. doctest-requires:: asdf

    >>> import asdf
    >>> asdf.open('file.asdf')

此外,如果代码仅针对可选依赖项的特定版本运行,则可以添加如下版本的检查

.. doctest-requires:: asdf<3

    >>> import asdf
    >>> asdf.open('file.asdf')

最后,可以使用setup.cfg文件包的[tool:pytest]部分的doctest_subpackage_requires来通过整个子包跳过收集doctests。此选项的语法是path = requirements列表,例如

doctest_subpackage_requires =
    astropy/wcs/* = scipy>2.0;numpy>1.14
    astropy/cosmology/* = scipy>1.0

如果用分号分隔,可以指定多个要求。

远程数据

“pytest-doctestplus”插件可以与pytest-remotedata插件一起使用,以控制需要访问互联网数据的doctest代码。为了使用这些功能,必须安装pytest-remotedata插件,并使用pytest的--remote-data命令行选项启用远程数据访问。有关更多详细信息,请参阅pytest-remotedata插件文档

以下示例说明了如何标记使用远程数据的doctest

>>> from urlib.request import urlopen
>>> url = urlopen('http://astropy.org')  # doctest: +REMOTE_DATA

+REMOTE_DATA指令表示,如果提供了--remote-data选项,则应仅执行标记的语句。默认情况下,所有带有远程数据指令标记的语句都将被跳过。

整个代码示例块也可以用这种方式标记,以控制从互联网访问数据

.. doctest-remote-data::

    >>> import requests
    >>> r = requests.get('https://www.astropy.org')

与Sphinx的兼容性

当使用Sphinx构建文档时,您可能需要启用Sphinx扩展,这些扩展将指令注册到Sphinx中。这样做可以确保Sphinx正确忽略这些指令,使用Sphinx运行doctests不受支持。为此,请在您的conf.py文件中将'pytest_doctestplus.sphinx.doctestplus'添加到您的extensions列表中。

修复现有文档字符串

插件提供了基本的修复文档字符串的支持,这可以通过使用pytest并带有--doctest-plus-generate-diff选项来实现。如果没有其他选项,这将打印出diff和将修改的文件列表。使用--doctest-plus-generate-diff=overwrite将就地修改文件,因此建议先运行检查以验证路径。您可能需要手动审查更改并仅提交一些补丁,例如使用git commit --patch

当前的diff生成仍然非常基础,例如,它不考虑现有的...。默认情况下,仅对失败的doctests生成diff。

通常,大量编辑可能希望专注于特定的更改,并可能包括通过测试。因此,您可以通过在conftest.py中添加钩子来选择此行为

@pytest.hookimpl
def pytest_doctestplus_diffhook(info):
    info["use"] = True  # Overwrite all results (even successes)
    if info["fileno"] is None:
        # E.g. NumPy has C docstrings that cannot be found, we can add
        # custom logic here to try and find these:
        info["filename"] = ...
        info["lineno"] = ...

其中info是一个包含以下项的字典

  • use:表示是否应用diff的TrueFalse。如果doctest成功,则设置为False;如果doctest失败,则设置为True

  • name:测试的名称(例如,正在记录的函数)

  • filename:包含测试的文件(在某些情况下,此文件可能不正确,在这种情况下,test_lineno也将是错误的,您可以手动尝试修复这些错误)

  • source:为该测试执行了源代码

  • test_lineno:示例块(或函数)开始的代码行。在某些情况下,找不到测试文件,因此lineno将是None,您可以手动尝试修复这些错误。

  • example_lineno:示例片段的行号(单独的>>>)。

  • want:当前的文档

  • got:执行示例的结果

您可以直接修改字典以更改行为。

请注意,我们假设此API仅偶尔使用,并保留随时更改的权利。

开发状态

问题、错误报告和功能请求可以通过 github 提交。

许可证

此插件采用3条款BSD风格许可 - 请参阅 LICENSE.rst 文件。

项目详情


下载文件

下载适合您平台文件。如果您不确定选择哪个,请了解有关 安装包 的更多信息。

源分发

pytest-doctestplus-1.2.1.tar.gz (45.9 kB 查看哈希值)

上传时间

构建分发

pytest_doctestplus-1.2.1-py3-none-any.whl (24.9 kB 查看哈希值)

上传时间 Python 3

由以下机构支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误日志 StatusPage StatusPage 状态页面