readthedocs / sphinx-autoapi

A new approach to API documentation in Sphinx.
https://sphinx-autoapi.readthedocs.io/
MIT License
432 stars 128 forks source link

`sphinx-autoapi==3.1.0` fails to properly handle Python imports #447

Closed odimko closed 4 months ago

odimko commented 4 months ago

Hi all! The latest update of the sphinx-autoapi (3.1.0) fails to properly handle Python imports and fails with the following error:

Warning, treated as error:
  /home/runner/work/repos/amazing_repo/docs/source/autoapi/src/generator/sample/generate_csv_sample/index.rst:905:more than one target found for cross-reference 'ConnRegisterType': src.generator.sample.sample_generator.ConnRegisterType, src.variable.ConnRegisterType

where ConnRegisterType is defined in src.variable:

class ConnRegisterType(StrEnum):
    """
    Docstring.
    """

    VAR1 = "str1"
    VAR2 = "str2"
    VAR3 = "str3"
    VAR4 = "str4"

and it is indirectly imported in src/generator/sample/generate_csv_sample.py

AWhetter commented 4 months ago

If a class or function is available in your API in two places, then it'll get documented in two places. You can control which gets documented using the methods documented here: https://sphinx-autoapi.readthedocs.io/en/latest/how_to.html#how-to-customise-what-gets-documented

odimko commented 4 months ago

Hi @AWhetter , Let me try to clarify further as I believe I was not fully clear (I am sorry if that is the case). The class is only defined once in src/variable.py:

class ConnRegisterType(StrEnum):
    """
    Docstring.
    """

    VAR1 = "str1"
    VAR2 = "str2"
    VAR3 = "str3"
    VAR4 = "str4"

After that, it is imported in src/generator/sample/sample_generator.py as:

from src.variable import (
    ...,
    ConnRegisterType,
    ...,
)

and, finally, the latter module, src/generator/sample/sample_generator.py, is imported in src/generator/sample/generate_csv_sample.py as:

from src.generator.sample.sample_generator import SampleGenerator

Is it still the case, that with such import structure, I'd need to specify which occasion exactly gets documented? I would appreciate any details.

AWhetter commented 4 months ago

Yes exactly. A user could import your class by doing either of the following:

from src.variable import ConnRegisterType
from src.generator.sample.sample_generator import SampleGenerator

Therefore, without more information, AutoAPI doesn't know which you want documented so it documents both.

adamnovak commented 3 months ago

I'm running into this same issue, trying to upgrade a large project from sphinx-autoapi 3.0 to 3.1: https://github.com/DataBiosphere/toil/issues/4940#issuecomment-2155491396

With 3.1, I get warnings that each place I import a class by name is a possible target for each reference to it generated by type annotations. With 3.0 only the place a class is initially defined is seen as a target.

How would I provide the necessary information to say that the type annotations' references should in general be resolved in favor of the initial definition and not all the imported aliases, to get the 3.0 behavior on 3.1? Or how do I in general suppress the generation of documentation for the aliases?

adamnovak commented 3 months ago

It looks like one answer might be to make sure to define autoapi_options in the Sphinx conf.py configuration file, and not put imported-members in it. I'm not sure how one would then go about making sure that documentation is generated for a particular list of imported members, but this seems to not make the many ambiguous targets for the references that Sphinx than warns about.

My project actually already has a autodoc-skip-member handler attached; maybe I just need to figure out how to identify when something is an imported-members item there?

adamnovak commented 3 months ago

Apparently one can identify an imported member in an autodoc-skip-member handler by looking at the obj argument and checking if "original_path" is in it like sphinx-autodoc itself does. So if I need some but not all imported members documented, I can put the logic there.