Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Building autodocs for derived classes produces invalid warnings #9250

Closed
TheFriendlyCoder opened this issue May 19, 2021 · 7 comments
Closed

Comments

@TheFriendlyCoder
Copy link

Describe the bug
Generating API docs using the autodoc extensions, when a base class has doc strings in the constructor as well as in the class definition, and the autoclass_content feature is set to "both", produces superfluous warnings when parsing derived classes with overloaded constructors with no doc strings on them.

To Reproduce

  1. Create a base class with a constructor, and provide both a class doc string and a constructor doc string, something like this:
class MyBase:
    """Base class docstring"""

    def __init__(self, fubar):
        """
        Args:
            fubar (str):
                parameter description here
        """
  1. Create a derived class that has an overloaded constructor, with no doc string, something like this:
class MyDerived(MyBase):
    def __init__(self):
        pass
  1. Enable the auto content option in Sphinx to combine the class doc string and constructor doc strings together (ie: autoclass_content = "both" in the conf.py script)

  2. Attempt to generate the docs using the apidoc extension (ie: when using sphinxcontrib.apidoc, just run sphinx-build docs/ htmldocs/)

Expected behavior
Expected behavior: the API docs for both the base and derived classes should be generated without warnings.
Actual behavior: docs for the base class generate correctly, but docs for the derived class produce the following warning
"docstring of sample.MyDerived: WARNING: Unexpected indentation."

Environment info

  • OS: MacOS 11.3.1 (reproducible on several other Linux / Mac systems)
  • Python version: 3.6.8 (reproducible on several newer versions as well)
  • Sphinx version: 4.0.1 (reproducible on versions as far back as v2.2.0)
  • Sphinx extensions: sphinx.ext.autodoc,sphinx.ext.napoleon
  • Extra tools: (optional) sphinxcontrib.apidoc
@TheFriendlyCoder
Copy link
Author

This is a rather insidious warning because it points the developer to the derived class as the root cause of the problem, but there is no obvious correlation between the code of the derived class and the actual cause of the problem. This is further exacerbated when the derived class is in a different project or library from the base class, because then the developer needs to review the contents of the full inheritance stack. However, even after reviewing the code for the base class (which may or may not be the direct parent class of the one exposing the error) there is no obvious correlation between the warning and the code because the doc strings on the base class(es) are defined and correctly formatted, and Sphinx does not complain when generating the docs for the base class.

After much ad-hoc testing I was able to deduce that simply adding a doc string to the constructor on the derived class was sufficient to circumvent the error, but when working on a large number of Python projects and sharing those projects across many developers, problems like this are hard to avoid in practice.

My team manages dozens of Python projects, and are trying to build docs for all without having any warnings produced, so we've opted to disable the combined auto content flag to avoid these superfluous warnings. However, this is just a hack/workaround to get us by for now. I hope someone can investigate the root cause of this problem and fix it so that docs for derived classes can be generated without warnings.

@tk0miya
Copy link
Member

tk0miya commented May 19, 2021

I think what you want is autodoc_inherit_docstrings = False, right? There are no way to disable warnings during processing docstrings in superclasses.

@TheFriendlyCoder
Copy link
Author

Disabling inherited doc strings is not the solution for this bug. The doc strings can and should be inheritable here.

The problem is that one of the pre-processing steps involved with the auto content logic is trying to combine doc strings from the class and constructor of the base class as well as the derived class, and not aligning the formatting between them.

@TheFriendlyCoder
Copy link
Author

To be clear, this code snippet produces warnings:

class MyBase:
    """Base class docstring"""

    def __init__(self, fubar):
        """
        Args:
            fubar (str):
                parameter description here
        """
class MyDerived(MyBase):
    def __init__(self):
        pass

Where as this code snippet does not:

class MyBase:
    """Base class docstring"""

    def __init__(self, fubar):
        """
        Args:
            fubar (str):
                parameter description here
        """
class MyDerived(MyBase):
    def __init__(self):
        """testing"""
        pass

Both of these examples are valid Python class definitions, with valid doc strings. Both the inherited docstring functionality AND the auto content combining logic should work in both situations.

@tk0miya
Copy link
Member

tk0miya commented May 22, 2021

Thank you for your explanation. I misunderstood the problem!

@tk0miya
Copy link
Member

tk0miya commented May 22, 2021

Internally, the example is expanded to the following code (without napoleon extension):

.. py:class:: MyBase(fubar)
   :module: example

   Base class docstring

   :param fubar: parameter description here
   :type fubar: str


.. py:class:: MyDerived()
   :module: example

   Args:
   fubar (str):
       parameter description here

The second and following lines of the inherited method not having docstring is unindented. This is unexpected behavior and it's a bug.

tk0miya added a commit to tk0miya/sphinx that referenced this issue May 22, 2021
…ng is wrongly parsed

`sphinx.util.inspect.getdoc()` clean the docstring up if the method is
inherited and not having docstring.  That causes indentations are
removed on processing it.
@tk0miya tk0miya added this to the 4.1.0 milestone May 22, 2021
tk0miya added a commit to tk0miya/sphinx that referenced this issue May 22, 2021
…fect to classes

The docstring of the superclass is not extracted even if the docstring
of the subclass is empty and autodoc_inherited_docstrings=True.

This adds `sphinx.util.inspect.getclassdoc()` to respect the configuration
on getting docstring.
tk0miya added a commit that referenced this issue May 23, 2021
Fix #9250: autodoc: The inherited method not having docstring is wrongly parsed
tk0miya added a commit to tk0miya/sphinx that referenced this issue May 23, 2021
…fect to classes

The docstring of the superclass is not extracted even if the docstring
of the subclass is empty and autodoc_inherited_docstrings=True.

This adds `sphinx.util.inspect.getclassdoc()` to respect the configuration
on getting docstring.
tk0miya added a commit to tk0miya/sphinx that referenced this issue May 23, 2021
…fect to classes

The docstring of the superclass is not extracted even if the docstring
of the subclass is empty and autodoc_inherited_docstrings=True.

This adds `sphinx.util.inspect.getclassdoc()` to respect the configuration
on getting docstring.
@TheFriendlyCoder
Copy link
Author

Awesome! Thanks for the quick turnaround on this. Hopefully that means it was an easy fix!

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jul 10, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants