mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge pull request #8972 from igo95862/master
Tutorial for extending autodoc
This commit is contained in:
commit
3693ffe232
142
doc/development/tutorials/autodoc_ext.rst
Normal file
142
doc/development/tutorials/autodoc_ext.rst
Normal file
@ -0,0 +1,142 @@
|
||||
.. _autodoc_ext_tutorial:
|
||||
|
||||
Developing autodoc extension for IntEnum
|
||||
========================================
|
||||
|
||||
The objective of this tutorial is to create an extension that adds
|
||||
support for new type for autodoc. This autodoc extension will format
|
||||
the ``IntEnum`` class from Python standard library. (module ``enum``)
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
We want the extension that will create auto-documentation for IntEnum.
|
||||
``IntEnum`` is the integer enum class from standard library ``enum`` module.
|
||||
|
||||
Currently this class has no special auto documentation behavior.
|
||||
|
||||
We want to add following to autodoc:
|
||||
|
||||
* A new ``autointenum`` directive that will document the ``IntEnum`` class.
|
||||
* The generated documentation will have all the enum possible values
|
||||
with names.
|
||||
* The ``autointenum`` directive will have an option ``:hex:`` which will
|
||||
cause the integers be printed in hexadecimal form.
|
||||
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
We need the same setup as in :doc:`the previous extensions <todo>`. This time,
|
||||
we will be putting out extension in a file called :file:`autodoc_intenum.py`.
|
||||
The :file:`my_enums.py` will contain the sample enums we will document.
|
||||
|
||||
Here is an example of the folder structure you might obtain:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
└── source
|
||||
├── _ext
|
||||
│ └── autodoc_intenum.py
|
||||
├── conf.py
|
||||
├── index.rst
|
||||
└── my_enums.py
|
||||
|
||||
|
||||
Writing the extension
|
||||
---------------------
|
||||
|
||||
Start with ``setup`` function for the extension.
|
||||
|
||||
.. literalinclude:: examples/autodoc_intenum.py
|
||||
:language: python
|
||||
:linenos:
|
||||
:pyobject: setup
|
||||
|
||||
|
||||
The :meth:`~Sphinx.setup_extension` method will pull the autodoc extension
|
||||
because our new extension depends on autodoc. :meth:`~Sphinx.add_autodocumenter`
|
||||
is the method that registers our new auto documenter class.
|
||||
|
||||
We want to import certain objects from the autodoc extension:
|
||||
|
||||
.. literalinclude:: examples/autodoc_intenum.py
|
||||
:language: python
|
||||
:linenos:
|
||||
:lines: 1-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:
|
||||
|
||||
.. literalinclude:: examples/autodoc_intenum.py
|
||||
:language: python
|
||||
:linenos:
|
||||
:pyobject: IntEnumDocumenter
|
||||
|
||||
|
||||
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.
|
||||
|
||||
|
||||
Using the extension
|
||||
-------------------
|
||||
|
||||
You can now use the new autodoc directive to document any ``IntEnum``.
|
||||
|
||||
For example, you have the following ``IntEnum``:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: 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:
|
||||
|
||||
.. code-block:: rst
|
||||
:caption: index.rst
|
||||
|
||||
.. autointenum:: my_enums.Colors
|
||||
|
||||
|
52
doc/development/tutorials/examples/autodoc_intenum.py
Normal file
52
doc/development/tutorials/examples/autodoc_intenum.py
Normal file
@ -0,0 +1,52 @@
|
||||
from enum import IntEnum
|
||||
from typing import Any, Optional
|
||||
|
||||
from docutils.statemachine import StringList
|
||||
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.ext.autodoc import ClassDocumenter, bool_option
|
||||
|
||||
|
||||
class IntEnumDocumenter(ClassDocumenter):
|
||||
objtype = 'intenum'
|
||||
directivetype = 'class'
|
||||
priority = 10 + ClassDocumenter.priority
|
||||
option_spec = dict(ClassDocumenter.option_spec)
|
||||
option_spec['hex'] = bool_option
|
||||
|
||||
@classmethod
|
||||
def can_document_member(cls,
|
||||
member: Any, membername: str,
|
||||
isattr: bool, parent: Any) -> bool:
|
||||
return isinstance(member, IntEnum)
|
||||
|
||||
def add_directive_header(self, sig: str) -> None:
|
||||
super().add_directive_header(sig)
|
||||
self.add_line(' :final:', self.get_sourcename())
|
||||
|
||||
def add_content(self,
|
||||
more_content: Optional[StringList],
|
||||
no_docstring: bool = False
|
||||
) -> None:
|
||||
|
||||
super().add_content(more_content, no_docstring)
|
||||
|
||||
source_name = self.get_sourcename()
|
||||
enum_object: IntEnum = self.object
|
||||
use_hex = self.options.hex
|
||||
self.add_line('', source_name)
|
||||
|
||||
for enum_value in enum_object:
|
||||
the_value_name = enum_value.name
|
||||
the_value_value = enum_value.value
|
||||
if use_hex:
|
||||
the_value_value = hex(the_value_value)
|
||||
|
||||
self.add_line(
|
||||
f"**{the_value_name}**: {the_value_value}", source_name)
|
||||
self.add_line('', source_name)
|
||||
|
||||
|
||||
def setup(app: Sphinx) -> None:
|
||||
app.setup_extension('sphinx.ext.autodoc') # Require autodoc extension
|
||||
app.add_autodocumenter(IntEnumDocumenter)
|
@ -13,3 +13,5 @@ Refer to the following tutorials to get started with extension development.
|
||||
helloworld
|
||||
todo
|
||||
recipe
|
||||
autodoc_ext
|
||||
|
||||
|
@ -1102,7 +1102,7 @@ class Sphinx:
|
||||
If *override* is True, the given *cls* is forcedly installed even if
|
||||
a documenter having the same name is already installed.
|
||||
|
||||
.. todo:: Add real docs for Documenter and subclassing
|
||||
See :ref:`autodoc_ext_tutorial`.
|
||||
|
||||
.. versionadded:: 0.6
|
||||
.. versionchanged:: 2.2
|
||||
|
Loading…
Reference in New Issue
Block a user