From 6f8d9390df41d377621020767b00e35601474871 Mon Sep 17 00:00:00 2001 From: Pawel Budzynski Date: Thu, 29 Apr 2021 14:15:51 +0200 Subject: [PATCH 1/4] autosummary includes instance attributes --- sphinx/ext/autosummary/__init__.py | 5 +++-- sphinx/ext/autosummary/generate.py | 16 +++++++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/sphinx/ext/autosummary/__init__.py b/sphinx/ext/autosummary/__init__.py index c29714ad4..5071921cc 100644 --- a/sphinx/ext/autosummary/__init__.py +++ b/sphinx/ext/autosummary/__init__.py @@ -662,8 +662,9 @@ def import_ivar_by_name(name: str, prefixes: List[str] = [None]) -> Tuple[str, A 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(): + analyzer = ModuleAnalyzer.for_module(getattr(obj, '__module__', modname)) + analyzer.analyze() + if (qualname, attr) in analyzer.attr_docs or (qualname, attr) in analyzer.annotations: return real_name + "." + attr, INSTANCEATTR, obj, modname except (ImportError, ValueError, PycodeError): pass diff --git a/sphinx/ext/autosummary/generate.py b/sphinx/ext/autosummary/generate.py index d1130d096..107b87605 100644 --- a/sphinx/ext/autosummary/generate.py +++ b/sphinx/ext/autosummary/generate.py @@ -239,15 +239,21 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any, name, exc, type='autosummary') return False + def attr_getter(obj, name, *defargs): + return sphinx.ext.autodoc.autodoc_attrgetter(app, obj, name, *defargs) + + def get_all_members(obj): + all_members = sphinx.ext.autodoc.get_class_members(obj, [qualname], attr_getter) + return all_members + def get_members(obj: Any, types: Set[str], include_public: List[str] = [], imported: bool = True) -> Tuple[List[str], List[str]]: items: List[str] = [] public: List[str] = [] - for name in dir(obj): - try: - value = safe_getattr(obj, name) - except AttributeError: - continue + + all_members = get_all_members(obj) + for name, member in all_members.items(): + value = member.object documenter = get_documenter(app, value, obj) if documenter.objtype in types: # skip imported members if expected From f12f5bc0757e5a3f3029fee8c23b2339ac0cc738 Mon Sep 17 00:00:00 2001 From: Pawel Budzynski Date: Thu, 29 Apr 2021 14:48:56 +0200 Subject: [PATCH 2/4] add tests --- tests/roots/test-autosummary/dummy_module.py | 7 +++++++ tests/test_ext_autosummary.py | 2 ++ 2 files changed, 9 insertions(+) diff --git a/tests/roots/test-autosummary/dummy_module.py b/tests/roots/test-autosummary/dummy_module.py index 93d482b59..4adc0313e 100644 --- a/tests/roots/test-autosummary/dummy_module.py +++ b/tests/roots/test-autosummary/dummy_module.py @@ -3,6 +3,7 @@ module_attr C.class_attr + C.instance_attr C.prop_attr1 C.prop_attr2 C.C2 @@ -51,6 +52,12 @@ class C: #: value is integer. class_attr = 42 + def __init__(self): + #: This is an instance attribute + #: + #: value is a string + self.instance_attr = "42" + def _prop_attr_get(self): """ This is a function docstring diff --git a/tests/test_ext_autosummary.py b/tests/test_ext_autosummary.py index 5d92b6afd..71868d492 100644 --- a/tests/test_ext_autosummary.py +++ b/tests/test_ext_autosummary.py @@ -161,6 +161,7 @@ def test_get_items_summary(make_app, app_params): 'emptyLine': "This is the real summary", 'module_attr': 'This is a module attribute', 'C.class_attr': 'This is a class attribute', + 'C.instance_attr': 'This is an instance attribute', 'C.prop_attr1': 'This is a function docstring', 'C.prop_attr2': 'This is a attribute docstring', 'C.C2': 'This is a nested inner class docstring', @@ -329,6 +330,7 @@ def test_autosummary_generate(app, status, warning): ' ~Foo.CONSTANT3\n' ' ~Foo.CONSTANT4\n' ' ~Foo.baz\n' + ' ~Foo.value\n' ' \n' in Foo) FooBar = (app.srcdir / 'generated' / 'autosummary_dummy_module.Foo.Bar.rst').read_text() From 260e26cad4fb2753653c07d639118bc899e8f68d Mon Sep 17 00:00:00 2001 From: Pawel Budzynski Date: Thu, 29 Apr 2021 16:28:18 +0200 Subject: [PATCH 3/4] add type hints --- sphinx/ext/autosummary/__init__.py | 1 + sphinx/ext/autosummary/generate.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/sphinx/ext/autosummary/__init__.py b/sphinx/ext/autosummary/__init__.py index 5071921cc..562bf9fd3 100644 --- a/sphinx/ext/autosummary/__init__.py +++ b/sphinx/ext/autosummary/__init__.py @@ -664,6 +664,7 @@ def import_ivar_by_name(name: str, prefixes: List[str] = [None]) -> Tuple[str, A qualname = real_name.replace(modname + ".", "") analyzer = ModuleAnalyzer.for_module(getattr(obj, '__module__', modname)) analyzer.analyze() + # check for presence in `annotations` to include dataclass attributes if (qualname, attr) in analyzer.attr_docs or (qualname, attr) in analyzer.annotations: return real_name + "." + attr, INSTANCEATTR, obj, modname except (ImportError, ValueError, PycodeError): diff --git a/sphinx/ext/autosummary/generate.py b/sphinx/ext/autosummary/generate.py index 107b87605..8a781a2e2 100644 --- a/sphinx/ext/autosummary/generate.py +++ b/sphinx/ext/autosummary/generate.py @@ -39,7 +39,7 @@ from sphinx.application import Sphinx from sphinx.builders import Builder from sphinx.config import Config from sphinx.deprecation import RemovedInSphinx50Warning -from sphinx.ext.autodoc import Documenter +from sphinx.ext.autodoc import Documenter, ObjectMember from sphinx.ext.autodoc.importer import import_module from sphinx.ext.autosummary import get_documenter, import_by_name, import_ivar_by_name from sphinx.locale import __ @@ -242,7 +242,7 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any, def attr_getter(obj, name, *defargs): return sphinx.ext.autodoc.autodoc_attrgetter(app, obj, name, *defargs) - def get_all_members(obj): + def get_all_members(obj: Any) -> Dict[str, ObjectMember]: all_members = sphinx.ext.autodoc.get_class_members(obj, [qualname], attr_getter) return all_members From abbd0056127e0834fff8933c25637fe2179b2332 Mon Sep 17 00:00:00 2001 From: pbudzyns Date: Sun, 2 May 2021 13:55:16 +0200 Subject: [PATCH 4/4] revert get members for module --- sphinx/ext/autosummary/generate.py | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/sphinx/ext/autosummary/generate.py b/sphinx/ext/autosummary/generate.py index 8a781a2e2..4f3493659 100644 --- a/sphinx/ext/autosummary/generate.py +++ b/sphinx/ext/autosummary/generate.py @@ -39,7 +39,7 @@ from sphinx.application import Sphinx from sphinx.builders import Builder from sphinx.config import Config from sphinx.deprecation import RemovedInSphinx50Warning -from sphinx.ext.autodoc import Documenter, ObjectMember +from sphinx.ext.autodoc import Documenter from sphinx.ext.autodoc.importer import import_module from sphinx.ext.autosummary import get_documenter, import_by_name, import_ivar_by_name from sphinx.locale import __ @@ -239,12 +239,25 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any, name, exc, type='autosummary') return False - def attr_getter(obj, name, *defargs): - return sphinx.ext.autodoc.autodoc_attrgetter(app, obj, name, *defargs) + def get_class_members(obj: Any) -> Dict[str, Any]: + members = sphinx.ext.autodoc.get_class_members(obj, [qualname], safe_getattr) + return {name: member.object for name, member in members.items()} - def get_all_members(obj: Any) -> Dict[str, ObjectMember]: - all_members = sphinx.ext.autodoc.get_class_members(obj, [qualname], attr_getter) - return all_members + def get_module_members(obj: Any) -> Dict[str, Any]: + members = {} + for name in dir(obj): + try: + members[name] = safe_getattr(obj, name) + except AttributeError: + continue + return members + + def get_all_members(obj: Any) -> Dict[str, Any]: + if doc.objtype == "module": + return get_module_members(obj) + elif doc.objtype == "class": + return get_class_members(obj) + return {} def get_members(obj: Any, types: Set[str], include_public: List[str] = [], imported: bool = True) -> Tuple[List[str], List[str]]: @@ -252,8 +265,7 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any, public: List[str] = [] all_members = get_all_members(obj) - for name, member in all_members.items(): - value = member.object + for name, value in all_members.items(): documenter = get_documenter(app, value, obj) if documenter.objtype in types: # skip imported members if expected