'Why does sphinx autosummary not create a toctree when used inside a class?

I am trying to use ..autosummary to document a module that replaces itself with a class upon import (lazy importing). Without lazy imports the module looks like this:

""" The demp_project package

The demp_project consists of the following classes

.. autosummary::
    :toctree: _autosummary

    demp_project.Foo
    demp_project.Bar

"""


class Foo:
    """ Summary of class Foo
    
    Here comes extensive documentation.
    
    """


class Bar:
    """ Summary of class Bar

    even more extensive documentation.
    
    """

Sphinx enters the above via .. automodule:: demp_project. However, when I now add the lazy importing hook, building the documentation breaks on python 3.9 and 3.10 (python 3.7 and 3.8 work fine), i.e., the documentation for the classes Foo and Bar is not generated anymore. Instead I get the following warning:

docstring of demp_project:5:autosummary: stub file not found 'demp_project.Foo'. Check your autosummary_generate setting.

This is how the module looks like after modifying it for lazy importing:

import sys

class Foo:
    """ Summary of class Foo
    
    Here comes extensive documentation.
    
    """


class Bar:
    """ Summary of class Bar

    even more extensive documentation.
    
    """

class LazyImporter:
    """ The demp_project package

    The demp_project consists of the following classes:

    .. autosummary::
        :toctree: _autosummary

        demp_project.Foo
        demp_project.Bar

    """

    __name__ = __name__

    def __getattr__(self, name):
        """Lazy-Import Awesome Things

        Note: this doesn't actually lazy import here, because everything is in
        the same file for demo purposes. In the real world, this calls
        importlib.import_module to make the magic happen.

        """

        if name == "Foo":
            return Foo
        elif name == "Bar":
            return Bar
        else:
            raise AttributeError(f"module '{__name__}' has no attribute '{name}'")

sys.modules[__name__] = LazyImporter()

Could somebody explain to me why this breaks? Also, why does it work for python <= 3.8?

For reference, I made a repo containing the full demo project. The main branch builds the docs normally (first code block), and the PR introduces lazy importing (second code block).

Note: the repo has CI that builds the docs on python 3.7 - 3.10 to demo the problem with different python versions.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source