mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Fix #7551: autosummary: a nested class is indexed as non-nested class
This commit is contained in:
parent
6ce265dc81
commit
c4d4ba2835
1
CHANGES
1
CHANGES
@ -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: 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
|
||||||
* #2785: html: Bad alignment of equation links
|
* #2785: html: Bad alignment of equation links
|
||||||
|
@ -45,6 +45,7 @@ from sphinx.locale import __
|
|||||||
from sphinx.registry import SphinxComponentRegistry
|
from sphinx.registry import SphinxComponentRegistry
|
||||||
from sphinx.util import logging
|
from sphinx.util import logging
|
||||||
from sphinx.util import rst
|
from sphinx.util import rst
|
||||||
|
from sphinx.util import split_full_qualified_name
|
||||||
from sphinx.util.inspect import safe_getattr
|
from sphinx.util.inspect import safe_getattr
|
||||||
from sphinx.util.osutil import ensuredir
|
from sphinx.util.osutil import ensuredir
|
||||||
from sphinx.util.template import SphinxTemplateLoader
|
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'] = \
|
ns['attributes'], ns['all_attributes'] = \
|
||||||
get_members(obj, {'attribute', 'property'})
|
get_members(obj, {'attribute', 'property'})
|
||||||
|
|
||||||
parts = name.split('.')
|
modname, qualname = split_full_qualified_name(name)
|
||||||
if doc.objtype in ('method', 'attribute', 'property'):
|
if doc.objtype in ('method', 'attribute', 'property'):
|
||||||
mod_name = '.'.join(parts[:-2])
|
ns['class'] = qualname.rsplit(".", 1)[0]
|
||||||
cls_name = parts[-2]
|
|
||||||
obj_name = '.'.join(parts[-2:])
|
if doc.objtype in ('class',):
|
||||||
ns['class'] = cls_name
|
shortname = qualname
|
||||||
else:
|
else:
|
||||||
mod_name, obj_name = '.'.join(parts[:-1]), parts[-1]
|
shortname = qualname.rsplit(".", 1)[-1]
|
||||||
|
|
||||||
ns['fullname'] = name
|
ns['fullname'] = name
|
||||||
ns['module'] = mod_name
|
ns['module'] = modname
|
||||||
ns['objname'] = obj_name
|
ns['objname'] = qualname
|
||||||
ns['name'] = parts[-1]
|
ns['name'] = shortname
|
||||||
|
|
||||||
ns['objtype'] = doc.objtype
|
ns['objtype'] = doc.objtype
|
||||||
ns['underline'] = len(name) * '='
|
ns['underline'] = len(name) * '='
|
||||||
|
@ -570,6 +570,31 @@ def import_object(objname: str, source: str = None) -> Any:
|
|||||||
raise ExtensionError('Could not import %s' % objname, exc)
|
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:
|
def encode_uri(uri: str) -> str:
|
||||||
split = list(urlsplit(uri))
|
split = list(urlsplit(uri))
|
||||||
split[1] = split[1].encode('idna').decode('ascii')
|
split[1] = split[1].encode('idna').decode('ascii')
|
||||||
|
@ -3,6 +3,9 @@ from typing import Union
|
|||||||
|
|
||||||
|
|
||||||
class Foo:
|
class Foo:
|
||||||
|
class Bar:
|
||||||
|
pass
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -9,5 +9,6 @@
|
|||||||
|
|
||||||
autosummary_dummy_module
|
autosummary_dummy_module
|
||||||
autosummary_dummy_module.Foo
|
autosummary_dummy_module.Foo
|
||||||
|
autosummary_dummy_module.Foo.Bar
|
||||||
autosummary_dummy_module.bar
|
autosummary_dummy_module.bar
|
||||||
autosummary_importfail
|
autosummary_importfail
|
||||||
|
@ -203,6 +203,7 @@ def test_autosummary_generate(app, status, warning):
|
|||||||
[autosummary_table, nodes.table, nodes.tgroup, (nodes.colspec,
|
[autosummary_table, nodes.table, nodes.tgroup, (nodes.colspec,
|
||||||
nodes.colspec,
|
nodes.colspec,
|
||||||
[nodes.tbody, (nodes.row,
|
[nodes.tbody, (nodes.row,
|
||||||
|
nodes.row,
|
||||||
nodes.row,
|
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][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][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][2].astext() == 'autosummary_dummy_module.Foo.Bar\n\n'
|
||||||
assert doctree[3][0][0][2][3].astext() == 'autosummary_importfail\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()
|
module = (app.srcdir / 'generated' / 'autosummary_dummy_module.rst').read_text()
|
||||||
assert (' .. autosummary::\n'
|
assert (' .. autosummary::\n'
|
||||||
@ -231,6 +233,11 @@ def test_autosummary_generate(app, status, warning):
|
|||||||
' ~Foo.baz\n'
|
' ~Foo.baz\n'
|
||||||
' \n' in Foo)
|
' \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',
|
@pytest.mark.sphinx('dummy', testroot='ext-autosummary',
|
||||||
confoverrides={'autosummary_generate_overwrite': False})
|
confoverrides={'autosummary_generate_overwrite': False})
|
||||||
|
Loading…
Reference in New Issue
Block a user