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 * #6857: autodoc: failed to detect a classmethod on Enum class
* #7562: autodoc: a typehint contains spaces is wrongly rendered under * #7562: autodoc: a typehint contains spaces is wrongly rendered under
autodoc_typehints='description' mode autodoc_typehints='description' mode
* #7551: autodoc: failed to import nested class
* #7551: autosummary: a nested class is indexed as non-nested class * #7551: autosummary: a nested class is indexed as non-nested class
* #7535: sphinx-autogen: crashes when custom template uses inheritance * #7535: sphinx-autogen: crashes when custom template uses inheritance
* #7536: sphinx-autogen: crashes when template uses i18n feature * #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.pycode import ModuleAnalyzer, PycodeError
from sphinx.util import inspect from sphinx.util import inspect
from sphinx.util import logging 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.docstrings import extract_metadata, prepare_docstring
from sphinx.util.inspect import getdoc, object_description, safe_getattr, stringify_signature from sphinx.util.inspect import getdoc, object_description, safe_getattr, stringify_signature
from sphinx.util.typing import stringify as stringify_typehint from sphinx.util.typing import stringify as stringify_typehint
@ -312,7 +312,8 @@ class Documenter:
modname = None modname = None
parents = [] 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: if not self.modname:
return False return False
@ -898,8 +899,14 @@ class ModuleLevelDocumenter(Documenter):
) -> Tuple[str, List[str]]: ) -> Tuple[str, List[str]]:
if modname is None: if modname is None:
if path: if path:
modname = path.rstrip('.') stripped = path.rstrip('.')
else: 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, # if documenting a toplevel object without explicit module,
# it can be contained in another auto directive ... # it can be contained in another auto directive ...
modname = self.env.temp_data.get('autodoc:module') 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 still None, there's no way to know
if mod_cls is None: if mod_cls is None:
return 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 the module name is still missing, get it like above
if not modname: if not modname:
modname = self.env.temp_data.get('autodoc:module') 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) directive = make_directive_bridge(app.env)
# for modules # for modules
verify('module', 'test_autodoc', ('test_autodoc', [], None, None)) verify('module', 'test_ext_autodoc', ('test_ext_autodoc', [], None, None))
verify('module', 'test.test_autodoc', ('test.test_autodoc', [], None, None)) verify('module', 'test.test_ext_autodoc', ('test.test_ext_autodoc', [], None, None))
verify('module', 'test(arg)', ('test', [], 'arg', None)) verify('module', 'test(arg)', ('test', [], 'arg', None))
assert 'signature arguments' in app._warning.getvalue() assert 'signature arguments' in app._warning.getvalue()
# for functions/classes # for functions/classes
verify('function', 'test_autodoc.raises', verify('function', 'test_ext_autodoc.raises',
('test_autodoc', ['raises'], None, None)) ('test_ext_autodoc', ['raises'], None, None))
verify('function', 'test_autodoc.raises(exc) -> None', verify('function', 'test_ext_autodoc.raises(exc) -> None',
('test_autodoc', ['raises'], 'exc', 'None')) ('test_ext_autodoc', ['raises'], 'exc', 'None'))
directive.env.temp_data['autodoc:module'] = 'test_autodoc' directive.env.temp_data['autodoc:module'] = 'test_ext_autodoc'
verify('function', 'raises', ('test_autodoc', ['raises'], None, None)) verify('function', 'raises', ('test_ext_autodoc', ['raises'], None, None))
del directive.env.temp_data['autodoc:module'] del directive.env.temp_data['autodoc:module']
directive.env.ref_context['py:module'] = 'test_autodoc' directive.env.ref_context['py:module'] = 'test_ext_autodoc'
verify('function', 'raises', ('test_autodoc', ['raises'], None, None)) verify('function', 'raises', ('test_ext_autodoc', ['raises'], None, None))
verify('class', 'Base', ('test_autodoc', ['Base'], None, None)) verify('class', 'Base', ('test_ext_autodoc', ['Base'], None, None))
# for members # for members
directive.env.ref_context['py:module'] = 'foo' directive.env.ref_context['py:module'] = 'foo'
verify('method', 'util.SphinxTestApp.cleanup', 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:module'] = 'util'
directive.env.ref_context['py:class'] = 'Foo' directive.env.ref_context['py:class'] = 'Foo'
directive.env.temp_data['autodoc:class'] = 'SphinxTestApp' 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) actual = do_autodoc(app, 'class', 'target.Outer.Inner', options)
assert list(actual) == [ assert list(actual) == [
'', '',
'.. py:class:: Inner', '.. py:class:: Outer.Inner',
' :module: target.Outer', ' :module: target',
'', '',
' Foo', ' Foo',
'', '',
'', '',
' .. py:method:: Inner.meth()', ' .. py:method:: Outer.Inner.meth()',
' :module: target.Outer', ' :module: target',
'', '',
' Foo', ' Foo',
'', '',