mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
refactor `mock()
` to based on PEP-451 implementation
This commit is contained in:
parent
ab3eb1b61d
commit
1a50d34520
2
CHANGES
2
CHANGES
@ -39,12 +39,14 @@ Deprecated
|
|||||||
``autodoc.DocstringSignatureMixin.get_doc()``,
|
``autodoc.DocstringSignatureMixin.get_doc()``,
|
||||||
``autodoc.DocstringSignatureMixin._find_signature()``, and
|
``autodoc.DocstringSignatureMixin._find_signature()``, and
|
||||||
``autodoc.ClassDocumenter.get_doc()`` are deprecated.
|
``autodoc.ClassDocumenter.get_doc()`` are deprecated.
|
||||||
|
* The ``importer`` argument of ``sphinx.ext.autodoc.importer._MockModule``
|
||||||
* The ``nodetype`` argument of ``sphinx.search.WordCollector.
|
* The ``nodetype`` argument of ``sphinx.search.WordCollector.
|
||||||
is_meta_keywords()``
|
is_meta_keywords()``
|
||||||
* The ``suffix`` argument of ``env.doc2path()`` is deprecated.
|
* The ``suffix`` argument of ``env.doc2path()`` is deprecated.
|
||||||
* The string style ``base`` argument of ``env.doc2path()`` is deprecated.
|
* The string style ``base`` argument of ``env.doc2path()`` is deprecated.
|
||||||
* ``sphinx.application.Sphinx._setting_up_extension``
|
* ``sphinx.application.Sphinx._setting_up_extension``
|
||||||
* ``sphinx.ext.config.check_unicode()``
|
* ``sphinx.ext.config.check_unicode()``
|
||||||
|
* ``sphinx.ext.autodoc.importer._MockImporter``
|
||||||
* ``sphinx.ext.doctest.doctest_encode()``
|
* ``sphinx.ext.doctest.doctest_encode()``
|
||||||
* ``sphinx.testing.util.remove_unicode_literal()``
|
* ``sphinx.testing.util.remove_unicode_literal()``
|
||||||
* ``sphinx.util.force_decode()``
|
* ``sphinx.util.force_decode()``
|
||||||
|
@ -187,6 +187,16 @@ The following is a list of deprecated interfaces.
|
|||||||
- 3.0
|
- 3.0
|
||||||
- N/A
|
- N/A
|
||||||
|
|
||||||
|
* - The ``importer`` argument of ``sphinx.ext.autodoc.importer._MockModule``
|
||||||
|
- 2.0
|
||||||
|
- 3.0
|
||||||
|
- N/A
|
||||||
|
|
||||||
|
* - ``sphinx.ext.autodoc.importer._MockImporter``
|
||||||
|
- 2.0
|
||||||
|
- 3.0
|
||||||
|
- N/A
|
||||||
|
|
||||||
* - ``sphinx.writers.latex.LaTeXTranslator._make_visit_admonition()``
|
* - ``sphinx.writers.latex.LaTeXTranslator._make_visit_admonition()``
|
||||||
- 2.0
|
- 2.0
|
||||||
- 3.0
|
- 3.0
|
||||||
|
@ -14,14 +14,17 @@ import sys
|
|||||||
import traceback
|
import traceback
|
||||||
import warnings
|
import warnings
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
from importlib.abc import Loader, MetaPathFinder
|
||||||
|
from importlib.machinery import ModuleSpec
|
||||||
from types import FunctionType, MethodType, ModuleType
|
from types import FunctionType, MethodType, ModuleType
|
||||||
|
|
||||||
|
from sphinx.deprecation import RemovedInSphinx30Warning
|
||||||
from sphinx.util import logging
|
from sphinx.util import logging
|
||||||
from sphinx.util.inspect import isenumclass, safe_getattr
|
from sphinx.util.inspect import isenumclass, safe_getattr
|
||||||
|
|
||||||
if False:
|
if False:
|
||||||
# For type annotation
|
# For type annotation
|
||||||
from typing import Any, Callable, Dict, Generator, Iterator, List, Optional, Tuple # NOQA
|
from typing import Any, Callable, Dict, Generator, Iterator, List, Optional, Sequence, Tuple, Union # NOQA
|
||||||
from sphinx.util.typing import unicode # NOQA
|
from sphinx.util.typing import unicode # NOQA
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -78,13 +81,16 @@ class _MockModule(ModuleType):
|
|||||||
"""Used by autodoc_mock_imports."""
|
"""Used by autodoc_mock_imports."""
|
||||||
__file__ = '/dev/null'
|
__file__ = '/dev/null'
|
||||||
|
|
||||||
def __init__(self, name, loader):
|
def __init__(self, name, loader=None):
|
||||||
# type: (str, _MockImporter) -> None
|
# type: (str, _MockImporter) -> None
|
||||||
self.__name__ = self.__package__ = name
|
super(_MockModule, self).__init__(name)
|
||||||
self.__loader__ = loader
|
|
||||||
self.__all__ = [] # type: List[str]
|
self.__all__ = [] # type: List[str]
|
||||||
self.__path__ = [] # type: List[str]
|
self.__path__ = [] # type: List[str]
|
||||||
|
|
||||||
|
if loader is not None:
|
||||||
|
warnings.warn('The loader argument for _MockModule is deprecated.',
|
||||||
|
RemovedInSphinx30Warning)
|
||||||
|
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
# type: (str) -> _MockObject
|
# type: (str) -> _MockObject
|
||||||
o = _MockObject()
|
o = _MockObject()
|
||||||
@ -100,6 +106,9 @@ class _MockImporter:
|
|||||||
# enable hook by adding itself to meta_path
|
# enable hook by adding itself to meta_path
|
||||||
sys.meta_path.insert(0, self)
|
sys.meta_path.insert(0, self)
|
||||||
|
|
||||||
|
warnings.warn('_MockImporter is now deprecated.',
|
||||||
|
RemovedInSphinx30Warning)
|
||||||
|
|
||||||
def disable(self):
|
def disable(self):
|
||||||
# type: () -> None
|
# type: () -> None
|
||||||
# remove `self` from `sys.meta_path` to disable import hook
|
# remove `self` from `sys.meta_path` to disable import hook
|
||||||
@ -131,14 +140,66 @@ class _MockImporter:
|
|||||||
return module
|
return module
|
||||||
|
|
||||||
|
|
||||||
|
class MockLoader(Loader):
|
||||||
|
"""A loader for mocking."""
|
||||||
|
def __init__(self, finder):
|
||||||
|
# type: (MockFinder) -> None
|
||||||
|
super(MockLoader, self).__init__()
|
||||||
|
self.finder = finder
|
||||||
|
|
||||||
|
def create_module(self, spec):
|
||||||
|
# type: (ModuleSpec) -> ModuleType
|
||||||
|
logger.debug('[autodoc] adding a mock module as %s!', spec.name)
|
||||||
|
self.finder.mocked_modules.append(spec.name)
|
||||||
|
return _MockModule(spec.name)
|
||||||
|
|
||||||
|
def exec_module(self, module):
|
||||||
|
# type: (ModuleType) -> None
|
||||||
|
pass # nothing to do
|
||||||
|
|
||||||
|
|
||||||
|
class MockFinder(MetaPathFinder):
|
||||||
|
"""A finder for mocking."""
|
||||||
|
|
||||||
|
def __init__(self, modnames):
|
||||||
|
# type: (List[str]) -> None
|
||||||
|
super(MockFinder, self).__init__()
|
||||||
|
self.modnames = modnames
|
||||||
|
self.loader = MockLoader(self)
|
||||||
|
self.mocked_modules = [] # type: List[str]
|
||||||
|
|
||||||
|
def find_spec(self, fullname, path, target=None):
|
||||||
|
# type: (str, Sequence[Union[bytes, str]], ModuleType) -> ModuleSpec
|
||||||
|
for modname in self.modnames:
|
||||||
|
# check if fullname is (or is a descendant of) one of our targets
|
||||||
|
if modname == fullname or fullname.startswith(modname + '.'):
|
||||||
|
return ModuleSpec(fullname, self.loader)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def invalidate_caches(self):
|
||||||
|
# type: () -> None
|
||||||
|
"""Invalidate mocked modules on sys.modules."""
|
||||||
|
for modname in self.mocked_modules:
|
||||||
|
sys.modules.pop(modname, None)
|
||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def mock(names):
|
def mock(modnames):
|
||||||
# type: (List[str]) -> Generator
|
# type: (List[str]) -> Generator[None, None, None]
|
||||||
|
"""Insert mock modules during context::
|
||||||
|
|
||||||
|
with mock(['target.module.name']):
|
||||||
|
# mock modules are enabled here
|
||||||
|
...
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
importer = _MockImporter(names)
|
finder = MockFinder(modnames)
|
||||||
|
sys.meta_path.insert(0, finder)
|
||||||
yield
|
yield
|
||||||
finally:
|
finally:
|
||||||
importer.disable()
|
sys.meta_path.remove(finder)
|
||||||
|
finder.invalidate_caches()
|
||||||
|
|
||||||
|
|
||||||
def import_module(modname, warningiserror=False):
|
def import_module(modname, warningiserror=False):
|
||||||
|
Loading…
Reference in New Issue
Block a user