From 611fff975e9c1b3972fd9e2dfd7a96d3d8d8cdb7 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Thu, 13 Aug 2020 00:05:27 +0900 Subject: [PATCH] Fix #8099: autodoc: NameError is raised when script uses TYPE_CHECKING `typing.get_type_hints()` raises NameError when the target object contains unresolavable type annotation (ex. TYPE_CHECKING). This handles the exception and use unresolved annotations for type hints. --- CHANGES | 1 + sphinx/ext/autodoc/__init__.py | 6 +++++ .../test-ext-autodoc/target/TYPE_CHECKING.py | 8 +++++++ tests/test_ext_autodoc.py | 22 +++++++++++++++++++ 4 files changed, 37 insertions(+) create mode 100644 tests/roots/test-ext-autodoc/target/TYPE_CHECKING.py diff --git a/CHANGES b/CHANGES index b852b699255..0615b3108e4 100644 --- a/CHANGES +++ b/CHANGES @@ -47,6 +47,7 @@ Bugs fixed class * #8091: autodoc: AttributeError is raised on documenting an attribute on Python 3.5.2 +* #8099: autodoc: NameError is raised when target code uses ``TYPE_CHECKING`` Testing -------- diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index f3820f71552..b61a96c8494 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -1608,6 +1608,9 @@ def add_directive_header(self, sig: str) -> None: # obtain annotation for this data try: annotations = get_type_hints(self.parent) + except NameError: + # Failed to evaluate ForwardRef (maybe TYPE_CHECKING) + annotations = safe_getattr(self.parent, '__annotations__', {}) except TypeError: annotations = {} except KeyError: @@ -1984,6 +1987,9 @@ def add_directive_header(self, sig: str) -> None: # obtain type annotation for this attribute try: annotations = get_type_hints(self.parent) + except NameError: + # Failed to evaluate ForwardRef (maybe TYPE_CHECKING) + annotations = safe_getattr(self.parent, '__annotations__', {}) except TypeError: annotations = {} except KeyError: diff --git a/tests/roots/test-ext-autodoc/target/TYPE_CHECKING.py b/tests/roots/test-ext-autodoc/target/TYPE_CHECKING.py new file mode 100644 index 00000000000..aa7eb99a6e0 --- /dev/null +++ b/tests/roots/test-ext-autodoc/target/TYPE_CHECKING.py @@ -0,0 +1,8 @@ +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from io import StringIO + + +class Foo: + attr1: "StringIO" diff --git a/tests/test_ext_autodoc.py b/tests/test_ext_autodoc.py index 15e1f35395e..90a2ec95a37 100644 --- a/tests/test_ext_autodoc.py +++ b/tests/test_ext_autodoc.py @@ -1740,6 +1740,28 @@ def test_autodoc_Annotated(app): ] +@pytest.mark.skipif(sys.version_info < (3, 6), reason='py36+ is required.') +@pytest.mark.sphinx('html', testroot='ext-autodoc') +def test_autodoc_TYPE_CHECKING(app): + options = {"members": None, + "undoc-members": None} + actual = do_autodoc(app, 'module', 'target.TYPE_CHECKING', options) + assert list(actual) == [ + '', + '.. py:module:: target.TYPE_CHECKING', + '', + '', + '.. py:class:: Foo()', + ' :module: target.TYPE_CHECKING', + '', + '', + ' .. py:attribute:: Foo.attr1', + ' :module: target.TYPE_CHECKING', + ' :type: StringIO', + '', + ] + + @pytest.mark.sphinx('html', testroot='pycode-egg') def test_autodoc_for_egged_code(app): options = {"members": None,