Search code examples
pythonpython-sphinxmagic-methods

autosummary generated documentation missing all dunder methods except for `__init__`


I am using Sphinx's autosummary to automatically generate individual rst files for each member of my module. The documentation is created as expected, except that the generated rst files are missing all dunder methods except for __init__.

In my conf.py I've got the following lines:

extensions = [
    'sphinx.ext.autodoc',
    'sphinx.ext.autosummary',
]

autosummary_generate = True
autosummary_imported_members = True

Consider the dummy class below, which contains both dunder and regular public methods:

class MyClassA:

    def __init__(self):
        r'__init__ docstring'
        pass

    def __call__(self):
        r'__call__ docstring'
        pass

    def __len__(self):
        r'__len__ docstring'
        pass

    def public_method_1(self):
        r'public_method_1 docstring'
        pass

    def public_method_2(self):
        r'public_method_2 docstring'
        pass

In my main rst file, I set up autosummary as follows:

.. autosummary::
    :toctree: my_module_members

    my_module.MyClassA
    my_module.MyClassB

As expected, autosummary creates a subdirectory named /my_module_members with individual rst files for each member of the module. But only __init__ is listed in the Methods section of these automatically generated rst files. E.g.:

my_module.MyClassA
==================

.. currentmodule:: my_module

.. autoclass:: MyClassA




   .. rubric:: Methods

   .. autosummary::

      ~MyClassA.__init__
      ~MyClassA.public_method_1
      ~MyClassA.public_method_2

Thus, in the html documentation generated, only those three methods are listed in the methods table, and __call__ and __len__ are not there:

enter image description here

So my question is how to include all special methods when using autosummary in this way?


Solution

  • The issue is with the default template that autosummary uses for classes. This is the relevant page in the documentation, but it's more helpful to look at the default template directly:

    # In the sphinx v3.0.4 source code:
    # sphinx/ext/autosummary/templates/autosummary/class.rst
    {{ fullname | escape | underline}}
    
    .. currentmodule:: {{ module }}
    
    .. autoclass:: {{ objname }}
    
       {% block methods %}
       .. automethod:: __init__
    
       {% if methods %}
       .. rubric:: Methods
    
       .. autosummary::
       {% for item in methods %}
          ~{{ name }}.{{ item }}
       {%- endfor %}
       {% endif %}
       {% endblock %}
    
       {% block attributes %}
       {% if attributes %}
       .. rubric:: Attributes
    
       .. autosummary::
       {% for item in attributes %}
          ~{{ name }}.{{ item }}
       {%- endfor %}
       {% endif %}
       {% endblock %}
    

    You can see how this template corresponds to the stub files that were generated for your project (although I'm not sure why yours is missing the .. automethod:: __init__ line; maybe we have different versions of sphinx). The important part is the {% for item in methods %} loop. The docs linked above briefly mention that methods only include "public" methods, which means methods that don't begin with an underscore. __init__() is also considered public, as per line 242 of sphinx/ext/autosummary/generate.py, although this doesn't seem to be documented anywhere. So hopefully that explains the behavior you're seeing.

    With that in mind, I can think of three ways to include all of the special methods in the documentation:

    1. Provide a custom template that uses members instead of methods. This should document everything, but will eliminate the distinction between methods, attributes, inherited members, inner classes, etc.

    2. This isn't documented and I haven't tried it, it looks like you might be able to replace methods with all_methods to include all methods in the autosummary (see line 242 again). There won't be any distinction between public and private methods, though.

    3. Try using autoclasstoc. Full disclosure: this is a package I wrote to do a better job of summarizing class methods in sphinx docs. It's much more configurable than autosummary, and it includes every method by default. It also collapses inherited methods, which can be really nice for big classes, although that may or may not be relevant to you.

      This page describes how to use autoclasstoc in conjunction with autosummary, but the gist of it is that you need a custom template that looks something like this:

      {{ fullname | escape | underline}}
      
      .. currentmodule:: {{ module }}
      
      .. autoclass:: {{ objname }}
         :members:
         :special-members:
      
          .. autoclasstoc::