Skip to content

Commit

Permalink
Merge pull request sphinx-doc#4232 from sphinx-doc/4212_autosummary-i…
Browse files Browse the repository at this point in the history
…mportsafe

4212 autosummary importsafe
  • Loading branch information
tk0miya authored Nov 11, 2017
2 parents f46c91b + 8b090c6 commit 63a5eaf
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 9 deletions.
1 change: 1 addition & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ Features added
* #4168: improve zh search with jieba
* HTML themes can set up default sidebars through ``theme.conf``
* #3160: html: Use ``<kdb>`` to represent ``:kbd:`` role
* #4212: autosummary: catch all exceptions when importing modules


Features removed
Expand Down
10 changes: 4 additions & 6 deletions sphinx/ext/autodoc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import sys
import inspect
import traceback
import warnings

from six import PY2, iterkeys, iteritems, itervalues, text_type, class_types, string_types

Expand All @@ -25,7 +24,7 @@
from docutils.statemachine import ViewList

import sphinx
from sphinx.ext.autodoc.importer import _MockImporter
from sphinx.ext.autodoc.importer import _MockImporter, import_module
from sphinx.ext.autodoc.inspector import format_annotation, formatargspec # to keep compatibility # NOQA
from sphinx.util import rpartition, force_decode
from sphinx.locale import _
Expand Down Expand Up @@ -392,10 +391,7 @@ def import_object(self):
import_hook = _MockImporter(self.env.config.autodoc_mock_imports)
try:
logger.debug('[autodoc] import %s', self.modname)
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=ImportWarning)
with logging.skip_warningiserror(not self.env.config.autodoc_warningiserror):
__import__(self.modname)
import_module(self.modname, self.env.config.autodoc_warningiserror)
parent = None
obj = self.module = sys.modules[self.modname]
logger.debug('[autodoc] => %r', obj)
Expand All @@ -420,6 +416,8 @@ def import_object(self):
if isinstance(e, SystemExit):
errmsg += ('; the module executes module level statement ' +
'and it might call sys.exit().')
elif isinstance(e, ImportError):
errmsg += '; the following exception was raised:\n%s' % e.args[0]
else:
errmsg += '; the following exception was raised:\n%s' % \
traceback.format_exc()
Expand Down
17 changes: 17 additions & 0 deletions sphinx/ext/autodoc/importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
"""

import sys
import traceback
import warnings
from types import FunctionType, MethodType, ModuleType

from sphinx.util import logging
Expand Down Expand Up @@ -116,3 +118,18 @@ def load_module(self, name):
sys.modules[name] = module
self.mocked_modules.append(name)
return module


def import_module(modname, warningiserror=False):
"""
Call __import__(modname), convert exceptions to ImportError
"""
try:
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=ImportWarning)
with logging.skip_warningiserror(not warningiserror):
return __import__(modname)
except BaseException:
# Importing modules may cause any side effects, including
# SystemExit, so we need to catch all errors.
raise ImportError(traceback.format_exc())
7 changes: 4 additions & 3 deletions sphinx/ext/autosummary/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
from sphinx.util import import_object, rst, logging
from sphinx.pycode import ModuleAnalyzer, PycodeError
from sphinx.ext.autodoc import Options
from sphinx.ext.autodoc.importer import import_module

if False:
# For type annotation
Expand Down Expand Up @@ -512,8 +513,7 @@ def _import_by_name(name):
modname = '.'.join(name_parts[:-1])
if modname:
try:
__import__(modname)
mod = sys.modules[modname]
mod = import_module(modname)
return getattr(mod, name_parts[-1]), mod, modname
except (ImportError, IndexError, AttributeError):
pass
Expand All @@ -525,9 +525,10 @@ def _import_by_name(name):
last_j = j
modname = '.'.join(name_parts[:j])
try:
__import__(modname)
import_module(modname)
except ImportError:
continue

if modname in sys.modules:
break

Expand Down
4 changes: 4 additions & 0 deletions tests/roots/test-ext-autosummary/autosummary_importfail.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import sys

# Fail module import in a catastrophic way
sys.exit(1)
5 changes: 5 additions & 0 deletions tests/roots/test-ext-autosummary/contents.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@

:autolink:`autosummary_dummy_module.Foo`

:autolink:`autosummary_importfail`

.. autosummary::
:toctree: generated

autosummary_dummy_module
autosummary_dummy_module.Foo
autosummary_importfail

0 comments on commit 63a5eaf

Please sign in to comment.