autodoc 拡張機能の開発

このチュートリアルの目的は、autodoc に新しいタイプサポートを追加する拡張機能を作成することです。この autodoc 拡張機能は、Python 標準ライブラリ(モジュール enum)の IntEnum クラスをフォーマットします。

概要

私たちは、IntEnum の自動ドキュメントを作成する拡張機能を望んでいます。IntEnum は、標準ライブラリ enum モジュールの整数 enum クラスです。

現在、このクラスには特別な自動ドキュメントの動作はありません。

autodoc に以下の機能を追加したいと考えています。

  • IntEnum クラスを記述する新しい autointenum ディレクティブ。

  • 生成されたドキュメントには、名前付きのすべての enum の可能な値が含まれます。

  • autointenum ディレクティブには、:hex: オプションがあり、整数が 16 進数形式で表示されます。

前提条件

前の拡張機能 と同じ設定が必要です。今回は、autodoc_intenum.py というファイルに拡張機能を配置します。my_enums.py には、記述するサンプル enum が含まれます。

取得する可能性のあるフォルダ構造の例を以下に示します。

└── 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, Any
5
6from sphinx.ext.autodoc import ClassDocumenter, bool_option
7

autodoc 拡張機能には、MethodDocumenterAttributeDocumenter などのさまざまなドキュメンタークラスがありますが、新しいクラスは、autodoc がクラスの記述に使用するドキュメンタークラスである ClassDocumenter のサブクラスです。

新しい自動ドキュメンタークラスの定義を以下に示します。

 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)

新しいクラスの重要な属性

objtype

この属性は、「auto」ディレクティブ名を決定します。この場合、auto ディレクティブは autointenum になります。

directivetype

この属性は、生成されるディレクティブ名を設定します。この例では、生成されるディレクティブは .. :py:class:: になります。

priority

数値が大きいほど、優先度が高くなります。親よりも優先度が高くなるようにしたいと考えています。

option_spec

オプションの仕様。親クラスのオプションをコピーし、新しいオプション *hex* を追加します。

オーバーライドされたメンバー

can_document_member

このメンバーのオーバーライドが重要です。渡されたオブジェクトがこのクラスで記述できる場合は *True* を返す必要があります。

add_directive_header

このメソッドは、ディレクティブヘッダーを生成します。:final: ディレクティブオプションを追加します。ディレクティブが生成されないように、**super** を呼び出すことを忘れないでください。

add_content

このメソッドは、クラスドキュメントの本文を生成します。super メソッドを呼び出した後、enum 説明の行を生成します。

拡張機能の使用

これで、新しい 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

参考資料

複数のプロジェクト間または他の人と拡張機能を共有したい場合は、サードパーティ製拡張機能 セクションを確認してください。