Fix #7551: autodoc: failed to import nested class

This commit is contained in:
Takeshi KOMIYA 2020-05-02 16:37:15 +09:00
parent c4d4ba2835
commit 560ccf83ae
3 changed files with 35 additions and 22 deletions

View File

@ -85,6 +85,7 @@ Bugs fixed
* #6857: autodoc: failed to detect a classmethod on Enum class
* #7562: autodoc: a typehint contains spaces is wrongly rendered under
autodoc_typehints='description' mode
* #7551: autodoc: failed to import nested class
* #7551: autosummary: a nested class is indexed as non-nested class
* #7535: sphinx-autogen: crashes when custom template uses inheritance
* #7536: sphinx-autogen: crashes when template uses i18n feature

View File

@ -31,7 +31,7 @@ from sphinx.locale import _, __
from sphinx.pycode import ModuleAnalyzer, PycodeError
from sphinx.util import inspect
from sphinx.util import logging
from sphinx.util import rpartition
from sphinx.util import split_full_qualified_name
from sphinx.util.docstrings import extract_metadata, prepare_docstring
from sphinx.util.inspect import getdoc, object_description, safe_getattr, stringify_signature
from sphinx.util.typing import stringify as stringify_typehint
@ -312,7 +312,8 @@ class Documenter:
modname = None
parents = []
self.modname, self.objpath = self.resolve_name(modname, parents, path, base)
with mock(self.env.config.autodoc_mock_imports):
self.modname, self.objpath = self.resolve_name(modname, parents, path, base)
if not self.modname:
return False
@ -898,8 +899,14 @@ class ModuleLevelDocumenter(Documenter):
) -> Tuple[str, List[str]]:
if modname is None:
if path:
modname = path.rstrip('.')
else:
stripped = path.rstrip('.')
modname, qualname = split_full_qualified_name(stripped)
if qualname:
parents = qualname.split(".")
else:
parents = []
if modname is None:
# if documenting a toplevel object without explicit module,
# it can be contained in another auto directive ...
modname = self.env.temp_data.get('autodoc:module')
@ -932,8 +939,13 @@ class ClassLevelDocumenter(Documenter):
# ... if still None, there's no way to know
if mod_cls is None:
return None, []
modname, cls = rpartition(mod_cls, '.')
parents = [cls]
try:
modname, qualname = split_full_qualified_name(mod_cls)
parents = qualname.split(".")
except ImportError:
parents = mod_cls.split(".")
# if the module name is still missing, get it like above
if not modname:
modname = self.env.temp_data.get('autodoc:module')

View File

@ -103,27 +103,27 @@ def test_parse_name(app):
directive = make_directive_bridge(app.env)
# for modules
verify('module', 'test_autodoc', ('test_autodoc', [], None, None))
verify('module', 'test.test_autodoc', ('test.test_autodoc', [], None, None))
verify('module', 'test_ext_autodoc', ('test_ext_autodoc', [], None, None))
verify('module', 'test.test_ext_autodoc', ('test.test_ext_autodoc', [], None, None))
verify('module', 'test(arg)', ('test', [], 'arg', None))
assert 'signature arguments' in app._warning.getvalue()
# for functions/classes
verify('function', 'test_autodoc.raises',
('test_autodoc', ['raises'], None, None))
verify('function', 'test_autodoc.raises(exc) -> None',
('test_autodoc', ['raises'], 'exc', 'None'))
directive.env.temp_data['autodoc:module'] = 'test_autodoc'
verify('function', 'raises', ('test_autodoc', ['raises'], None, None))
verify('function', 'test_ext_autodoc.raises',
('test_ext_autodoc', ['raises'], None, None))
verify('function', 'test_ext_autodoc.raises(exc) -> None',
('test_ext_autodoc', ['raises'], 'exc', 'None'))
directive.env.temp_data['autodoc:module'] = 'test_ext_autodoc'
verify('function', 'raises', ('test_ext_autodoc', ['raises'], None, None))
del directive.env.temp_data['autodoc:module']
directive.env.ref_context['py:module'] = 'test_autodoc'
verify('function', 'raises', ('test_autodoc', ['raises'], None, None))
verify('class', 'Base', ('test_autodoc', ['Base'], None, None))
directive.env.ref_context['py:module'] = 'test_ext_autodoc'
verify('function', 'raises', ('test_ext_autodoc', ['raises'], None, None))
verify('class', 'Base', ('test_ext_autodoc', ['Base'], None, None))
# for members
directive.env.ref_context['py:module'] = 'foo'
verify('method', 'util.SphinxTestApp.cleanup',
('util', ['SphinxTestApp', 'cleanup'], None, None))
('foo', ['util', 'SphinxTestApp', 'cleanup'], None, None))
directive.env.ref_context['py:module'] = 'util'
directive.env.ref_context['py:class'] = 'Foo'
directive.env.temp_data['autodoc:class'] = 'SphinxTestApp'
@ -735,14 +735,14 @@ def test_autodoc_inner_class(app):
actual = do_autodoc(app, 'class', 'target.Outer.Inner', options)
assert list(actual) == [
'',
'.. py:class:: Inner',
' :module: target.Outer',
'.. py:class:: Outer.Inner',
' :module: target',
'',
' Foo',
'',
'',
' .. py:method:: Inner.meth()',
' :module: target.Outer',
' .. py:method:: Outer.Inner.meth()',
' :module: target',
'',
' Foo',
'',