Fix sphinx.ext.autodoc crashes if target code imports * from mock modules by autodoc_mock_imports

This commit is contained in:
Takeshi KOMIYA 2016-08-09 12:19:49 +09:00
parent 54dd5c5fd1
commit e15216c568
6 changed files with 63 additions and 8 deletions

View File

@ -101,6 +101,8 @@ Bugs fixed
* #2707: (latex) the column width is badly computed for tabular
* #2799: Sphinx installs roles and directives automatically on importing sphinx
module. Now Sphinx installs them on running application.
* `sphinx.ext.autodoc` crashes if target code imports * from mock modules
by `autodoc_mock_imports`.
Documentation
-------------

View File

@ -86,17 +86,21 @@ class Options(dict):
class _MockModule(object):
"""Used by autodoc_mock_imports."""
__file__ = '/dev/null'
__path__ = '/dev/null'
def __init__(self, *args, **kwargs):
pass
self.__all__ = []
def __call__(self, *args, **kwargs):
return _MockModule()
def _append_submodule(self, submod):
self.__all__.append(submod)
@classmethod
def __getattr__(cls, name):
if name in ('__file__', '__path__'):
return '/dev/null'
elif name[0] == name[0].upper():
if name[0] == name[0].upper():
# Not very good, we assume Uppercase names are classes...
mocktype = type(name, (), {})
mocktype.__module__ = __name__
@ -109,9 +113,12 @@ def mock_import(modname):
if '.' in modname:
pkg, _n, mods = modname.rpartition('.')
mock_import(pkg)
mod = _MockModule()
sys.modules[modname] = mod
return mod
if isinstance(sys.modules[pkg], _MockModule):
sys.modules[pkg]._append_submodule(mods)
if modname not in sys.modules:
mod = _MockModule()
sys.modules[modname] = mod
ALL = object()
@ -514,7 +521,7 @@ class Documenter(object):
try:
dbg('[autodoc] import %s', self.modname)
for modname in self.env.config.autodoc_mock_imports:
dbg('[autodoc] adding a mock module %s!', self.modname)
dbg('[autodoc] adding a mock module %s!', modname)
mock_import(modname)
__import__(self.modname)
parent = None

View File

@ -0,0 +1,6 @@
from dummy import *
def test():
"""Dummy function using dummy.*"""
dummy_function()

View File

@ -0,0 +1,12 @@
import sys, os
sys.path.insert(0, os.path.abspath('.'))
extensions = ['sphinx.ext.autodoc']
# The suffix of source filenames.
source_suffix = '.rst'
autodoc_mock_imports = [
'dummy'
]

View File

@ -0,0 +1,3 @@
.. automodule:: autodoc_dummy_module
:members:

25
tests/test_ext_autodoc.py Normal file
View File

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
"""
test_autodoc
~~~~~~~~~~~~
Test the autodoc extension.
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
import pickle
from docutils import nodes
from sphinx import addnodes
from util import with_app
@with_app(buildername='dummy', testroot='ext-autodoc')
def test_autodoc(app, status, warning):
app.builder.build_all()
content = pickle.loads((app.doctreedir / 'contents.doctree').bytes())
assert isinstance(content[3], addnodes.desc)
assert content[3][0].astext() == 'autodoc_dummy_module.test'
assert content[3][1].astext() == 'Dummy function using dummy.*'