開發 autodoc 擴充功能

本教學的目標是建立一個擴充功能,為 autodoc 新增對新類型的支援。此 autodoc 擴充功能將格式化 Python 標準函式庫中的 IntEnum 類別。(模組 enum

概觀

我們希望擴充功能可以為 IntEnum 建立自動文件。IntEnum 是標準函式庫 enum 模組中的整數列舉類別。

目前此類別沒有特殊的自動文件行為。

我們希望將以下內容新增至 autodoc

  • 一個新的 autointenum 指令,將會文件化 IntEnum 類別。

  • 產生的文件將包含所有可能的列舉值及其名稱。

  • autointenum 指令將有一個 :hex: 選項,這會導致整數以十六進位格式印出。

先決條件

我們需要與先前的擴充功能相同的設定。這次,我們將把我們的擴充功能放在一個名為 autodoc_intenum.py 的檔案中。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    }

setup_extension() 方法將拉取 autodoc 擴充功能,因為我們的新擴充功能依賴 autodoc。add_autodocumenter() 方法會註冊我們新的自動文件編寫器類別。

我們想要從 autodoc 擴充功能匯入某些物件

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

在 autodoc 擴充功能中有幾個不同的文件編寫器類別,例如 MethodDocumenterAttributeDocumenter,但我們的新類別是 ClassDocumenter 的子類別,ClassDocumenter 是 autodoc 用於文件化類別的文件編寫器類別。

這是我們新的自動文件編寫器類別的定義

 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    ) -> None:
25        super().add_content(more_content)
26
27        source_name = self.get_sourcename()
28        enum_object: IntEnum = self.object
29        use_hex = self.options.hex
30        self.add_line('', source_name)
31
32        for the_member_name, enum_member in enum_object.__members__.items():  # type: ignore[attr-defined]
33            the_member_value = enum_member.value
34            if use_hex:
35                the_member_value = hex(the_member_value)
36
37            self.add_line(f'**{the_member_name}**: {the_member_value}', source_name)
38            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 方法之後,我們為列舉描述產生行。

使用擴充功能

你現在可以使用新的 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

延伸閱讀

如果你希望在多個專案或與他人分享你的擴充功能,請查看第三方擴充功能章節。