diff --git a/CHANGES b/CHANGES index da1245f3251..de008d019a2 100644 --- a/CHANGES +++ b/CHANGES @@ -85,6 +85,8 @@ Bugs fixed attribute not having any comment * #9364: autodoc: single element tuple on the default argument value is wrongly rendered +* #9404: autodoc: TypeError is raised on processing dict-like object (not a + class) via autoclass directive * #9317: html: Pushing left key causes visiting the next page at the first page * #9381: html: URL for html_favicon and html_log does not work * #9270: html theme : pyramid theme generates incorrect logo links diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index 1cecb1f797d..4ce5a7ab1d4 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -1744,7 +1744,7 @@ def add_content(self, more_content: Optional[StringList], no_docstring: bool = F if self.doc_as_attr and not self.get_variable_comment(): try: more_content = StringList([_('alias of %s') % restify(self.object)], source='') - except AttributeError: + except (AttributeError, ValueError): pass # Invalid class object is passed. super().add_content(more_content) diff --git a/sphinx/util/typing.py b/sphinx/util/typing.py index 279268aee32..565f66cf676 100644 --- a/sphinx/util/typing.py +++ b/sphinx/util/typing.py @@ -105,27 +105,30 @@ def restify(cls: Optional[Type]) -> str: """Convert python class to a reST reference.""" from sphinx.util import inspect # lazy loading - if cls is None or cls is NoneType: - return ':obj:`None`' - elif cls is Ellipsis: - return '...' - elif cls in INVALID_BUILTIN_CLASSES: - return ':class:`%s`' % INVALID_BUILTIN_CLASSES[cls] - elif inspect.isNewType(cls): - return ':class:`%s`' % cls.__name__ - elif types_Union and isinstance(cls, types_Union): - if len(cls.__args__) > 1 and None in cls.__args__: - args = ' | '.join(restify(a) for a in cls.__args__ if a) - return 'Optional[%s]' % args - else: - return ' | '.join(restify(a) for a in cls.__args__) - elif cls.__module__ in ('__builtin__', 'builtins'): - return ':class:`%s`' % cls.__name__ - else: - if sys.version_info >= (3, 7): # py37+ - return _restify_py37(cls) + try: + if cls is None or cls is NoneType: + return ':obj:`None`' + elif cls is Ellipsis: + return '...' + elif cls in INVALID_BUILTIN_CLASSES: + return ':class:`%s`' % INVALID_BUILTIN_CLASSES[cls] + elif inspect.isNewType(cls): + return ':class:`%s`' % cls.__name__ + elif types_Union and isinstance(cls, types_Union): + if len(cls.__args__) > 1 and None in cls.__args__: + args = ' | '.join(restify(a) for a in cls.__args__ if a) + return 'Optional[%s]' % args + else: + return ' | '.join(restify(a) for a in cls.__args__) + elif cls.__module__ in ('__builtin__', 'builtins'): + return ':class:`%s`' % cls.__name__ else: - return _restify_py36(cls) + if sys.version_info >= (3, 7): # py37+ + return _restify_py37(cls) + else: + return _restify_py36(cls) + except TypeError as exc: + raise ValueError from exc def _restify_py37(cls: Optional[Type]) -> str: