如何让 doctest 与 mkdocs 的 markdown 代码块中的示例一起运行?

问题描述 投票:0回答:1

我使用 mkdocs 和 mkdocstring 来构建我的文档,并在文档字符串中包含代码示例。我还使用 doctest(通过

pytest --doctest-modules
)来测试所有这些示例。

选项 1 - 文档格式

如果我像这样格式化我的文档字符串:

    """
    Recursively flattens a nested iterable (including strings!) and returns all elements in order left to right.

    Examples:
    --------
    ```
    >>> [x for x in flatten([1,2,[3,4,[5],6],7,[8,9]])]
    [1, 2, 3, 4, 5, 6, 7, 8, 9]
    ```
    """

然后它在文档中呈现得很好,但 doctest 失败并出现错误:

Expected:
    [1, 2, 3, 4, 5, 6, 7, 8, 9]
    ```
Got:
    [1, 2, 3, 4, 5, 6, 7, 8, 9]

这是有道理的,因为 doctest 对待所有内容,直到空行作为预期输出并旨在匹配是完全

选项 2 - doctest 的格式

如果我在没有代码块的情况下格式化文档测试的文档字符串:

    """
    Recursively flattens a nested iterable (including strings!) and returns all elements in order left to right.

    Examples:
    --------
    >>> [x for x in flatten([1,2,[3,4,[5],6],7,[8,9]])]
    [1, 2, 3, 4, 5, 6, 7, 8, 9]
    """

然后 doctest 通过,但文档呈现

[x for x in flatten([1,2,[3,4,[5],6],7,[8,9]])][1, 2, 3, 4, 5, 6, 7, 8, 9]

解决方法? - 为 doctest 添加一个空行

如果我在代码块末尾之前使用额外的空行对其进行格式化:

    """
    Recursively flattens a nested iterable (including strings!) and returns all elements in order left to right.

    Examples:
    --------
    ```
    >>> [x for x in flatten([1,2,[3,4,[5],6],7,[8,9]])]
    [1, 2, 3, 4, 5, 6, 7, 8, 9]

    ```
    """

然后 doctest 通过了但是

  1. 文档中示例底部有一个空行(丑陋)
  2. 我需要记住在每个示例的末尾添加一个空行(容易出错且烦人)

有人知道更好的解决方案吗?

python pytest doctest mkdocs mkdocstrings
1个回答
0
投票

修补 doctest 用于识别代码块的正则表达式解决了这个问题。在此记录下来,供将来偶然发现此问题的人使用...

由于这不是我想在项目中定期执行的操作(!),因此我创建了 pytest-doctest-mkdocstrings 作为 pytest 插件来为我执行此操作,并包含一些额外的健全性检查、配置选项等。

pip install pytest-doctest-mkdocstrings
pytest --doctest-mdcodeblocks --doctest-modules --doctest-glob="*.md"

对于那些在这里寻找代码答案以供自己使用的人,所需的更改是:


    _MD_EXAMPLE_RE = re.compile(
        r"""
            # Source consists of a PS1 line followed by zero or more PS2 lines.
            (?P<source>
                (?:^(?P<indent> [ ]*) >>>    .*)    # PS1 line
                (?:\n           [ ]*  \.\.\. .*)*)  # PS2 lines
            \n?
            # Want consists of any non-blank lines that do not start with PS1.
            (?P<want> (?:(?![ ]*$)    # Not a blank line
                        (?![ ]*```)  # Not end of a code block
                        (?![ ]*>>>)  # Not a line starting with PS1
                        .+$\n?       # But any other line
                    )*)
            """,
        re.MULTILINE | re.VERBOSE,
    )

    doctest.DocTestParser._EXAMPLE_RE = _MD_EXAMPLE_RE

具体来说,我已将

(?![ ]*```)  # Not end of a code block
包含在“想要”的标识中

© www.soinside.com 2019 - 2024. All rights reserved.