From 1ac05a2a832dfecfbf9431e919cb9f3b99ebf11f Mon Sep 17 00:00:00 2001 From: igo95862 Date: Mon, 8 Mar 2021 12:18:25 +0300 Subject: [PATCH 1/4] doc: Create autodoc extension tutorial --- doc/development/tutorials/autodoc_ext.rst | 140 ++++++++++++++++++ .../tutorials/examples/autodoc_intenum.py | 52 +++++++ 2 files changed, 192 insertions(+) create mode 100644 doc/development/tutorials/autodoc_ext.rst create mode 100644 doc/development/tutorials/examples/autodoc_intenum.py diff --git a/doc/development/tutorials/autodoc_ext.rst b/doc/development/tutorials/autodoc_ext.rst new file mode 100644 index 000000000..eca0e5120 --- /dev/null +++ b/doc/development/tutorials/autodoc_ext.rst @@ -0,0 +1,140 @@ +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 `. 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 + + diff --git a/doc/development/tutorials/examples/autodoc_intenum.py b/doc/development/tutorials/examples/autodoc_intenum.py new file mode 100644 index 000000000..7fb85d066 --- /dev/null +++ b/doc/development/tutorials/examples/autodoc_intenum.py @@ -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) From a56f69b916c1ae139eb1f38ee6d147b71b3d1d59 Mon Sep 17 00:00:00 2001 From: igo95862 Date: Mon, 8 Mar 2021 12:21:56 +0300 Subject: [PATCH 2/4] doc: Added autodoc extension tutorial to tutorials index --- doc/development/tutorials/index.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/development/tutorials/index.rst b/doc/development/tutorials/index.rst index be126b3ca..a7eee4899 100644 --- a/doc/development/tutorials/index.rst +++ b/doc/development/tutorials/index.rst @@ -13,3 +13,5 @@ Refer to the following tutorials to get started with extension development. helloworld todo recipe + autodoc_ext + From c57cb0b5ed02990b376ffc8b3ba58a95c4faba70 Mon Sep 17 00:00:00 2001 From: igo95862 Date: Mon, 8 Mar 2021 12:23:02 +0300 Subject: [PATCH 3/4] doc: Link autodoc tutorial in add_autodocumenter docstring Uses :ref: link because :doc: does not work. --- sphinx/application.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/application.py b/sphinx/application.py index b5cc44268..7812cecc9 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -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 From 7ee2000598716262cf802594165cd12c20f16d23 Mon Sep 17 00:00:00 2001 From: igo95862 Date: Mon, 8 Mar 2021 12:45:43 +0300 Subject: [PATCH 4/4] doc: Added reflink to autodoc tutorial Used in add_autodocumenter docstring --- doc/development/tutorials/autodoc_ext.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/development/tutorials/autodoc_ext.rst b/doc/development/tutorials/autodoc_ext.rst index eca0e5120..d8905710c 100644 --- a/doc/development/tutorials/autodoc_ext.rst +++ b/doc/development/tutorials/autodoc_ext.rst @@ -1,3 +1,5 @@ +.. _autodoc_ext_tutorial: + Developing autodoc extension for IntEnum ========================================