Advanced Usage

The following topics may be relevant when working on real-world documentation projects, which often demand a greater level of customization.

A TOC for every class

It is also possible to use autoclasstoc in auto-generated API documentation, i.e. where all of the classes in your project are documented without you having to explicitly write an autoclass directive for each one. The way to do this is to use the sphinx.ext.autosummary extension with a custom Jinja template for classes, as detailed below:

  1. Configure the sphinx.ext.autosummary extension to automatically generate stub files each time the documentation is built:

    conf.py
    autosummary_generate = True
    

    Alternatively, you could generate stub files yourself by running the autogen command when necessary (after completing steps 2 and 3 below). I find this less convenient, but it might be better if you intend to edit the stub files by hand:

    $ sphinx-autogen -t _templates path/to/doc/with/autosummary.rst
    
  2. Add an autosummary directive with the :toctree: and :recursive: options to your documentation. Anywhere will work, but index.rst is a common choice:

    index.rst
    .. autosummary::
       :toctree: path/to/directory/for/autogenerated/files
       :recursive:
    
       mоdulе.tо.dосumеnt
    
  3. Provide a custom Jinja template for formatting class stub files. The purpose of this template is to specify that autoclasstoc should be used for each class:

    _templates/autosummary/class.rst
    {{ fullname | escape | underline}}
    
    .. currentmodule:: {{ module }}
    
    .. autoclass:: {{ objname }}
       :members:
       :undoc-members:
       :special-members:
       :private-members:
       :inherited-members:
       :show-inheritance:
    
       .. autoclasstoc::
    

    Note that the name of the _templates directory depends on the value of the templates_path setting in conf.py.

Custom sections

By default, autoclasstoc divides the TOC into sections based whether or not attributes are methods, and whether or not they are public. This is a reasonable default, but for many projects it may make sense to add custom sections specific to the idioms of that project. Fortunately, this is easy to configure. The basic steps are:

  1. Define new autoclasstoc.Section subclasses.

  2. Reference the subclasses either in conf.py or in the documentation itself.

This approach is very powerful, because the Section class controls all aspects of defining and formatting the TOC sections, and its subclasses can overwrite any of that behavior. Below are some specific examples showing how custom sections can be configured:

Based on name

Categorizing attributes based on their names is convenient, because it doesn’t require making any changes or annotations to the code itself. For this example, we’ll make a custom “Event Handlers” section that will consist of methods that begin with the prefix “on_”, e.g. on_mouse_down() or on_key_up().

The first step is to define a new Section subclass with the following attributes:

  • key: used to include or exclude the section from class TOCs.

  • title: how the section will be labeled in the documentation.

  • predicate(): which attributes to include in the section.

conf.py
from autoclasstoc import Section, is_method

class EventHandlers(Section):
    key = 'event-handlers'
    title = "Event Handlers:"

    def predicate(self, name, attr, meta):
        return is_method(name, attr) and name.startswith('on_')

We also have to redefine the “Public Methods” section, so that it doesn’t include the event handlers (as it otherwise would):

conf.py
from autoclasstoc import PublicMethods

class RemainingPublicMethods(PublicMethods):
    exclude_section = EventHandlers

Finally, we need to specify that our new sections should be used by default (and what order they should go in):

conf.py
autoclasstoc_sections = [
        'event-handlers',
        'public-methods',
        'private-methods',
]

Based on pattern

Excluding attributes from a section based on their name is a common desire. To make this easier, Section classes have a exclude_pattern attribute that filters any matching attributes out of the section. To demonstrate how this works, we’ll make a custom “Public Methods” section that will consist of public methods but excluding all “dunders” methods, e.g. __init__().

The first step is to define a new PublicSection subclass with the following attributes:

  • key: used to include or exclude the section from class TOCs.

  • exclude_pattern: used for regex matching of the name for exclusion

conf.py
from autoclasstoc import PublicSection, is_method

class PublicMethodsWithoutDunders(PublicSection):
    key = 'public-methods-without-dunders'
    exclude_pattern = '__'

autoclasstoc_sections = [
        'public-methods-without-dunders',
        'private-methods',
]

No more is necessary because the PublicSection (and all other Section subclasses) check for possible exclude_pattern. Note here, that exclude_pattern can also be a list of strings.

This class we just created (PublicMethodsWithoutDunders) is already within autoclasstoc. It can be used with the key public-methods-without-dunders in the autoclasstoc_sections variable.

Based on decorator

A more explicit way to categorize methods is to use a decorator to label methods that belong to a particular section. This approach only is only applicable to methods and inner classes (because data attributes cannot be decorated), but is easy to implement. For this example, we’ll make a section for “Read Only” methods that are identified by a decorator:

The first step is to write a decorator to label read-only methods:

def read_only(f):
    f.__readonly__ = True
    return f

class MyClass:

    @read_only
    def do_nothing(self):
        pass

Next, we have to define Section subclasses that are aware of the decorator:

conf.py
from autoclasstoc import Section

class ReadOnlySection(Section):
    key = 'read-only'
    title = "Read-Only Methods:"

    def predicate(self, name, attr, meta):
        return getattr(attr, '__readonly__', False)

class ReadWriteSection(Section):
    key = 'read-write'
    title = "Read/Write Methods:"

    def predicate(self, name, attr, meta):
        return not getattr(attr, '__readonly__', False)

autoclasstoc_sections = [
        'read-only',
        'read-write',
]

Note that this example removes the distinction between private and public methods, so both the “Read-Only” and “Read/Write” sections will contain public and private methods.

Based on :meta: fields

With sphinx.ext.autodoc, it’s possible to describe how an object should be documented by including :meta: fields in that object’s docstring. autoclasstoc automatically parses these fields and provides them as an argument to predicate(), so they can be easily used to categorize attributes. As in the previous example, we’ll make a custom section for read-only methods. The snippet below shows how such a method might be identified using a meta field:

class MyClass:

    def do_nothing(self):
        """
        This method doesn't do anything.

        :meta read-only:
        """
        pass

These meta fields are parsed into a dictionary such that :meta key: value would give {'key': 'value'}. This dictionary is provided to the predicate() method via the meta argument:

conf.py
from autoclasstoc import Section

class ReadOnlySection(Section):
    key = 'read-only'
    title = "Read-Only Methods:"

    def predicate(self, name, attr, meta):
        return 'read-only' in meta

class ReadWriteSection(Section):
    key = 'read-write'
    title = "Read/Write Methods:"

    def predicate(self, name, attr, meta):
        return 'read-only' not in meta

autoclasstoc_sections = [
        'read-only',
        'read-write',
]

Custom CSS

All of the HTML elements generated by autoclasstoc are contained in a <div> with class autoclasstoc. This can be used to select and style the elements in the class TOC. Note that the plugin includes some default rules to control the spacing around the <details> elements that contain TOCs for inherited attributes.