为IntEnum开发autodoc 插件

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

概述

我们希望插件能为IntEnum创建自动文档。IntEnum 是标准库``enum`` 模块中的一个整数枚举模块。

这个类目前没有特殊的自动记录行为。

我们想在autodoc中加入以下内容:

  • 一个新的``autointenum``指令会文档化``IntEnum`` 类。

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

  • autointenum``指令将有一个选项:hex:``,能使整数以十六进制表示。

系统需求

我们需要与  the previous extensions.  相同的设置。 这次,我们将把扩展名放到一个名为:file:my_enums.py`的文件中。文件:file:`my_enums.py 将包含我们要记录的示例枚举。

这是您将获得的文件夹结构的示例:

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

编写插件

从插件的``setup``函数开始。

1def setup(app: Sphinx) -> ExtensionMetadata:
2    app.setup_extension('sphinx.ext.autodoc')  # Require autodoc extension
3    app.add_autodocumenter(IntEnumDocumenter)
4    return {
5        'version': '1',
6        'parallel_read_safe': True,
7    }

The setup_extension() method will pull the autodoc extension because our new extension depends on autodoc. add_autodocumenter() is the method that registers our new auto documenter class.

We want to import certain objects from the autodoc extension:

1from __future__ import annotations
2
3from enum import IntEnum
4from typing import TYPE_CHECKING, Any
5
6from sphinx.ext.autodoc import ClassDocumenter, bool_option
7

There are several different documenter classes such as MethodDocumenter or AttributeDocumenter available in the autodoc extension but our new class is the subclass of ClassDocumenter which a documenter class used by autodoc to document classes.

This is the definition of our new the auto-documenter class:

 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(
10        cls, member: Any, membername: str, isattr: bool, parent: Any
11    ) -> 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(
22        self,
23        more_content: StringList | None,
24        no_docstring: bool = False,
25    ) -> None:
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(f'**{the_member_name}**: {the_member_value}', source_name)
39            self.add_line('', source_name)

Important attributes of the new class:

objtype

This attribute determines the auto directive name. In this case the auto directive will be autointenum.

directivetype

This attribute sets the generated directive name. In this example the generated directive will be .. :py:class::.

priority

the larger the number the higher is the priority. We want our documenter be higher priority than the parent.

option_spec

option specifications. We copy the parent class options and add a new option hex.

Overridden members:

can_document_member

This member is important to override. It should return True when the passed object can be documented by this class.

add_directive_header

This method generates the directive header. We add :final: directive option. Remember to call super or no directive will be generated.

add_content

This method generates the body of the class documentation. After calling the super method we generate lines for enum description.

使用扩展

You can now use the new autodoc directive to document any IntEnum.

For example, you have the following IntEnum:

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

This will be the documentation file with auto-documentation directive:

index.rst
.. autointenum:: my_enums.Colors