Fix #7551: autosummary: a nested class is indexed as non-nested class

This commit is contained in:
Takeshi KOMIYA 2020-04-29 20:44:59 +09:00
parent 6ce265dc81
commit c4d4ba2835
6 changed files with 49 additions and 11 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: 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
* #2785: html: Bad alignment of equation links

View File

@ -45,6 +45,7 @@ from sphinx.locale import __
from sphinx.registry import SphinxComponentRegistry
from sphinx.util import logging
from sphinx.util import rst
from sphinx.util import split_full_qualified_name
from sphinx.util.inspect import safe_getattr
from sphinx.util.osutil import ensuredir
from sphinx.util.template import SphinxTemplateLoader
@ -248,19 +249,19 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any,
ns['attributes'], ns['all_attributes'] = \
get_members(obj, {'attribute', 'property'})
parts = name.split('.')
modname, qualname = split_full_qualified_name(name)
if doc.objtype in ('method', 'attribute', 'property'):
mod_name = '.'.join(parts[:-2])
cls_name = parts[-2]
obj_name = '.'.join(parts[-2:])
ns['class'] = cls_name
ns['class'] = qualname.rsplit(".", 1)[0]
if doc.objtype in ('class',):
shortname = qualname
else:
mod_name, obj_name = '.'.join(parts[:-1]), parts[-1]
shortname = qualname.rsplit(".", 1)[-1]
ns['fullname'] = name
ns['module'] = mod_name
ns['objname'] = obj_name
ns['name'] = parts[-1]
ns['module'] = modname
ns['objname'] = qualname
ns['name'] = shortname
ns['objtype'] = doc.objtype
ns['underline'] = len(name) * '='

View File

@ -570,6 +570,31 @@ def import_object(objname: str, source: str = None) -> Any:
raise ExtensionError('Could not import %s' % objname, exc)
def split_full_qualified_name(name: str) -> Tuple[str, str]:
"""Split full qualified name to a pair of modname and qualname.
A qualname is an abbreviation for "Qualified name" introduced at PEP-3155
(https://www.python.org/dev/peps/pep-3155/). It is a dotted path name
from the module top-level.
A "full" qualified name means a string containing both module name and
qualified name.
.. note:: This function imports module actually to check the exisitence.
Therefore you need to mock 3rd party modules if needed before
calling this function.
"""
parts = name.split('.')
for i, part in enumerate(parts, 1):
try:
modname = ".".join(parts[:i])
import_module(modname)
except ImportError:
return ".".join(parts[:i - 1]), ".".join(parts[i - 1:])
return name, ""
def encode_uri(uri: str) -> str:
split = list(urlsplit(uri))
split[1] = split[1].encode('idna').decode('ascii')

View File

@ -3,6 +3,9 @@ from typing import Union
class Foo:
class Bar:
pass
def __init__(self):
pass

View File

@ -9,5 +9,6 @@
autosummary_dummy_module
autosummary_dummy_module.Foo
autosummary_dummy_module.Foo.Bar
autosummary_dummy_module.bar
autosummary_importfail

View File

@ -203,6 +203,7 @@ def test_autosummary_generate(app, status, warning):
[autosummary_table, nodes.table, nodes.tgroup, (nodes.colspec,
nodes.colspec,
[nodes.tbody, (nodes.row,
nodes.row,
nodes.row,
nodes.row,
nodes.row)])])
@ -210,8 +211,9 @@ def test_autosummary_generate(app, status, warning):
assert doctree[3][0][0][2][0].astext() == 'autosummary_dummy_module\n\n'
assert doctree[3][0][0][2][1].astext() == 'autosummary_dummy_module.Foo()\n\n'
assert doctree[3][0][0][2][2].astext() == 'autosummary_dummy_module.bar(x[, y])\n\n'
assert doctree[3][0][0][2][3].astext() == 'autosummary_importfail\n\n'
assert doctree[3][0][0][2][2].astext() == 'autosummary_dummy_module.Foo.Bar\n\n'
assert doctree[3][0][0][2][3].astext() == 'autosummary_dummy_module.bar(x[, y])\n\n'
assert doctree[3][0][0][2][4].astext() == 'autosummary_importfail\n\n'
module = (app.srcdir / 'generated' / 'autosummary_dummy_module.rst').read_text()
assert (' .. autosummary::\n'
@ -231,6 +233,11 @@ def test_autosummary_generate(app, status, warning):
' ~Foo.baz\n'
' \n' in Foo)
FooBar = (app.srcdir / 'generated' / 'autosummary_dummy_module.Foo.Bar.rst').read_text()
assert ('.. currentmodule:: autosummary_dummy_module\n'
'\n'
'.. autoclass:: Foo.Bar\n' in FooBar)
@pytest.mark.sphinx('dummy', testroot='ext-autosummary',
confoverrides={'autosummary_generate_overwrite': False})