From dcd8ff544aadbd75a6357457462be15e17fa2e67 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Thu, 19 Nov 2020 00:32:49 +0900 Subject: [PATCH] Fix #8443: autoattribute does not support uninitialized ivars --- CHANGES | 2 ++ sphinx/ext/autodoc/__init__.py | 20 ++++++++++++++++- tests/test_ext_autodoc_autoattribute.py | 30 +++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 5639d032f..44f63a357 100644 --- a/CHANGES +++ b/CHANGES @@ -45,6 +45,8 @@ Bugs fixed and attributes * #8443: autodoc: autodata directive can't create document for PEP-526 based type annotated variables +* #8443: autodoc: autoattribute directive can't create document for PEP-526 + based uninitalized variables * #8419: html search: Do not load ``language_data.js`` in non-search pages Testing diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index 79a3c78fc..a73b67f92 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -2045,6 +2045,22 @@ class AttributeDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter): def isinstanceattribute(self) -> bool: """Check the subject is an instance attribute.""" + # uninitialized instance variable (PEP-526) + with mock(self.config.autodoc_mock_imports): + try: + ret = import_object(self.modname, self.objpath[:-1], 'class', + attrgetter=self.get_attr, + warningiserror=self.config.autodoc_warningiserror) + self.parent = ret[3] + annotations = get_type_hints(self.parent, None, + self.config.autodoc_type_aliases) + if self.objpath[-1] in annotations: + self.object = UNINITIALIZED_ATTR + return True + except ImportError: + pass + + # An instance variable defined inside __init__(). try: analyzer = ModuleAnalyzer.for_module(self.modname) attr_docs = analyzer.find_attr_docs() @@ -2055,7 +2071,9 @@ class AttributeDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter): return False except PycodeError: - return False + pass + + return False def import_object(self, raiseerror: bool = False) -> bool: try: diff --git a/tests/test_ext_autodoc_autoattribute.py b/tests/test_ext_autodoc_autoattribute.py index ca74f9aeb..31dccbd03 100644 --- a/tests/test_ext_autodoc_autoattribute.py +++ b/tests/test_ext_autodoc_autoattribute.py @@ -9,6 +9,8 @@ :license: BSD, see LICENSE for details. """ +import sys + import pytest from test_ext_autodoc import do_autodoc @@ -39,3 +41,31 @@ def test_autoattribute_novalue(app): ' should be documented -- süß', '', ] + + +@pytest.mark.skipif(sys.version_info < (3, 6), reason='python 3.6+ is required.') +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autoattribute_typed_variable(app): + actual = do_autodoc(app, 'attribute', 'target.typed_vars.Class.attr2') + assert list(actual) == [ + '', + '.. py:attribute:: Class.attr2', + ' :module: target.typed_vars', + ' :type: int', + '', + ] + + +@pytest.mark.skipif(sys.version_info < (3, 6), reason='python 3.6+ is required.') +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autoattribute_instance_variable(app): + actual = do_autodoc(app, 'attribute', 'target.typed_vars.Class.attr4') + assert list(actual) == [ + '', + '.. py:attribute:: Class.attr4', + ' :module: target.typed_vars', + ' :type: int', + '', + ' attr4', + '', + ]