doc: Do not mock non-existing __qualname__ attribute

Building the documentation with the Python 3 version of sphinx fails:

$ make -C doc html SPHINXBUILD=/usr/share/sphinx/scripts/python3/sphinx-build
[...]
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/sphinx/cmdline.py", line 296, in main
    app.build(opts.force_all, filenames)
  File "/usr/lib/python3/dist-packages/sphinx/application.py", line 333, in build
    self.builder.build_update()
  File "/usr/lib/python3/dist-packages/sphinx/builders/__init__.py", line 251, in build_update
    'out of date' % len(to_build))
  File "/usr/lib/python3/dist-packages/sphinx/builders/__init__.py", line 265, in build
    self.doctreedir, self.app))
  File "/usr/lib/python3/dist-packages/sphinx/environment/__init__.py", line 556, in update
    self._read_serial(docnames, app)
  File "/usr/lib/python3/dist-packages/sphinx/environment/__init__.py", line 576, in _read_serial
    self.read_doc(docname, app)
  File "/usr/lib/python3/dist-packages/sphinx/environment/__init__.py", line 684, in read_doc
    pub.publish()
  File "/usr/lib/python3/dist-packages/docutils/core.py", line 217, in publish
    self.settings)
  File "/usr/lib/python3/dist-packages/sphinx/io.py", line 55, in read
    self.parse()
  File "/usr/lib/python3/dist-packages/docutils/readers/__init__.py", line 78, in parse
    self.parser.parse(self.input, document)
  File "/usr/lib/python3/dist-packages/docutils/parsers/rst/__init__.py", line 191, in parse
    self.statemachine.run(inputlines, document, inliner=self.inliner)
  File "/usr/lib/python3/dist-packages/docutils/parsers/rst/states.py", line 172, in run
    input_source=document['source'])
  File "/usr/lib/python3/dist-packages/docutils/statemachine.py", line 239, in run
    context, state, transitions)
  File "/usr/lib/python3/dist-packages/docutils/statemachine.py", line 460, in check_line
    return method(match, context, next_state)
  File "/usr/lib/python3/dist-packages/docutils/parsers/rst/states.py", line 2989, in text
    self.section(title.lstrip(), source, style, lineno + 1, messages)
  File "/usr/lib/python3/dist-packages/docutils/parsers/rst/states.py", line 328, in section
    self.new_subsection(title, lineno, messages)
  File "/usr/lib/python3/dist-packages/docutils/parsers/rst/states.py", line 396, in new_subsection
    node=section_node, match_titles=True)
  File "/usr/lib/python3/dist-packages/docutils/parsers/rst/states.py", line 283, in nested_parse
    node=node, match_titles=match_titles)
  File "/usr/lib/python3/dist-packages/docutils/parsers/rst/states.py", line 197, in run
    results = StateMachineWS.run(self, input_lines, input_offset)
  File "/usr/lib/python3/dist-packages/docutils/statemachine.py", line 239, in run
    context, state, transitions)
  File "/usr/lib/python3/dist-packages/docutils/statemachine.py", line 460, in check_line
    return method(match, context, next_state)
  File "/usr/lib/python3/dist-packages/docutils/parsers/rst/states.py", line 2754, in underline
    self.section(title, source, style, lineno - 1, messages)
  File "/usr/lib/python3/dist-packages/docutils/parsers/rst/states.py", line 328, in section
    self.new_subsection(title, lineno, messages)
  File "/usr/lib/python3/dist-packages/docutils/parsers/rst/states.py", line 396, in new_subsection
    node=section_node, match_titles=True)
  File "/usr/lib/python3/dist-packages/docutils/parsers/rst/states.py", line 283, in nested_parse
    node=node, match_titles=match_titles)
  File "/usr/lib/python3/dist-packages/docutils/parsers/rst/states.py", line 197, in run
    results = StateMachineWS.run(self, input_lines, input_offset)
  File "/usr/lib/python3/dist-packages/docutils/statemachine.py", line 239, in run
    context, state, transitions)
  File "/usr/lib/python3/dist-packages/docutils/statemachine.py", line 460, in check_line
    return method(match, context, next_state)
  File "/usr/lib/python3/dist-packages/docutils/parsers/rst/states.py", line 2754, in underline
    self.section(title, source, style, lineno - 1, messages)
  File "/usr/lib/python3/dist-packages/docutils/parsers/rst/states.py", line 328, in section
    self.new_subsection(title, lineno, messages)
  File "/usr/lib/python3/dist-packages/docutils/parsers/rst/states.py", line 396, in new_subsection
    node=section_node, match_titles=True)
  File "/usr/lib/python3/dist-packages/docutils/parsers/rst/states.py", line 283, in nested_parse
    node=node, match_titles=match_titles)
  File "/usr/lib/python3/dist-packages/docutils/parsers/rst/states.py", line 197, in run
    results = StateMachineWS.run(self, input_lines, input_offset)
  File "/usr/lib/python3/dist-packages/docutils/statemachine.py", line 239, in run
    context, state, transitions)
  File "/usr/lib/python3/dist-packages/docutils/statemachine.py", line 460, in check_line
    return method(match, context, next_state)
  File "/usr/lib/python3/dist-packages/docutils/parsers/rst/states.py", line 2327, in explicit_markup
    nodelist, blank_finish = self.explicit_construct(match)
  File "/usr/lib/python3/dist-packages/docutils/parsers/rst/states.py", line 2339, in explicit_construct
    return method(self, expmatch)
  File "/usr/lib/python3/dist-packages/docutils/parsers/rst/states.py", line 2082, in directive
    directive_class, match, type_name, option_presets)
  File "/usr/lib/python3/dist-packages/docutils/parsers/rst/states.py", line 2131, in run_directive
    result = directive_instance.run()
  File "/usr/lib/python3/dist-packages/sphinx/ext/autodoc.py", line 1668, in run
    documenter.generate(more_content=self.content)
  File "/usr/lib/python3/dist-packages/sphinx/ext/autodoc.py", line 1013, in generate
    self.document_members(all_members)
  File "/usr/lib/python3/dist-packages/sphinx/ext/autodoc.py", line 1388, in document_members
    ModuleLevelDocumenter.document_members(self, all_members)
  File "/usr/lib/python3/dist-packages/sphinx/ext/autodoc.py", line 903, in document_members
    for (mname, member, isattr) in self.filter_members(members, want_all):
  File "/usr/lib/python3/dist-packages/sphinx/ext/autodoc.py", line 871, in filter_members
    not keep, self.options)
  File "/usr/lib/python3/dist-packages/sphinx/application.py", line 593, in emit_firstresult
    for result in self.emit(event, *args):
  File "/usr/lib/python3/dist-packages/sphinx/application.py", line 589, in emit
    results.append(callback(self, *args))
  File "/usr/lib/python3/dist-packages/sphinx/ext/napoleon/__init__.py", line 426, in _skip_member
    cls_path, _, _ = qualname.rpartition('.')
ValueError: not enough values to unpack (expected 3, got 0)

The napoleon sphinx extensions queries the attribute __qualname__ of the
given obj and expect a string as result. It uses a default value if this
attribute does not exist. The real Python modules do not have a
__qualname__ attribute, but the doc.conf.Mock object returns a Mock
object when queried for the __qualname__ attribute. Change the Mock
object to raise an AttributeError instead. This fixes #45684.
This commit is contained in:
Benjamin Drung 2018-01-26 17:13:57 +01:00
parent 971e59ebe2
commit 179e8fbe73

View file

@ -46,6 +46,8 @@ class Mock(object):
data = self.__mapping.get(name)
elif name in ('__file__', '__path__'):
data = '/dev/null'
elif name == '__qualname__':
raise AttributeError("'Mock' object has no attribute '__qualname__'")
else:
data = Mock(mapping=self.__mapping)
return data