Fix #3164: Change search order of `sphinx.ext.inheritance_diagram`

This commit is contained in:
Takeshi KOMIYA
2016-11-23 00:50:02 +09:00
parent 9676e79c1c
commit 52f54a6379
3 changed files with 51 additions and 42 deletions
+1
View File
@@ -15,6 +15,7 @@ Bugs fixed
* #3093: gettext build broken on image node under ``note`` directive.
* imgmath: crashes on showing error messages if image generation failed
* #3117: LaTeX writer crashes if admonition is placed before first section title
* #3164: Change search order of ``sphinx.ext.inheritance_diagram``
Release 1.4.8 (released Oct 1, 2016)
====================================
+43 -37
View File
@@ -58,51 +58,57 @@ from sphinx.util import force_decode
from sphinx.util.compat import Directive
class_sig_re = re.compile(r'''^([\w.]*\.)? # module names
(\w+) \s* $ # class/final module name
''', re.VERBOSE)
module_sig_re = re.compile(r'''^(?:([\w.]*)\.)? # module names
(\w+) \s* $ # class/final module name
''', re.VERBOSE)
def try_import(objname):
"""Import a object or module using *name* and *currentmodule*.
*name* should be a relative name from *currentmodule* or
a fully-qualified name.
Returns imported object or module. If failed, returns None value.
"""
try:
__import__(objname)
return sys.modules.get(objname)
except ImportError:
modname, attrname = module_sig_re.match(objname).groups()
if modname is None:
return None
try:
__import__(modname)
return getattr(sys.modules.get(modname), attrname, None)
except ImportError:
return None
def import_classes(name, currmodule):
"""Import a class using its fully-qualified *name*."""
try:
path, base = class_sig_re.match(name).groups()
except (AttributeError, ValueError):
raise InheritanceException('Invalid class or module %r specified '
'for inheritance diagram' % name)
target = None
fullname = (path or '') + base
path = (path and path.rstrip('.') or '')
# import class or module using currmodule
if currmodule:
target = try_import(currmodule + '.' + name)
# two possibilities: either it is a module, then import it
try:
__import__(fullname)
todoc = sys.modules[fullname]
except ImportError:
# else it is a class, then import the module
if not path:
if currmodule:
# try the current module
path = currmodule
else:
raise InheritanceException(
'Could not import class %r specified for '
'inheritance diagram' % base)
try:
__import__(path)
todoc = getattr(sys.modules[path], base)
except (ImportError, AttributeError):
raise InheritanceException(
'Could not import class or module %r specified for '
'inheritance diagram' % (path + '.' + base))
# import class or module without currmodule
if target is None:
target = try_import(name)
# If a class, just return it
if inspect.isclass(todoc):
return [todoc]
elif inspect.ismodule(todoc):
if target is None:
raise InheritanceException(
'Could not import class or module %r specified for '
'inheritance diagram' % name)
if inspect.isclass(target):
# If imported object is a class, just return it
return [target]
elif inspect.ismodule(target):
# If imported object is a module, return classes defined on it
classes = []
for cls in todoc.__dict__.values():
if inspect.isclass(cls) and cls.__module__ == todoc.__name__:
for cls in target.__dict__.values():
if inspect.isclass(cls) and cls.__module__ == target.__name__:
classes.append(cls)
return classes
raise InheritanceException('%r specified for inheritance diagram is '
+7 -5
View File
@@ -21,9 +21,11 @@ def test_inheritance_diagram_html(app, status, warning):
def test_import_classes():
from sphinx.application import Sphinx, TemplateBridge
from sphinx.util.i18n import CatalogInfo
try:
sys.path.append(rootdir / 'roots/test-ext-inheritance_diagram')
from example.sphinx import DummyClass
# got exception for unknown class or module
raises(InheritanceException, import_classes, 'unknown', None)
@@ -48,15 +50,15 @@ def test_import_classes():
classes = import_classes('Sphinx', 'sphinx.application')
assert classes == [Sphinx]
# ignore current module if name include the module name
raises(InheritanceException, import_classes, 'i18n.CatalogInfo', 'sphinx.util')
# relative module name to current module
classes = import_classes('i18n.CatalogInfo', 'sphinx.util')
assert classes == [CatalogInfo]
# got exception for functions
raises(InheritanceException, import_classes, 'encode_uri', 'sphinx.util')
# try to load example.sphinx, but inheritance_diagram imports sphinx instead
# refs: #3164
# import submodule on current module (refs: #3164)
classes = import_classes('sphinx', 'example')
assert classes == []
assert classes == [DummyClass]
finally:
sys.path.pop()