inheritance_diagram: Move _import_class_or_module() method to function

This commit is contained in:
Takeshi KOMIYA
2016-11-22 00:00:50 +09:00
parent 43197de299
commit 9676e79c1c
4 changed files with 99 additions and 47 deletions

View File

@@ -63,6 +63,52 @@ class_sig_re = re.compile(r'''^([\w.]*\.)? # module names
''', re.VERBOSE)
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)
fullname = (path or '') + base
path = (path and path.rstrip('.') or '')
# 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))
# If a class, just return it
if inspect.isclass(todoc):
return [todoc]
elif inspect.ismodule(todoc):
classes = []
for cls in todoc.__dict__.values():
if inspect.isclass(cls) and cls.__module__ == todoc.__name__:
classes.append(cls)
return classes
raise InheritanceException('%r specified for inheritance diagram is '
'not a class or module' % name)
class InheritanceException(Exception):
pass
@@ -88,56 +134,11 @@ class InheritanceGraph(object):
raise InheritanceException('No classes found for '
'inheritance diagram')
def _import_class_or_module(self, 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)
fullname = (path or '') + base
path = (path and path.rstrip('.') or '')
# 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))
# If a class, just return it
if inspect.isclass(todoc):
return [todoc]
elif inspect.ismodule(todoc):
classes = []
for cls in todoc.__dict__.values():
if inspect.isclass(cls) and cls.__module__ == todoc.__name__:
classes.append(cls)
return classes
raise InheritanceException('%r specified for inheritance diagram is '
'not a class or module' % name)
def _import_classes(self, class_names, currmodule):
"""Import a list of classes."""
classes = []
for name in class_names:
classes.extend(self._import_class_or_module(name, currmodule))
classes.extend(import_classes(name, currmodule))
return classes
def _class_info(self, classes, show_builtins, private_bases, parts):

View File

@@ -0,0 +1 @@
# example.py

View File

@@ -0,0 +1,5 @@
# example.sphinx
class DummyClass(object):
pass

View File

@@ -9,9 +9,54 @@
:license: BSD, see LICENSE for details.
"""
from util import with_app
import sys
from util import with_app, rootdir, raises
from sphinx.ext.inheritance_diagram import InheritanceException, import_classes
@with_app('html', testroot='ext-inheritance_diagram')
def test_inheritance_diagram_html(app, status, warning):
app.builder.build_all()
def test_import_classes():
from sphinx.application import Sphinx, TemplateBridge
try:
sys.path.append(rootdir / 'roots/test-ext-inheritance_diagram')
# got exception for unknown class or module
raises(InheritanceException, import_classes, 'unknown', None)
raises(InheritanceException, import_classes, 'unknown.Unknown', None)
# a module having no classes
classes = import_classes('sphinx', None)
assert classes == []
classes = import_classes('sphinx', 'foo')
assert classes == []
# all of classes in the module
classes = import_classes('sphinx.application', None)
assert set(classes) == set([Sphinx, TemplateBridge])
# specified class in the module
classes = import_classes('sphinx.application.Sphinx', None)
assert classes == [Sphinx]
# specified class in current module
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')
# 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
classes = import_classes('sphinx', 'example')
assert classes == []
finally:
sys.path.pop()