mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge pull request #8028 from tk0miya/8011_ivar_for_autosummary
Close #8011: autosummary: Support instance attributes
This commit is contained in:
commit
03a6028663
2
CHANGES
2
CHANGES
@ -20,6 +20,8 @@ Features added
|
||||
* #2076: autodoc: Allow overriding of exclude-members in skip-member function
|
||||
* #2024: autosummary: Add :confval:`autosummary_filename_map` to avoid conflict
|
||||
of filenames between two object with different case
|
||||
* #8011: autosummary: Support instance attributes as a target of autosummary
|
||||
directive
|
||||
* #7849: html: Add :confval:`html_codeblock_linenos_style` to change the style
|
||||
of line numbers for code-blocks
|
||||
* #7853: C and C++, support parameterized GNU style attributes.
|
||||
|
@ -75,7 +75,7 @@ from sphinx.application import Sphinx
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning
|
||||
from sphinx.environment import BuildEnvironment
|
||||
from sphinx.environment.adapters.toctree import TocTree
|
||||
from sphinx.ext.autodoc import Documenter
|
||||
from sphinx.ext.autodoc import Documenter, INSTANCEATTR
|
||||
from sphinx.ext.autodoc.directive import DocumenterBridge, Options
|
||||
from sphinx.ext.autodoc.importer import import_module
|
||||
from sphinx.ext.autodoc.mock import mock
|
||||
@ -285,6 +285,19 @@ class Autosummary(SphinxDirective):
|
||||
|
||||
return nodes
|
||||
|
||||
def import_by_name(self, name: str, prefixes: List[str]) -> Tuple[str, Any, Any, str]:
|
||||
with mock(self.config.autosummary_mock_imports):
|
||||
try:
|
||||
return import_by_name(name, prefixes)
|
||||
except ImportError as exc:
|
||||
# check existence of instance attribute
|
||||
try:
|
||||
return import_ivar_by_name(name, prefixes)
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
raise exc # re-raise ImportError if instance attribute not found
|
||||
|
||||
def get_items(self, names: List[str]) -> List[Tuple[str, str, str, str]]:
|
||||
"""Try to import the given names, and return a list of
|
||||
``[(name, signature, summary_string, real_name), ...]``.
|
||||
@ -302,8 +315,7 @@ class Autosummary(SphinxDirective):
|
||||
display_name = name.split('.')[-1]
|
||||
|
||||
try:
|
||||
with mock(self.config.autosummary_mock_imports):
|
||||
real_name, obj, parent, modname = import_by_name(name, prefixes=prefixes)
|
||||
real_name, obj, parent, modname = self.import_by_name(name, prefixes=prefixes)
|
||||
except ImportError:
|
||||
logger.warning(__('autosummary: failed to import %s'), name,
|
||||
location=self.get_source_info())
|
||||
@ -659,6 +671,23 @@ def _import_by_name(name: str) -> Tuple[Any, Any, str]:
|
||||
raise ImportError(*e.args) from e
|
||||
|
||||
|
||||
def import_ivar_by_name(name: str, prefixes: List[str] = [None]) -> Tuple[str, Any, Any, str]:
|
||||
"""Import an instance variable that has the given *name*, under one of the
|
||||
*prefixes*. The first name that succeeds is used.
|
||||
"""
|
||||
try:
|
||||
name, attr = name.rsplit(".", 1)
|
||||
real_name, obj, parent, modname = import_by_name(name, prefixes)
|
||||
qualname = real_name.replace(modname + ".", "")
|
||||
analyzer = ModuleAnalyzer.for_module(modname)
|
||||
if (qualname, attr) in analyzer.find_attr_docs():
|
||||
return real_name + "." + attr, INSTANCEATTR, obj, modname
|
||||
except (ImportError, ValueError):
|
||||
pass
|
||||
|
||||
raise ImportError
|
||||
|
||||
|
||||
# -- :autolink: (smart default role) -------------------------------------------
|
||||
|
||||
def autolink_role(typ: str, rawtext: str, etext: str, lineno: int, inliner: Inliner,
|
||||
|
@ -41,7 +41,7 @@ from sphinx.builders import Builder
|
||||
from sphinx.config import Config
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning
|
||||
from sphinx.ext.autodoc import Documenter
|
||||
from sphinx.ext.autosummary import import_by_name, get_documenter
|
||||
from sphinx.ext.autosummary import import_by_name, import_ivar_by_name, get_documenter
|
||||
from sphinx.locale import __
|
||||
from sphinx.pycode import ModuleAnalyzer, PycodeError
|
||||
from sphinx.registry import SphinxComponentRegistry
|
||||
@ -413,8 +413,13 @@ def generate_autosummary_docs(sources: List[str], output_dir: str = None,
|
||||
name, obj, parent, modname = import_by_name(entry.name)
|
||||
qualname = name.replace(modname + ".", "")
|
||||
except ImportError as e:
|
||||
_warn(__('[autosummary] failed to import %r: %s') % (entry.name, e))
|
||||
continue
|
||||
try:
|
||||
# try to importl as an instance attribute
|
||||
name, obj, parent, modname = import_ivar_by_name(entry.name)
|
||||
qualname = name.replace(modname + ".", "")
|
||||
except ImportError:
|
||||
_warn(__('[autosummary] failed to import %r: %s') % (entry.name, e))
|
||||
continue
|
||||
|
||||
context = {}
|
||||
if app:
|
||||
|
@ -16,7 +16,8 @@ class Foo:
|
||||
pass
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
#: docstring
|
||||
self.value = 1
|
||||
|
||||
def bar(self):
|
||||
pass
|
||||
|
@ -10,6 +10,7 @@
|
||||
autosummary_dummy_module
|
||||
autosummary_dummy_module.Foo
|
||||
autosummary_dummy_module.Foo.Bar
|
||||
autosummary_dummy_module.Foo.value
|
||||
autosummary_dummy_module.bar
|
||||
autosummary_dummy_module.qux
|
||||
autosummary_importfail
|
||||
|
@ -293,15 +293,17 @@ def test_autosummary_generate(app, status, warning):
|
||||
nodes.row,
|
||||
nodes.row,
|
||||
nodes.row,
|
||||
nodes.row,
|
||||
nodes.row)])])
|
||||
assert_node(doctree[4][0], addnodes.toctree, caption="An autosummary")
|
||||
|
||||
assert len(doctree[3][0][0][2]) == 5
|
||||
assert len(doctree[3][0][0][2]) == 6
|
||||
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.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_dummy_module.qux\n\na module-level attribute'
|
||||
assert doctree[3][0][0][2][3].astext() == 'autosummary_dummy_module.Foo.value\n\ndocstring'
|
||||
assert doctree[3][0][0][2][4].astext() == 'autosummary_dummy_module.bar(x[, y])\n\n'
|
||||
assert doctree[3][0][0][2][5].astext() == 'autosummary_dummy_module.qux\n\na module-level attribute'
|
||||
|
||||
module = (app.srcdir / 'generated' / 'autosummary_dummy_module.rst').read_text()
|
||||
assert (' .. autosummary::\n'
|
||||
@ -333,6 +335,11 @@ def test_autosummary_generate(app, status, warning):
|
||||
'\n'
|
||||
'.. autoclass:: Foo.Bar\n' in FooBar)
|
||||
|
||||
Foo_value = (app.srcdir / 'generated' / 'autosummary_dummy_module.Foo.value.rst').read_text()
|
||||
assert ('.. currentmodule:: autosummary_dummy_module\n'
|
||||
'\n'
|
||||
'.. autoattribute:: Foo.value' in Foo_value)
|
||||
|
||||
qux = (app.srcdir / 'generated' / 'autosummary_dummy_module.qux.rst').read_text()
|
||||
assert ('.. currentmodule:: autosummary_dummy_module\n'
|
||||
'\n'
|
||||
|
Loading…
Reference in New Issue
Block a user