Skip to content

Sphinx 4.x + :any: + autodoc + aliasing objects = warning #10088

@ewjoachim

Description

@ewjoachim

Describe the bug

Let's say you have a module:

# mypackage/module.py
class A:
    pass

And expose it in your __init__.py:

from .module import A
__all__ = ["A"]

In your doc, you want to expose the "official" api:

.. autoclass:: mypackage.A

And reference it:

Use the :any:`A` class

Alternatively, in conf.py use default_role = "any" and in your doc:

Use the `A` class

Then autodoc will output an warning:

more than one target found for 'any' cross-reference 'A': could be :py:class:`mypackage.A` or :py:class:`myackage.module.A`

And if building with -W, this warning will be an error.
I believe there's no way to avoid this warning without abandoning :any: altogether.

How to Reproduce

$ git clone git@github.com:ewjoachim/sphinx-bug-any-canonical.git
$ cd sphinx-bug-any-canonical
$ pip install -r requirements.txt
$ cd docs
$ make SPHINX_OPTS=-W html
<build fails>

Expected behavior

There used to be a way for me to simultaneously:

  • Use :any:
  • Define the API of my project in __init__.py while having the real classes live elsewhere
  • use autodoc
  • build with -W

without the combination of those things failing the build. I can probably rewrite a lot of documentation to use explicit py:obj: classes instead of any but it would be a lot of work, and I'm not sure it would make my doc more readable.

Your project

https://github.com/ewjoachim/sphinx-bug-any-canonical

Screenshots

No response

OS

Linux

Python version

3.8, 3.9, 3.10

Sphinx version

latest stable: 4.3.2

Sphinx extensions

sphinx.ext.autodoc

Extra tools

No response

Additional context

I believe what happens is that:

  • sphinx/ext/autodoc/__init__.py ClassDocumenter.add_directive_header we have
        canonical_fullname = self.get_canonical_fullname()
        if not self.doc_as_attr and canonical_fullname and self.fullname != canonical_fullname:
            self.add_line('   :canonical: %s' % canonical_fullname, sourcename)

This means that the py:class directive that will be generated by autodoc will have a :canonical: option

  • sphinx/domains/python.py PyObject.add_target_and_index
        canonical_name = self.options.get('canonical')
        if canonical_name:
            domain.note_object(canonical_name, self.objtype, node_id, aliased=True,
                               location=signode)

If an object has a canonical option, both names will be added to the known objects.

This means that :any:`Class` will always end up confused, and issue a warning.

I don't know how I can solve this.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions