From 6076bff66259e3f1fdb8f3e305fb4bc7452345ce Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 18 Nov 2020 01:22:55 +0900 Subject: [PATCH] refactor: Add sphinx.util.typing.get_type_hints() Add a simple wrapper of `typing.get_type_hints()` that does not raise an error on runtime. --- sphinx/ext/autodoc/__init__.py | 36 ++++------------------------------ sphinx/util/typing.py | 23 ++++++++++++++++++++++ 2 files changed, 27 insertions(+), 32 deletions(-) diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index a79e540eb..665927268 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -16,7 +16,7 @@ import warnings from inspect import Parameter, Signature from types import ModuleType from typing import (Any, Callable, Dict, Iterator, List, Optional, Sequence, Set, Tuple, Type, - TypeVar, Union, get_type_hints) + TypeVar, Union) from docutils.statemachine import StringList @@ -33,7 +33,7 @@ from sphinx.util import inspect, logging from sphinx.util.docstrings import extract_metadata, prepare_docstring from sphinx.util.inspect import (evaluate_signature, getdoc, object_description, safe_getattr, stringify_signature) -from sphinx.util.typing import restify +from sphinx.util.typing import get_type_hints, restify from sphinx.util.typing import stringify as stringify_typehint if False: @@ -1701,21 +1701,7 @@ class DataDocumenter(ModuleLevelDocumenter): sourcename = self.get_sourcename() if not self.options.annotation: # obtain annotation for this data - try: - annotations = get_type_hints(self.parent, None, - self.config.autodoc_type_aliases) - except NameError: - # Failed to evaluate ForwardRef (maybe TYPE_CHECKING) - annotations = safe_getattr(self.parent, '__annotations__', {}) - except TypeError: - annotations = {} - except KeyError: - # a broken class found (refs: https://github.com/sphinx-doc/sphinx/issues/8084) - annotations = {} - except AttributeError: - # AttributeError is raised on 3.5.2 (fixed by 3.5.3) - annotations = {} - + annotations = get_type_hints(self.parent, None, self.config.autodoc_type_aliases) if self.objpath[-1] in annotations: objrepr = stringify_typehint(annotations.get(self.objpath[-1])) self.add_line(' :type: ' + objrepr, sourcename) @@ -2093,21 +2079,7 @@ class AttributeDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter): sourcename = self.get_sourcename() if not self.options.annotation: # obtain type annotation for this attribute - try: - annotations = get_type_hints(self.parent, None, - self.config.autodoc_type_aliases) - except NameError: - # Failed to evaluate ForwardRef (maybe TYPE_CHECKING) - annotations = safe_getattr(self.parent, '__annotations__', {}) - except TypeError: - annotations = {} - except KeyError: - # a broken class found (refs: https://github.com/sphinx-doc/sphinx/issues/8084) - annotations = {} - except AttributeError: - # AttributeError is raised on 3.5.2 (fixed by 3.5.3) - annotations = {} - + annotations = get_type_hints(self.parent, None, self.config.autodoc_type_aliases) if self.objpath[-1] in annotations: objrepr = stringify_typehint(annotations.get(self.objpath[-1])) self.add_line(' :type: ' + objrepr, sourcename) diff --git a/sphinx/util/typing.py b/sphinx/util/typing.py index 28f9c5e38..18649433b 100644 --- a/sphinx/util/typing.py +++ b/sphinx/util/typing.py @@ -57,6 +57,29 @@ TitleGetter = Callable[[nodes.Node], str] Inventory = Dict[str, Dict[str, Tuple[str, str, str, str]]] +def get_type_hints(obj: Any, globalns: Dict = None, localns: Dict = None) -> Dict[str, Any]: + """Return a dictionary containing type hints for a function, method, module or class object. + + This is a simple wrapper of `typing.get_type_hints()` that does not raise an error on + runtime. + """ + from sphinx.util.inspect import safe_getattr # lazy loading + + try: + return typing.get_type_hints(obj, None, localns) + except NameError: + # Failed to evaluate ForwardRef (maybe TYPE_CHECKING) + return safe_getattr(obj, '__annotations__', {}) + except TypeError: + return {} + except KeyError: + # a broken class found (refs: https://github.com/sphinx-doc/sphinx/issues/8084) + return {} + except AttributeError: + # AttributeError is raised on 3.5.2 (fixed by 3.5.3) + return {} + + def is_system_TypeVar(typ: Any) -> bool: """Check *typ* is system defined TypeVar.""" modname = getattr(typ, '__module__', '')