diff --git a/pyproject.toml b/pyproject.toml index 4dc78f852ab..8e8dac4a4f8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -259,8 +259,6 @@ module = [ "sphinx.ext.autodoc", "sphinx.ext.autodoc.directive", "sphinx.ext.autodoc.importer", - "sphinx.ext.autodoc.mock", - "sphinx.ext.autodoc.mock", "sphinx.ext.autosummary.generate", "sphinx.ext.doctest", "sphinx.ext.graphviz", diff --git a/sphinx/ext/autodoc/mock.py b/sphinx/ext/autodoc/mock.py index c2ab0feb442..f17c3302cb6 100644 --- a/sphinx/ext/autodoc/mock.py +++ b/sphinx/ext/autodoc/mock.py @@ -8,13 +8,14 @@ from importlib.abc import Loader, MetaPathFinder from importlib.machinery import ModuleSpec from types import MethodType, ModuleType -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING from sphinx.util import logging from sphinx.util.inspect import isboundmethod, safe_getattr if TYPE_CHECKING: from collections.abc import Iterator, Sequence + from typing import Any logger = logging.getLogger(__name__) @@ -46,10 +47,10 @@ def __len__(self) -> int: def __contains__(self, key: str) -> bool: return False - def __iter__(self) -> Iterator: - return iter([]) + def __iter__(self) -> Iterator[Any]: + return iter(()) - def __mro_entries__(self, bases: tuple) -> tuple: + def __mro_entries__(self, bases: tuple[Any, ...]) -> tuple[type, ...]: return (self.__class__,) def __getitem__(self, key: Any) -> _MockObject: @@ -68,7 +69,7 @@ def __repr__(self) -> str: def _make_subclass(name: str, module: str, superclass: Any = _MockObject, - attributes: Any = None, decorator_args: tuple = ()) -> Any: + attributes: Any = None, decorator_args: tuple[Any, ...] = ()) -> Any: attrs = {'__module__': module, '__display_name__': module + '.' + name, '__name__': name, @@ -144,8 +145,8 @@ def mock(modnames: list[str]) -> Iterator[None]: # mock modules are enabled here ... """ + finder = MockFinder(modnames) try: - finder = MockFinder(modnames) sys.meta_path.insert(0, finder) yield finally: diff --git a/tests/test_extensions/test_ext_autodoc_automodule.py b/tests/test_extensions/test_ext_autodoc_automodule.py index 92565aef058..c6ced7eebb1 100644 --- a/tests/test_extensions/test_ext_autodoc_automodule.py +++ b/tests/test_extensions/test_ext_autodoc_automodule.py @@ -4,7 +4,9 @@ source file translated by test_build. """ +import inspect import sys +import typing import pytest @@ -185,8 +187,22 @@ def test_automodule_inherited_members(app): 'sphinx.missing_module4']}) @pytest.mark.usefixtures("rollback_sysmodules") def test_subclass_of_mocked_object(app): + from sphinx.ext.autodoc.mock import _MockObject sys.modules.pop('target', None) # unload target module to clear the module cache + options = {'members': None} + actual = do_autodoc(app, 'module', 'target.need_mocks', options) + # ``typing.Any`` is not available at runtime on ``_MockObject.__new__`` + assert '.. py:class:: Inherited(*args: Any, **kwargs: Any)' in actual + + # make ``typing.Any`` available at runtime on ``_MockObject.__new__`` + sig = inspect.signature(_MockObject.__new__) + parameters = sig.parameters.copy() + for name in ('args', 'kwargs'): + parameters[name] = parameters[name].replace(annotation=typing.Any) + sig = sig.replace(parameters=tuple(parameters.values())) + _MockObject.__new__.__signature__ = sig # type: ignore[attr-defined] + options = {'members': None} actual = do_autodoc(app, 'module', 'target.need_mocks', options) assert '.. py:class:: Inherited(*args: ~typing.Any, **kwargs: ~typing.Any)' in actual