为 IntEnum 开发 autodoc 插件

本教程的目的是创建插件,为 autodoc 添加新类型的支持。这个 autodoc 插件将从 Python 标准库格式化 IntEnum 类。(模块 enum

概述

我们想要的插件,将创建自动文档的 IntEnum。IntEnum 是来自标准库 enum 模块的整数枚举类。

目前这个类没有特殊的自动文档行为。

我们想添加以下 autodoc:

  • 新的 autointenum 指令,将记录 IntEnum 类。

  • 生成的文档将包含所有具有名称的枚举可能值。

  • autointenum 指令将有选项 :hex:,该选项将导致整数以十六进制形式输出。

准备

我们需要相同的设置,如在 the previous extensions。这一次,我们将把插件放在名为 autodoc_intenum.py 的文件中。my_enums.py 将包含我们将记录的示例枚举。

下面是您可能获得的文件夹结构示例:

└── source
    ├── _ext
    │   └── autodoc_intenum.py
    ├── conf.py
    ├── index.rst
    └── my_enums.py

编写插件

setup 函数开始扩展。

1def setup(app: Sphinx) -> None:
2    app.setup_extension('sphinx.ext.autodoc')  # Require autodoc extension
3    app.add_autodocumenter(IntEnumDocumenter)

setup_extension() 方法将拉出 autodoc 插件,因为我们的新插件依赖于 autodoc。add_autodocumenter() 是注册我们新的自动文档器类的方法

我们想从 autodoc 插件导入某些对象

1from enum import IntEnum
2from typing import Any, Optional
3
4from docutils.statemachine import StringList
5
6from sphinx.application import Sphinx
7from sphinx.ext.autodoc import ClassDocumenter, bool_option

在 autodoc 插件中有几种不同的文档类,如 MethodDocumenterAttributeDocumenter,但我们的新类是 ClassDocumenter 的子类,它是 autodoc 用来记录类的文档类。

下面是我们的新类 auto-documenter 的定义:

 1class IntEnumDocumenter(ClassDocumenter):
 2    objtype = 'intenum'
 3    directivetype = ClassDocumenter.objtype
 4    priority = 10 + ClassDocumenter.priority
 5    option_spec = dict(ClassDocumenter.option_spec)
 6    option_spec['hex'] = bool_option
 7
 8    @classmethod
 9    def can_document_member(cls,
10                            member: Any, membername: str,
11                            isattr: bool, parent: Any) -> bool:
12        try:
13            return issubclass(member, IntEnum)
14        except TypeError:
15            return False
16
17    def add_directive_header(self, sig: str) -> None:
18        super().add_directive_header(sig)
19        self.add_line('   :final:', self.get_sourcename())
20
21    def add_content(self,
22                    more_content: Optional[StringList],
23                    no_docstring: bool = False
24                    ) -> None:
25
26        super().add_content(more_content, no_docstring)
27
28        source_name = self.get_sourcename()
29        enum_object: IntEnum = self.object
30        use_hex = self.options.hex
31        self.add_line('', source_name)
32
33        for the_member_name, enum_member in enum_object.__members__.items():
34            the_member_value = enum_member.value
35            if use_hex:
36                the_member_value = hex(the_member_value)
37
38            self.add_line(
39                f"**{the_member_name}**: {the_member_value}", source_name)
40            self.add_line('', source_name)

新类的重要属性:

objtype

这个属性决定了 auto 指令的名称。在这种情况下,auto 指令将是 autointenum

directivetype

这个属性设置生成的指令名。在这个例子中,生成的指令是 .. :py:class::

priority

数字越大,优先级越高。我们希望文档文件的优先级高于父文件。

option_spec

选项规范。我们复制父类选项,并添加新选项 hex

覆盖成员:

can_document_member

覆写这个成员很重要。当传递的对象可以被这个类记录时,它应该返回 True

add_directive_header

这个方法生成指令头文件。我们添加了 :final: 指令选项。记住调用 super,否则不会生成任何指令。

add_content

这个方法生成类文档的主体。在调用 super 方法后,我们生成了用于 enum description 的行。

使用插件

你现在可以使用新的 autodoc 指令来记录任何 IntEnum

例如,你有以下``IntEnum``:

my_enums.py
class Colors(IntEnum):
    """Colors enumerator"""
    NONE = 0
    RED = 1
    GREEN = 2
    BLUE = 3

这将是带有自动文档指令的文档文件:

index.rst
.. autointenum:: my_enums.Colors