Skip to content

Docstring implicit inheritance can render cross-reference targets ambiguous. #6211

Open

Description

@anntzer

Describe the bug

When a subclass is added, implicit docstring inheritance by its methods can create ambiguous cross-reference targets in the docstrings of the methods of the parent class.

To Reproduce

Start with a minimal project:

$ sphinx-quickstart --sep --dot _ -pfoo -afoo -r0 -len --suffix .rst --master index --ext-autodoc -m

Edit index.rst to include

.. automodule:: themodule
   :members:

and write the following themodule.py:

class A:
    """The A."""

    def dothis(self):
        """Call :obj:`.dothat`."""

    def dothat(self):
        """Really do it."""


class Unrelated:
    """Nothing related."""

    def dothat(self):
        """Has the same name as :obj:`A.dothat`, but otherwise unrelated."""

Build the docs with themodule.py in the PYTHONPATH (PYTHONPATH=. make html) -- things work fine; in particular the doc of A.dothis correctly links to A.dothat.

Now let's say someone adds (in the same module) a subclass of A that overrides dothis, but doesn't bother with a docstring:

class B(A):
    def dothis(self): pass

Trying to build the docs now results in a warning:

/tmp/testdocs/themodule.py:docstring of themodule.B.dothis:1: WARNING: more than one target found for cross-reference 'dothat': themodule.A.dothat, themodule.Unrelated.dothat

i.e. B.dothis inherited A.dothis's docstring, but doesn't know what ":obj:`.dothat`" is supposed to refer to. I believe it should actually resolve it to mean B.dothat (which happens to be equal to A.dothat). (emphasis as this is the actual issue at hand) Indeed, if B also defines dothat:

class B(A):
    def dothis(self): pass
    def dothat(self): pass

then the docstring of B.dothis does link to B.dothat.

Expected behavior

In B.dothis's docstring, ":obj:`.dothat`" should link to A.dothat (if B.dothat does not exist).

Your project
n/a

Screenshots
n/a

Environment info

  • OS: linux
  • Python version: 3.7.2
  • Sphinx version: 1.8.5
  • Sphinx extensions: sphinx.ext.autodoc
  • Extra tools: n/a

Additional context
Add any other context about the problem here.

  • [e.g. URL or Ticket]

Activity

  1. added this to the 2.1.0 milestone on Mar 31, 2019
  2. modified the milestones: 2.1.0, 2.2.0 on Jun 1, 2019
  3. modified the milestones: 2.2.0, 2.3.0 on Aug 18, 2019
  4. anntzer commented on Nov 17, 2019

    @anntzer
    ContributorAuthor

    I looked a bit into how to resolve this (and other similar issues, e.g. Derived classes in other modules losing the ability to refer to things defined in the module of the parent class). Unfortunately, it looks like by the time the references are getting resolved (in resolve_xref), the information that B derives from A (and thus that the docstrings should be resolved by preferring A) has been lost. Indeed, even when using :show-inheritance:, autodoc just formats the parent classes as

        Bases: :class:`...`
    

    It may help if :py:class: gained the ability to record base classes, e.g.

    .. py:class:: Derived
       :bases: Base, fully.qualified.base.Name
    

    (one can't use .. py:class:: Derived(Base, ...) because parentheses specify the constructor signature).

  5. modified the milestones: 2.3.0, 2.4.0 on Dec 8, 2019
  6. modified the milestones: 2.4.0, 3.0.0 on Feb 7, 2020
  7. modified the milestones: 3.0.0, 3.1.0 on Mar 14, 2020
  8. 8 remaining items

  9. modified the milestones: 4.1.0, 4.2.0 on Jul 10, 2021
  10. modified the milestones: 4.2.0, 4.3.0 on Sep 12, 2021
  11. modified the milestones: 4.3.0, 4.4.0 on Nov 9, 2021
  12. modified the milestones: 4.4.0, 4.5.0 on Jan 15, 2022
  13. modified the milestones: 4.5.0, 5.0.0 on Mar 27, 2022
  14. modified the milestones: 5.0.0, 5.x on May 15, 2022
  15. spaceone commented on Oct 13, 2025

    @spaceone
    Contributor

    CC me, as I am also affected by this bug.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions