sphinx-doc / sphinx-doc/sphinx

A class with a `__setattr__` method raising an exception cannot be rendered by Sphinx's autodoc

Open
#11,986 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

extensions:autodoc type:bug
Dominant language
Python
Stars
8k
Forks
2.6k
PR merge metrics
No merged PRs in 30d

Description

Describe the bug

There is a class called FrozenSpaceMeta from the cloup project that I try to render with Sphinx's autodoc, but it always fails because its __setattr__ method is raising an exception.

Tl;Dr - the following class:

class FrozenSpaceMeta(type):

    def __setattr__(cls, key: str, value: Any) -> None:
        raise Exception("you can't set attributes on this class")

triggers that exception:

(...)
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/sphinx/ext/autodoc/__init__.py", line 824, in document_members
    documenter.generate(
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/sphinx/ext/autodoc/__init__.py", line 879, in generate
    if not self.import_object():
           ^^^^^^^^^^^^^^^^^^^^
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/sphinx/ext/autodoc/__init__.py", line 2575, in import_object
    self.update_annotations(self.parent)
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/sphinx/ext/autodoc/__init__.py", line 2552, in update_annotations
    parent.__annotations__ = annotations
    ^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/cloup/_util.py", line 129, in __setattr__
    raise Exception("you can't set attributes on this class")
Exception: you can't set attributes on this class
How to Reproduce

This happened in my Click Extra project, in which I re-expose cloup.Color in my click_extra module via __all__.

You can setup the initial project with:

$ git clone https://github.com/kdeldycke/click-extra.git
$ cd click-extra
$ pip install poetry
$ poetry install

And here is the full traceback of Sphinx trying to generate the documentation of Click Extra:

$ poetry run sphinx-build -b html ./docs ./docs/html
# Platform:         darwin; (macOS-14.3.1-arm64-64bit)
# Sphinx version:   7.1.2
# Python version:   3.12.1 (CPython)
# Docutils version: 0.20.1
# Jinja2 version:   3.1.3
# Pygments version: 2.17.2

# Last messages:
#   [config changed ('version')]
#   22 added, 0 changed, 0 removed

#   reading sources... [  5%]
#   changelog
#   

#   reading sources... [  9%]
#   click_extra
#   

# Loaded extensions:
#   sphinx.ext.mathjax (7.1.2)
#   alabaster (0.7.13)
#   sphinxcontrib.applehelp (1.0.4)
#   sphinxcontrib.devhelp (1.0.2)
#   sphinxcontrib.htmlhelp (2.0.1)
#   sphinxcontrib.serializinghtml (1.1.5)
#   sphinxcontrib.qthelp (1.0.3)
#   sphinx.ext.autodoc.preserve_defaults (7.1.2)
#   sphinx.ext.autodoc.type_comment (7.1.2)
#   sphinx.ext.autodoc.typehints (7.1.2)
#   sphinx.ext.autodoc (7.1.2)
#   sphinx.ext.todo (7.1.2)
#   sphinx.ext.extlinks (7.1.2)
#   sphinx.ext.intersphinx (7.1.2)
#   sphinx.ext.viewcode (7.1.2)
#   sphinx_copybutton (0.5.2)
#   sphinx_design (0.5.0)
#   sphinx_issues (4.0.0)
#   sphinxext.opengraph (unknown version)
#   myst_parser (2.0.0)
#   sphinx.ext.autosectionlabel (7.1.2)
#   sphinx_autodoc_typehints (unknown version)
#   click_extra.sphinx (unknown version)
#   sphinxcontrib.mermaid (7.1.2)
#   furo (2024.01.29)
#   sphinx_basic_ng (1.0.0.beta2)

# Traceback:
Traceback (most recent call last):
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/sphinx/cmd/build.py", line 290, in build_main
    app.build(args.force_all, args.filenames)
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/sphinx/application.py", line 351, in build
    self.builder.build_update()
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/sphinx/builders/__init__.py", line 290, in build_update
    self.build(to_build,
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/sphinx/builders/__init__.py", line 310, in build
    updated_docnames = set(self.read())
                           ^^^^^^^^^^^
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/sphinx/builders/__init__.py", line 417, in read
    self._read_serial(docnames)
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/sphinx/builders/__init__.py", line 438, in _read_serial
    self.read_doc(docname)
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/sphinx/builders/__init__.py", line 494, in read_doc
    publisher.publish()
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/docutils/core.py", line 234, in publish
    self.document = self.reader.read(self.source, self.parser,
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/sphinx/io.py", line 104, in read
    self.parse()
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/docutils/readers/__init__.py", line 76, in parse
    self.parser.parse(self.input, document)
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/sphinx/parsers.py", line 80, in parse
    self.statemachine.run(inputlines, document, inliner=self.inliner)
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/docutils/parsers/rst/states.py", line 169, in run
    results = StateMachineWS.run(self, input_lines, input_offset,
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/docutils/statemachine.py", line 233, in run
    context, next_state, result = self.check_line(
                                  ^^^^^^^^^^^^^^^^
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/docutils/statemachine.py", line 445, in check_line
    return method(match, context, next_state)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/docutils/parsers/rst/states.py", line 2785, in underline
    self.section(title, source, style, lineno - 1, messages)
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/docutils/parsers/rst/states.py", line 325, in section
    self.new_subsection(title, lineno, messages)
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/docutils/parsers/rst/states.py", line 391, in new_subsection
    newabsoffset = self.nested_parse(
                   ^^^^^^^^^^^^^^^^^^
  File "/Users/kde/click-extra/.venv/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 "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/docutils/parsers/rst/states.py", line 195, in run
    results = StateMachineWS.run(self, input_lines, input_offset)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/docutils/statemachine.py", line 233, in run
    context, next_state, result = self.check_line(
                                  ^^^^^^^^^^^^^^^^
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/docutils/statemachine.py", line 445, in check_line
    return method(match, context, next_state)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/docutils/parsers/rst/states.py", line 2355, in explicit_markup
    nodelist, blank_finish = self.explicit_construct(match)
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/docutils/parsers/rst/states.py", line 2367, in explicit_construct
    return method(self, expmatch)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/docutils/parsers/rst/states.py", line 2104, in directive
    return self.run_directive(
           ^^^^^^^^^^^^^^^^^^^
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/docutils/parsers/rst/states.py", line 2154, in run_directive
    result = directive_instance.run()
             ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/sphinx/ext/autodoc/directive.py", line 135, in run
    documenter.generate(more_content=self.content)
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/sphinx/ext/autodoc/__init__.py", line 950, in generate
    self.document_members(all_members)
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/sphinx/ext/autodoc/__init__.py", line 824, in document_members
    documenter.generate(
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/sphinx/ext/autodoc/__init__.py", line 1871, in generate
    return super().generate(more_content=more_content,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/sphinx/ext/autodoc/__init__.py", line 950, in generate
    self.document_members(all_members)
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/sphinx/ext/autodoc/__init__.py", line 1857, in document_members
    super().document_members(all_members)
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/sphinx/ext/autodoc/__init__.py", line 824, in document_members
    documenter.generate(
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/sphinx/ext/autodoc/__init__.py", line 879, in generate
    if not self.import_object():
           ^^^^^^^^^^^^^^^^^^^^
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/sphinx/ext/autodoc/__init__.py", line 2575, in import_object
    self.update_annotations(self.parent)
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/sphinx/ext/autodoc/__init__.py", line 2552, in update_annotations
    parent.__annotations__ = annotations
    ^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/kde/click-extra/.venv/lib/python3.12/site-packages/cloup/_util.py", line 129, in __setattr__
    raise Exception("you can't set attributes on this class")
Exception: you can't set attributes on this class
Environment Information
Platform:              darwin; (macOS-14.3.1-arm64-64bit)
Python version:        3.12.2 (main, Feb  6 2024, 20:19:44) [Clang 15.0.0 (clang-1500.1.0.2.5)])
Python implementation: CPython
Sphinx version:        7.1.2
Docutils version:      0.20.1
Jinja2 version:        3.1.3
Pygments version:      2.17.2
Sphinx extensions
extensions = [
    "sphinx.ext.autodoc",
    "sphinx.ext.todo",
    "sphinx.ext.intersphinx",
    "sphinx.ext.viewcode",
    "sphinx_copybutton",
    "sphinx_design",
    "sphinx_issues",
    "sphinxext.opengraph",
    "myst_parser",
    "sphinx.ext.autosectionlabel",
    "sphinx_autodoc_typehints",
    "click_extra.sphinx",
    "sphinxcontrib.mermaid",
]
Additional context

This has been originally reported at: https://github.com/janluke/cloup/issues/177

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in sphinx/ext/autodoc/init.py at import_object() and update_annotations(), which the traceback identifies as assigning to the class. Reproduce the failure with poetry run sphinx-build -b html ./docs ./docs/html using the Click Extra example. Done means autodoc can render a class whose setattr raises without propagating that exception.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
documentation
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.