1

I have a class structured as follow:

class BaseObject(IBaseObject):
    """
    DESCRIPTION 1
    """

    class Setup(TypedDict, total=False):
        """
        DESCRIPTION 1.1
        """
        log_id:IntKEY
        """DESCRIPTION 1.1.1"""
        name:str
        """DESCRIPTION 1.1.2"""

and another class like this:

class VersionInfo(BaseObject):
    """
    DESCRIPTION 2

    """
    class Setup(BaseObject.Setup):
        items_dict:Dict[str,int]
        """DESCRIPTION 2.1.1"""
        hash:int
        """DESCRIPTION 2.1.2"""

When I create the documentation, I would like to see in VersionInfo.Setup the DESCRIPTION 1.1.1 and 1.1.2 used in the BaseObject.Setup's attributes (inherited), but I can only see the list of attributes without the description.

I tried to use :inherited-members: but only the TypedDict functions are added.

EDIT: The class

class IBaseObject():
    @abstractmethod
    def setup(self, params:Optional[TypedDict]) -> None:
        raise NotImplementedError("Should implement setup method")

    @abstractmethod
    def InFields(self, filer:QSFiler) -> bool:
        raise NotImplementedError("Should implement setup method")

is just a simple class with a couple of abstract methods not related to the nested class Setup.

IntKEY is just an int value

IntKEY = int
bad_coder
  • 11,289
  • 20
  • 44
  • 72
AsiaLootus
  • 112
  • 1
  • 10

1 Answers1

1

In this solution inheritance from dict and IBaseObject is not shown by using the :exclude-members: option, as to not clutter the result visually. It's easy to fine-tune the working solution to your needs.

image of resulting documentation

Below are the classes grouped into a single code fence (to ease copy-pasting). QSFiler wasn't defined in the question so it's changed to int, but that's the only difference from the code in the question. Let's assume it's a module called inner_class_problem.py, because a module/package name will be necessary for referencing by name.

from abc import abstractmethod
from typing import TypedDict, Optional, Dict

IntKEY = int

class IBaseObject:

    @abstractmethod
    def setup(self, params: Optional[TypedDict]) -> None:
        raise NotImplementedError("Should implement setup method")

    @abstractmethod
    def InFields(self, filer: int) -> bool:
        raise NotImplementedError("Should implement setup method")

class BaseObject(IBaseObject):
    """
    DESCRIPTION 1
    """
    class Setup(TypedDict, total=False):
        """
        DESCRIPTION 1.1
        """
        log_id: IntKEY
        """DESCRIPTION 1.1.1"""
        name: str
        """DESCRIPTION 1.1.2"""

class VersionInfo(BaseObject):
    """
    DESCRIPTION 2

    """
    class Setup(BaseObject.Setup):
        items_dict: Dict[str, int]
        """DESCRIPTION 2.1.1"""
        hash: int
        """DESCRIPTION 2.1.2"""

The corresponding reStructuredText file inner_class_problem.rst

inheritance with inner class
----------------------------

.. automodule:: inner_class_problem
    :members:
    :exclude-members: IBaseObject, BaseObject, VersionInfo

    .. autoclass:: IBaseObject
        :members:

    .. autoclass:: BaseObject
        :members:

    .. autoclass:: VersionInfo
        :members:
        :exclude-members: Setup

        .. autoclass:: inner_class_problem.VersionInfo::Setup
            :members:
            :inherited-members: dict
            :exclude-members: log_id, name

            .. autoattribute:: inner_class_problem.BaseObject::Setup.log_id
                :noindex:

            .. autoattribute:: inner_class_problem.BaseObject::Setup.name
                :noindex:

The problem statement was: the inner class VersionInfo.Setup didn't render the comments that document the inhereted variables BaseObject.Setup.log_id and BaseObjectSetup.name.

In order to circumvent this, you can sucessivly use the :exclude-members: option to isolate VersionInfo.Setup afterwards using the .. autoattribute:: directive to include the inherited variables BaseObject.Setup.name and BaseObject.Setup.log_id straight from the parent class into the child class (:noindex: option was used - see Options and avanced usage- to avoid a duplicate warning being issued by Sphinx).

This is inconvenient but it's probably your best choice. There are some alternatives, like writing the documentation of log_id and name directly in the .rst files with domain declarations.

Generally documentation of members from parent classes isn't repeated in child classes, because it's just a repetition. A class signature that inherits implicitly tells you the inherited members will be documented in the parent class.

bad_coder
  • 11,289
  • 20
  • 44
  • 72
  • I tried your code, but the warning "WARNING: missing attribute :exclude-members: Setup in object ..." raises and all the members are excluded... – AsiaLootus Feb 10 '21 at 16:01
  • 1
    @AsiaLootus the answer has 2 files (one `.py` and one `.rst`) test them isolated from the rest of your project (you just need to copy the files and link the `.rst` file in your `.. toctree::` as you normally do). I just double checked again and this works exactly *"as is"*. (The solution is correct). – bad_coder Feb 10 '21 at 16:09
  • 1
    Yes, the solution isolated in another project works. I also manage to use it also in my project (I have to add `:undoc-members:` in .. autoclass:: inner_class_problem.VersionInfo::Setup and remove `:inherited-members: dict`). Could be the latter related to the fact that I'm using `from typing_extensions import TypedDict` instead of `from typing import TypedDict`? Thank you for your support! – AsiaLootus Feb 11 '21 at 10:00
  • @AsiaLootus `:undoc-members:` and `:members:` is well explained at the beginning of [this post](https://stackoverflow.com/a/64601933). Having inheritance [complicates things](https://github.com/sphinx-doc/sphinx/issues/741#issuecomment-500229049). [typing-extensions](https://pypi.org/project/typing-extensions/) backports the standard library `typing` module, implementation details aren't clear. It's not possible to fully explain in just a comment, carefully read [`:inherited-members:`](https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html) and do trial&error experiments. – bad_coder Feb 11 '21 at 16:38
  • @AsiaLootus if you run into further problems the best approach is opening a new question, including a [Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example) with all necessary specifics, and preferably following the 2 file format like in the answer. – bad_coder Feb 11 '21 at 16:59