diff --git a/CHANGES b/CHANGES index 22876d43b1c..126dd2fffd3 100644 --- a/CHANGES +++ b/CHANGES @@ -34,6 +34,7 @@ Bugs fixed by string not ending with blank lines * #8142: autodoc: Wrong constructor signature for the class derived from typing.Generic +* #8157: autodoc: TypeError is raised when annotation has invalid __args__ * #8192: napoleon: description is disappeared when it contains inline literals * #8142: napoleon: Potential of regex denial of service in google style docs * #8169: LaTeX: pxjahyper loaded even when latex_engine is not platex diff --git a/sphinx/util/inspect.py b/sphinx/util/inspect.py index 37997e6b275..228efd98106 100644 --- a/sphinx/util/inspect.py +++ b/sphinx/util/inspect.py @@ -9,6 +9,7 @@ """ import builtins +import collections.abc import contextlib import enum import inspect @@ -302,6 +303,11 @@ def iscoroutinefunction(obj: Any) -> bool: return False +def isiterable(obj: Any) -> bool: + """Check if the object is iterable.""" + return isinstance(obj, collections.abc.Iterable) + + def isproperty(obj: Any) -> bool: """Check if the object is property.""" if sys.version_info > (3, 8): diff --git a/sphinx/util/typing.py b/sphinx/util/typing.py index d71ca1b2d66..19196b595fe 100644 --- a/sphinx/util/typing.py +++ b/sphinx/util/typing.py @@ -15,6 +15,8 @@ from docutils import nodes from docutils.parsers.rst.states import Inliner +from sphinx.util.inspect import isiterable + if sys.version_info > (3, 7): from typing import ForwardRef @@ -105,7 +107,10 @@ def _stringify_py37(annotation: Any) -> str: return repr(annotation) if getattr(annotation, '__args__', None): - if qualname == 'Union': + if not isiterable(annotation.__args__): + # broken __args__ found + qualname = repr(annotation) + elif qualname == 'Union': if len(annotation.__args__) > 1 and annotation.__args__[-1] is NoneType: if len(annotation.__args__) > 2: args = ', '.join(stringify(a) for a in annotation.__args__[:-1])