diff options
author | Takeshi KOMIYA <i.tkomiya@gmail.com> | 2021-01-27 18:56:46 +0300 |
---|---|---|
committer | Takeshi KOMIYA <i.tkomiya@gmail.com> | 2021-01-27 18:56:46 +0300 |
commit | c9480f99433a660942cbd8a739d989cb69fedc36 (patch) | |
tree | a5861ecf723184f5a7e6e89ba14433867f2d5e4f /sphinx/ext | |
parent | 2ee0338388a54e976c3776c116cdc1080fb62c53 (diff) | |
parent | 62dad2f13331d15d94b36b8f125f08fd4304b68b (diff) |
Merge branch '3.x'
Diffstat (limited to 'sphinx/ext')
-rw-r--r-- | sphinx/ext/autodoc/__init__.py | 6 | ||||
-rw-r--r-- | sphinx/ext/autodoc/importer.py | 4 | ||||
-rw-r--r-- | sphinx/ext/autodoc/mock.py | 27 | ||||
-rw-r--r-- | sphinx/ext/viewcode.py | 13 |
4 files changed, 42 insertions, 8 deletions
diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index ee74db370..b4d5a4581 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -26,7 +26,7 @@ from sphinx.deprecation import RemovedInSphinx50Warning, RemovedInSphinx60Warnin from sphinx.environment import BuildEnvironment from sphinx.ext.autodoc.importer import (get_class_members, get_object_members, import_module, import_object) -from sphinx.ext.autodoc.mock import ismock, mock +from sphinx.ext.autodoc.mock import ismock, mock, undecorate from sphinx.locale import _, __ from sphinx.pycode import ModuleAnalyzer, PycodeError from sphinx.util import inspect, logging @@ -418,6 +418,8 @@ class Documenter: attrgetter=self.get_attr, warningiserror=self.config.autodoc_warningiserror) self.module, self.parent, self.object_name, self.object = ret + if ismock(self.object): + self.object = undecorate(self.object) return True except ImportError as exc: if raiseerror: @@ -1046,6 +1048,8 @@ class ModuleDocumenter(Documenter): for name in dir(self.object): try: value = safe_getattr(self.object, name, None) + if ismock(value): + value = undecorate(value) docstring = attr_docs.get(('', name), []) members[name] = ObjectMember(name, value, docstring="\n".join(docstring)) except AttributeError: diff --git a/sphinx/ext/autodoc/importer.py b/sphinx/ext/autodoc/importer.py index 097dc6d07..a60feed7e 100644 --- a/sphinx/ext/autodoc/importer.py +++ b/sphinx/ext/autodoc/importer.py @@ -14,6 +14,7 @@ import warnings from typing import Any, Callable, Dict, List, NamedTuple, Optional, Tuple from sphinx.deprecation import RemovedInSphinx50Warning +from sphinx.ext.autodoc.mock import ismock, undecorate from sphinx.pycode import ModuleAnalyzer, PycodeError from sphinx.util import logging from sphinx.util.inspect import (getannotations, getmro, getslots, isclass, isenumclass, @@ -273,6 +274,9 @@ def get_class_members(subject: Any, objpath: List[str], attrgetter: Callable for name in dir(subject): try: value = attrgetter(subject, name) + if ismock(value): + value = undecorate(value) + unmangled = unmangle(subject, name) if unmangled and unmangled not in members: if name in obj_dict: diff --git a/sphinx/ext/autodoc/mock.py b/sphinx/ext/autodoc/mock.py index 513ce523f..80e3d2b50 100644 --- a/sphinx/ext/autodoc/mock.py +++ b/sphinx/ext/autodoc/mock.py @@ -13,7 +13,7 @@ import os import sys from importlib.abc import Loader, MetaPathFinder from importlib.machinery import ModuleSpec -from types import FunctionType, MethodType, ModuleType +from types import ModuleType from typing import Any, Generator, Iterator, List, Optional, Sequence, Tuple, Union from sphinx.util import logging @@ -27,6 +27,7 @@ class _MockObject: __display_name__ = '_MockObject' __sphinx_mock__ = True + __sphinx_decorator_args__ = () # type: Tuple[Any, ...] def __new__(cls, *args: Any, **kwargs: Any) -> Any: if len(args) == 3 and isinstance(args[1], tuple): @@ -60,18 +61,19 @@ class _MockObject: return _make_subclass(key, self.__display_name__, self.__class__)() def __call__(self, *args: Any, **kwargs: Any) -> Any: - if args and type(args[0]) in [type, FunctionType, MethodType]: - # Appears to be a decorator, pass through unchanged - return args[0] - return self + call = self.__class__() + call.__sphinx_decorator_args__ = args + return call def __repr__(self) -> str: return self.__display_name__ def _make_subclass(name: str, module: str, superclass: Any = _MockObject, - attributes: Any = None) -> Any: - attrs = {'__module__': module, '__display_name__': module + '.' + name} + attributes: Any = None, decorator_args: Tuple = ()) -> Any: + attrs = {'__module__': module, + '__display_name__': module + '.' + name, + '__sphinx_decorator_args__': decorator_args} attrs.update(attributes or {}) return type(name, (superclass,), attrs) @@ -172,3 +174,14 @@ def ismock(subject: Any) -> bool: pass return False + + +def undecorate(subject: _MockObject) -> Any: + """Unwrap mock if *subject* is decorated by mocked object. + + If not decorated, returns given *subject* itself. + """ + if ismock(subject) and subject.__sphinx_decorator_args__: + return subject.__sphinx_decorator_args__[0] + else: + return subject diff --git a/sphinx/ext/viewcode.py b/sphinx/ext/viewcode.py index baf86dbbf..21cff6a03 100644 --- a/sphinx/ext/viewcode.py +++ b/sphinx/ext/viewcode.py @@ -149,6 +149,18 @@ def env_merge_info(app: Sphinx, env: BuildEnvironment, docnames: Iterable[str], env._viewcode_modules.update(other._viewcode_modules) # type: ignore +def env_purge_doc(app: Sphinx, env: BuildEnvironment, docname: str) -> None: + modules = getattr(env, '_viewcode_modules', {}) + + for modname, (code, tags, used, refname) in list(modules.items()): + for fullname in list(used): + if used[fullname] == docname: + used.pop(fullname) + + if len(used) == 0: + modules.pop(modname) + + class ViewcodeAnchorTransform(SphinxPostTransform): """Convert or remove viewcode_anchor nodes depends on builder.""" default_priority = 100 @@ -323,6 +335,7 @@ def setup(app: Sphinx) -> Dict[str, Any]: app.add_config_value('viewcode_follow_imported_members', True, False) app.connect('doctree-read', doctree_read) app.connect('env-merge-info', env_merge_info) + app.connect('env-purge-doc', env_purge_doc) app.connect('html-collect-pages', collect_pages) app.connect('missing-reference', missing_reference) # app.add_config_value('viewcode_include_modules', [], 'env') |