Merge pull request #6106 from tk0miya/refactor_import_object

refactor: import_object() allows to import nested objects (ex. nested class)
This commit is contained in:
Takeshi KOMIYA 2019-02-27 23:34:09 +09:00 committed by GitHub
commit a7b1c08487
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 41 additions and 17 deletions

View File

@ -603,22 +603,26 @@ class PeekableIterator:
def import_object(objname, source=None):
# type: (str, str) -> Any
"""Import python object by qualname."""
try:
module, name = objname.rsplit('.', 1)
except ValueError as err:
raise ExtensionError('Invalid full object name %s' % objname +
(source and ' (needed for %s)' % source or ''),
err)
try:
return getattr(__import__(module, None, None, [name]), name)
except ImportError as err:
raise ExtensionError('Could not import %s' % module +
(source and ' (needed for %s)' % source or ''),
err)
except AttributeError as err:
raise ExtensionError('Could not find %s' % objname +
(source and ' (needed for %s)' % source or ''),
err)
objpath = objname.split('.')
modname = objpath.pop(0)
obj = __import__(modname)
for name in objpath:
modname += '.' + name
try:
obj = getattr(obj, name)
except AttributeError:
__import__(modname)
obj = getattr(obj, name)
return obj
except (AttributeError, ImportError) as exc:
if source:
raise ExtensionError('Could not import %s (needed for %s)' %
(objname, source), exc)
else:
raise ExtensionError('Could not import %s' % objname, exc)
def encode_uri(uri):

View File

@ -15,11 +15,11 @@ import pytest
from mock import patch
import sphinx
from sphinx.errors import PycodeError
from sphinx.errors import ExtensionError, PycodeError
from sphinx.testing.util import strip_escseq
from sphinx.util import (
SkipProgressMessage, display_chunk, encode_uri, ensuredir, get_module_source,
parselinenos, progress_message, status_iterator, xmlname_checker
import_object, parselinenos, progress_message, status_iterator, xmlname_checker
)
from sphinx.util import logging
@ -71,6 +71,26 @@ def test_get_module_source():
get_module_source('itertools')
def test_import_object():
module = import_object('sphinx')
assert module.__name__ == 'sphinx'
module = import_object('sphinx.application')
assert module.__name__ == 'sphinx.application'
obj = import_object('sphinx.application.Sphinx')
assert obj.__name__ == 'Sphinx'
with pytest.raises(ExtensionError) as exc:
import_object('sphinx.unknown_module')
assert exc.value.args[0] == 'Could not import sphinx.unknown_module'
with pytest.raises(ExtensionError) as exc:
import_object('sphinx.unknown_module', 'my extension')
assert exc.value.args[0] == ('Could not import sphinx.unknown_module '
'(needed for my extension)')
@pytest.mark.sphinx('dummy')
@patch('sphinx.util.console._tw', 40) # terminal width = 40
def test_status_iterator(app, status, warning):