diff --git a/CHANGES b/CHANGES index 585dd42b7..3fa74fea5 100644 --- a/CHANGES +++ b/CHANGES @@ -34,6 +34,8 @@ Bugs fixed * #4928: i18n: Ignore dot-directories like .git/ in LC_MESSAGES/ * #4946: py domain: type field could not handle "None" as a type * #4979: latex: Incorrect escaping of curly braces in index entries +* #4956: autodoc: Failed to extract document from a subclass of the class on + mocked module Testing -------- diff --git a/sphinx/ext/autodoc/importer.py b/sphinx/ext/autodoc/importer.py index 00a55c4c5..e3bf1560c 100644 --- a/sphinx/ext/autodoc/importer.py +++ b/sphinx/ext/autodoc/importer.py @@ -23,7 +23,7 @@ from sphinx.util.inspect import isenumclass, safe_getattr if False: # For type annotation - from typing import Any, Callable, Dict, Generator, List, Optional # NOQA + from typing import Any, Callable, Dict, Generator, List, Optional, Tuple # NOQA logger = logging.getLogger(__name__) @@ -31,6 +31,14 @@ logger = logging.getLogger(__name__) class _MockObject(object): """Used by autodoc_mock_imports.""" + def __new__(cls, *args, **kwargs): + # type: (Any, Any) -> Any + if len(args) == 3 and isinstance(args[1], tuple) and args[1][-1].__class__ is cls: + # subclassing MockObject + return type(args[0], (_MockObject,), args[2], **kwargs) # type: ignore + else: + return super(_MockObject, cls).__new__(cls) + def __init__(self, *args, **kwargs): # type: (Any, Any) -> None pass @@ -47,6 +55,10 @@ class _MockObject(object): # type: () -> None pass + def __mro_entries__(self, bases): + # type: (Tuple) -> Tuple + return bases + def __getitem__(self, key): # type: (str) -> _MockObject return self diff --git a/tests/test_ext_autodoc_importer.py b/tests/test_ext_autodoc_importer.py new file mode 100644 index 000000000..fe0c9f2bc --- /dev/null +++ b/tests/test_ext_autodoc_importer.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +""" + test_ext_autodoc_importer + ~~~~~~~~~~~~~~~~~~~~~~~~~ + + Test the autodoc extension. + + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +from sphinx.ext.autodoc.importer import _MockObject + + +def test_MockObject(): + mock = _MockObject() + assert isinstance(mock.some_attr, _MockObject) + assert isinstance(mock.some_method, _MockObject) + assert isinstance(mock.attr1.attr2, _MockObject) + assert isinstance(mock.attr1.attr2.meth(), _MockObject) + + class SubClass(mock.SomeClass): + """docstring of SubClass""" + def method(self): + return "string" + + obj = SubClass() + assert SubClass.__doc__ == "docstring of SubClass" + assert isinstance(obj, SubClass) + assert obj.method() == "string" + assert isinstance(obj.other_method(), SubClass)