Desenvolvendo extensões autodoc

O objetivo deste tutorial é criar uma extensão que adicione suporte a novos tipos de autodoc. Esta extensão autodoc irá formatar a classe IntEnum da biblioteca padrão do Python. (módulo enum)

Visão geral

Queremos a extensão que criará documentação automática para IntEnum. IntEnum é a classe enum inteira do módulo enum da biblioteca padrão.

Atualmente esta classe não possui nenhum comportamento especial de documentação automática.

Queremos adicionar o seguinte ao autodoc:

  • Uma nova diretiva autointenum que documentará a classe IntEnum.

  • A documentação gerada terá todos os valores possíveis de enum com nomes.

  • A diretiva autointenum terá uma opção :hex: que fará com que os inteiros sejam impressos em formato hexadecimal.

Pré-requisitos

Precisamos da mesma configuração que em as extensões anteriores. Desta vez, colocaremos a extensão em um arquivo chamado autodoc_intenum.py. O my_enums.py vai conter a amostra de enums que vamos documentar.

Aqui está um exemplo da estrutura de pastas que você pode obter:

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

Escrevendo a extensão

Comece com a função setup para a extensão.

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    }

O método setup_extension() extrairá a extensão autodoc porque nossa nova extensão depende do autodoc. add_autodocumenter() é o método que registra nossa nova classe de documentador automático.

Queremos importar certos objetos da extensão autodoc:

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

Existem várias classes documentadoras diferentes, como MethodDocumenter ou AttributeDocumenter disponíveis na extensão autodoc, mas nossa nova classe é a subclasse de ClassDocumenter que é uma classe documentadora usada pelo autodoc para documentar classes.

Esta é a definição da nossa nova classe auto-documentadora:

 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: Documenter
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)

Atributos importantes da nova classe:

objtype

Este atributo determina o nome da diretiva auto. Neste caso a diretiva auto será autointenum.

directivetype

Este atributo define o nome da diretiva gerada. Neste exemplo a diretiva gerada será .. :py:class::.

priority

quanto maior o número, maior é a prioridade. Queremos que nosso documentador tenha maior prioridade que o pai.

option_spec

especificações da opção. Copiamos as opções da classe pai e adicionamos uma nova opção hex.

Membros substituídos:

can_document_member

É importante substituir esse membro. Deve retornar True quando o objeto passado puder ser documentado por esta classe.

add_directive_header

Este método gera o cabeçalho da diretiva. Adicionamos a opção de diretiva :final:. Lembre-se de chamar super ou nenhuma diretiva será gerada.

add_content

Este método gera o corpo da documentação da classe. Depois de chamar o super método, geramos linhas para descrição de enum.

Usando a extensão

Agora você pode usar a nova diretiva de autodoc para documentar qualquer IntEnum.

Por exemplo, você tem o seguinte IntEnum:

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

Este será o arquivo de documentação com diretiva de documentação automática:

index.rst
.. autointenum:: my_enums.Colors

Leitura adicional

Se você deseja compartilhar sua extensão entre vários projetos ou com outras pessoas, confira a seção Extensões de terceiros.