readthedocs / sphinx-autoapi

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

Sphinx Build fails on `AttributeError: 'AssignName' object has no attribute 'getattr'` #480

Open michaelweinold opened 2 months ago

michaelweinold commented 2 months ago

Our sphinx build on readthedocs.org is failing on an error likely related to sphinx-autoapi. Surprisingly, this is even though we had pinned the package version in the environment recipe:

name: sphinx_documentation
channels:
  - conda-forge
  - nodefaults
dependencies:
  # core functionality
  - python=3.12
  - ipython
  # sphinx
  - sphinx=7.4.7 # core builder # https://anaconda.org/conda-forge/sphinx/files
  # theme and extensions
  - pydata-sphinx-theme=0.15.4 # website theme # https://anaconda.org/conda-forge/pydata-sphinx-theme/files
  - myst-parser=4.0.0 # Markdown support # https://anaconda.org/conda-forge/myst-parser/files
  - myst-nb=1.1.1 # Jupyter notebook support # https://anaconda.org/conda-forge/myst-nb/files
  - sphinx-autoapi=3.3.1 # to build docs from source code instead of package import # https://anaconda.org/conda-forge/sphinx-autoapi/files
  - sphinx-design=0.6.1 # responsive web component support # https://anaconda.org/conda-forge/sphinx-design/files
  - sphinx-notfound-page=1.0.4 # custom 404 page # https://anaconda.org/conda-forge/sphinx-notfound-page/files
  - graphviz=12.0.0 # for plotting dependency diagrams with sphinx-autoapi # https://anaconda.org/conda-forge/graphviz/files
  - sphinx-favicon=1.0.1 # for custom favicons # https://anaconda.org/conda-forge/sphinx-favicon/files
  - sphinx-copybutton=0.5.2 # for copy button in code blocks # https://anaconda.org/conda-forge/sphinx-copybutton/files
  # build process
  - sphinx-autobuild=2024.9.3 # live-html support # https://anaconda.org/conda-forge/sphinx-autobuild/files
Exception occurred:
  File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/autoapi/inheritance_diagrams.py", line 14, in _do_import_class
    target = (target.getattr(path_part) or (None,))[0]
              ^^^^^^^^^^^^^^
AttributeError: 'AssignName' object has no attribute 'getattr'

The only change in our documentation that occurred prior to this build failure were edits to the source code of a submodule that sphinx-autoapi is documenting: https://github.com/brightway-lca/brightway-documentation/commit/6910b282704dd5df2a8898072ecff90625fe3076

Full Traceback ``` Traceback (most recent call last): File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/sphinx/cmd/build.py", line 337, in build_main app.build(args.force_all, args.filenames) File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/sphinx/application.py", line 378, in build self.builder.build_update() File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/sphinx/builders/__init__.py", line 297, in build_update self.build(to_build, File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/sphinx/builders/__init__.py", line 318, in build updated_docnames = set(self.read()) ^^^^^^^^^^^ File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/sphinx/builders/__init__.py", line 425, in read self._read_serial(docnames) File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/sphinx/builders/__init__.py", line 477, in _read_serial self.read_doc(docname) File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/sphinx/builders/__init__.py", line 536, in read_doc publisher.publish() File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/docutils/core.py", line 234, in publish self.document = self.reader.read(self.source, self.parser, ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/sphinx/io.py", line 106, in read self.parse() File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/docutils/readers/__init__.py", line 76, in parse self.parser.parse(self.input, document) File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/sphinx/parsers.py", line 83, in parse self.statemachine.run(inputlines, document, inliner=self.inliner) File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/docutils/parsers/rst/states.py", line 169, in run results = StateMachineWS.run(self, input_lines, input_offset, ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/docutils/statemachine.py", line 233, in run context, next_state, result = self.check_line( ^^^^^^^^^^^^^^^^ File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/docutils/statemachine.py", line 445, in check_line return method(match, context, next_state) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/docutils/parsers/rst/states.py", line 2790, in underline self.section(title, source, style, lineno - 1, messages) File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/docutils/parsers/rst/states.py", line 325, in section self.new_subsection(title, lineno, messages) File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/docutils/parsers/rst/states.py", line 391, in new_subsection newabsoffset = self.nested_parse( ^^^^^^^^^^^^^^^^^^ File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/docutils/parsers/rst/states.py", line 279, in nested_parse state_machine.run(block, input_offset, memo=self.memo, File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/docutils/parsers/rst/states.py", line 195, in run results = StateMachineWS.run(self, input_lines, input_offset) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/docutils/statemachine.py", line 233, in run context, next_state, result = self.check_line( ^^^^^^^^^^^^^^^^ File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/docutils/statemachine.py", line 445, in check_line return method(match, context, next_state) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/docutils/parsers/rst/states.py", line 2790, in underline self.section(title, source, style, lineno - 1, messages) File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/docutils/parsers/rst/states.py", line 325, in section self.new_subsection(title, lineno, messages) File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/docutils/parsers/rst/states.py", line 391, in new_subsection newabsoffset = self.nested_parse( ^^^^^^^^^^^^^^^^^^ File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/docutils/parsers/rst/states.py", line 279, in nested_parse state_machine.run(block, input_offset, memo=self.memo, File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/docutils/parsers/rst/states.py", line 195, in run results = StateMachineWS.run(self, input_lines, input_offset) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/docutils/statemachine.py", line 233, in run context, next_state, result = self.check_line( ^^^^^^^^^^^^^^^^ File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/docutils/statemachine.py", line 445, in check_line return method(match, context, next_state) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/docutils/parsers/rst/states.py", line 2357, in explicit_markup nodelist, blank_finish = self.explicit_construct(match) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/docutils/parsers/rst/states.py", line 2369, in explicit_construct return method(self, expmatch) ^^^^^^^^^^^^^^^^^^^^^^ File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/docutils/parsers/rst/states.py", line 2106, in directive return self.run_directive( ^^^^^^^^^^^^^^^^^^^ File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/docutils/parsers/rst/states.py", line 2156, in run_directive result = directive_instance.run() ^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/sphinx/domains/__init__.py", line 289, in run return super().run() ^^^^^^^^^^^^^ File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/sphinx/directives/__init__.py", line 286, in run content_children = self.parse_content_to_nodes(allow_section_headings=True) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/sphinx/util/docutils.py", line 415, in parse_content_to_nodes return nested_parse_to_nodes( ^^^^^^^^^^^^^^^^^^^^^^ File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/sphinx/util/parsing.py", line 65, in nested_parse_to_nodes state.nested_parse(content, offset, node, match_titles=allow_section_headings) File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/docutils/parsers/rst/states.py", line 279, in nested_parse state_machine.run(block, input_offset, memo=self.memo, File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/docutils/parsers/rst/states.py", line 195, in run results = StateMachineWS.run(self, input_lines, input_offset) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/docutils/statemachine.py", line 233, in run context, next_state, result = self.check_line( ^^^^^^^^^^^^^^^^ File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/docutils/statemachine.py", line 445, in check_line return method(match, context, next_state) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/docutils/parsers/rst/states.py", line 2357, in explicit_markup nodelist, blank_finish = self.explicit_construct(match) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/docutils/parsers/rst/states.py", line 2369, in explicit_construct return method(self, expmatch) ^^^^^^^^^^^^^^^^^^^^^^ File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/docutils/parsers/rst/states.py", line 2106, in directive return self.run_directive( ^^^^^^^^^^^^^^^^^^^ File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/docutils/parsers/rst/states.py", line 2156, in run_directive result = directive_instance.run() ^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/autoapi/inheritance_diagrams.py", line 129, in run return super().run() ^^^^^^^^^^^^^ File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/sphinx/ext/inheritance_diagram.py", line 374, in run graph = InheritanceGraph( ^^^^^^^^^^^^^^^^^ File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/sphinx/ext/inheritance_diagram.py", line 153, in __init__ classes = self._import_classes(class_names, currmodule) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/autoapi/inheritance_diagrams.py", line 62, in _import_classes classes.extend(_import_class(name, currmodule)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/autoapi/inheritance_diagrams.py", line 34, in _import_class target = _do_import_class(name) ^^^^^^^^^^^^^^^^^^^^^^ File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/autoapi/inheritance_diagrams.py", line 14, in _do_import_class target = (target.getattr(path_part) or (None,))[0] ^^^^^^^^^^^^^^ AttributeError: 'AssignName' object has no attribute 'getattr' Exception occurred: File "/home/docs/checkouts/readthedocs.org/user_builds/brightway-documentation/conda/latest/lib/python3.12/site-packages/autoapi/inheritance_diagrams.py", line 14, in _do_import_class target = (target.getattr(path_part) or (None,))[0] ^^^^^^^^^^^^^^ AttributeError: 'AssignName' object has no attribute 'getattr' The full traceback has been saved in /tmp/sphinx-err-9le6mgfs.log, if you want to report the issue to the developers. Please also report this if it was a user error, so that a better error message can be provided next time. A bug report can be filed in the tracker at . Thanks! ```
cmutel commented 2 months ago

To be more precise, the edits which triggered the failure were a shift from relative to absolute imports throughout a library. This PR passed the CI tests and the code is importable, so there isn't an obvious error.

michaelweinold commented 2 months ago

The MWE to reproduce this issue:

__init__.py:

from test_library.test_module import banana

test_module.py:

class highest:
    def __init__(self):
        self.a = 'a'

class middle(highest):
    def __init__(self):
        self.a = 'a'

class lowest:
    def __init__(self):
        self.db = "middle"

test_module = lowest()

It is all a little peculiar. If the instance of the lowest() class is named something other than the name of the module, such as banana = lowest(), no error is thrown. But even if the instance of the lowest() class is named test_module, the error can be avoided by not making the class middle() inherit from another class.