Fix bug 638 - "Documentation for phonon doesn't show class inheritance diagrams."
This commit is contained in:
parent
f5a70fbbc4
commit
dae317b831
3 changed files with 63 additions and 65 deletions
|
|
@ -17,6 +17,7 @@ import sys, os
|
||||||
# add these directories to sys.path here. If the directory is relative to the
|
# add these directories to sys.path here. If the directory is relative to the
|
||||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||||
sys.path.append('@CMAKE_CURRENT_SOURCE_DIR@')
|
sys.path.append('@CMAKE_CURRENT_SOURCE_DIR@')
|
||||||
|
sys.path.append('@pyside_BINARY_DIR@')
|
||||||
|
|
||||||
# -- General configuration -----------------------------------------------------
|
# -- General configuration -----------------------------------------------------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
"""
|
# -*- coding: utf-8 -*-
|
||||||
|
r"""
|
||||||
sphinx.ext.inheritance_diagram
|
sphinx.ext.inheritance_diagram
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
@ -31,7 +32,8 @@
|
||||||
The graph is inserted as a PNG+image map into HTML and a PDF in
|
The graph is inserted as a PNG+image map into HTML and a PDF in
|
||||||
LaTeX.
|
LaTeX.
|
||||||
|
|
||||||
:copyright: Copyright 2007-2009 by the Sphinx team, see AUTHORS.
|
:copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
|
||||||
|
:copyright: Copyright 2010-2011 by the PySide team.
|
||||||
:license: BSD, see LICENSE for details.
|
:license: BSD, see LICENSE for details.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
@ -39,7 +41,6 @@ import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
import inspect
|
import inspect
|
||||||
import subprocess
|
|
||||||
try:
|
try:
|
||||||
from hashlib import md5
|
from hashlib import md5
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
|
@ -48,7 +49,6 @@ except ImportError:
|
||||||
from docutils import nodes
|
from docutils import nodes
|
||||||
from docutils.parsers.rst import directives
|
from docutils.parsers.rst import directives
|
||||||
|
|
||||||
from sphinx.roles import xfileref_role
|
|
||||||
from sphinx.ext.graphviz import render_dot_html, render_dot_latex
|
from sphinx.ext.graphviz import render_dot_html, render_dot_latex
|
||||||
from sphinx.util.compat import Directive
|
from sphinx.util.compat import Directive
|
||||||
|
|
||||||
|
|
@ -68,7 +68,7 @@ class InheritanceGraph(object):
|
||||||
from all the way to the root "object", and then is able to generate a
|
from all the way to the root "object", and then is able to generate a
|
||||||
graphviz dot graph from them.
|
graphviz dot graph from them.
|
||||||
"""
|
"""
|
||||||
def __init__(self, class_names, currmodule, show_builtins=False):
|
def __init__(self, class_names, currmodule, show_builtins=False, parts=0):
|
||||||
"""
|
"""
|
||||||
*class_names* is a list of child classes to show bases from.
|
*class_names* is a list of child classes to show bases from.
|
||||||
|
|
||||||
|
|
@ -76,12 +76,11 @@ class InheritanceGraph(object):
|
||||||
in the graph.
|
in the graph.
|
||||||
"""
|
"""
|
||||||
self.class_names = class_names
|
self.class_names = class_names
|
||||||
self.classes = self._import_classes(class_names, currmodule)
|
classes = self._import_classes(class_names, currmodule)
|
||||||
self.all_classes = self._all_classes(self.classes)
|
self.class_info = self._class_info(classes, show_builtins, parts)
|
||||||
if len(self.all_classes) == 0:
|
if not self.class_info:
|
||||||
raise InheritanceException('No classes found for '
|
raise InheritanceException('No classes found for '
|
||||||
'inheritance diagram')
|
'inheritance diagram')
|
||||||
self.show_builtins = show_builtins
|
|
||||||
|
|
||||||
def _import_class_or_module(self, name, currmodule):
|
def _import_class_or_module(self, name, currmodule):
|
||||||
"""
|
"""
|
||||||
|
|
@ -89,7 +88,7 @@ class InheritanceGraph(object):
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
path, base = class_sig_re.match(name).groups()
|
path, base = class_sig_re.match(name).groups()
|
||||||
except ValueError:
|
except (AttributeError, ValueError):
|
||||||
raise InheritanceException('Invalid class or module %r specified '
|
raise InheritanceException('Invalid class or module %r specified '
|
||||||
'for inheritance diagram' % name)
|
'for inheritance diagram' % name)
|
||||||
|
|
||||||
|
|
@ -98,25 +97,18 @@ class InheritanceGraph(object):
|
||||||
|
|
||||||
# two possibilities: either it is a module, then import it
|
# two possibilities: either it is a module, then import it
|
||||||
try:
|
try:
|
||||||
module = __import__(fullname)
|
__import__(fullname)
|
||||||
todoc = sys.modules[fullname]
|
todoc = sys.modules[fullname]
|
||||||
except ImportError:
|
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:
|
try:
|
||||||
module = __import__(path)
|
__import__(currmodule)
|
||||||
todoc = getattr(sys.modules[path], base)
|
todoc = sys.modules[currmodule]
|
||||||
|
for attr in name.split('.'):
|
||||||
|
todoc = getattr(todoc, attr)
|
||||||
except (ImportError, AttributeError):
|
except (ImportError, AttributeError):
|
||||||
raise InheritanceException(
|
raise InheritanceException(
|
||||||
'Could not import class or module %r specified for '
|
'Could not import class or module %r specified for '
|
||||||
'inheritance diagram' % (path + '.' + base))
|
'inheritance diagram' % (currmodule + '.' + name))
|
||||||
|
|
||||||
# If a class, just return it
|
# If a class, just return it
|
||||||
if inspect.isclass(todoc):
|
if inspect.isclass(todoc):
|
||||||
|
|
@ -131,36 +123,50 @@ class InheritanceGraph(object):
|
||||||
'not a class or module' % name)
|
'not a class or module' % name)
|
||||||
|
|
||||||
def _import_classes(self, class_names, currmodule):
|
def _import_classes(self, class_names, currmodule):
|
||||||
"""
|
"""Import a list of classes."""
|
||||||
Import a list of classes.
|
|
||||||
"""
|
|
||||||
classes = []
|
classes = []
|
||||||
for name in class_names:
|
for name in class_names:
|
||||||
classes.extend(self._import_class_or_module(name, currmodule))
|
classes.extend(self._import_class_or_module(name, currmodule))
|
||||||
return classes
|
return classes
|
||||||
|
|
||||||
def _all_classes(self, classes):
|
def _class_info(self, classes, show_builtins, parts):
|
||||||
"""
|
"""Return name and bases for all classes that are ancestors of
|
||||||
Return a list of all classes that are ancestors of *classes*.
|
*classes*.
|
||||||
|
|
||||||
|
*parts* gives the number of dotted name parts that is removed from the
|
||||||
|
displayed node names.
|
||||||
"""
|
"""
|
||||||
all_classes = {}
|
all_classes = {}
|
||||||
|
builtins = __builtins__.values()
|
||||||
|
|
||||||
def recurse(cls):
|
def recurse(cls):
|
||||||
all_classes[cls] = None
|
if not show_builtins and cls in builtins:
|
||||||
for c in cls.__bases__:
|
return
|
||||||
if c not in all_classes and not (c.__name__ == "Object" and c.__module__ == "Shiboken"):
|
|
||||||
recurse(c)
|
nodename = self.class_name(cls, parts)
|
||||||
|
fullname = self.class_name(cls, 0)
|
||||||
|
|
||||||
|
baselist = []
|
||||||
|
all_classes[cls] = (nodename, fullname, baselist)
|
||||||
|
for base in cls.__bases__:
|
||||||
|
if not show_builtins and base in builtins:
|
||||||
|
continue
|
||||||
|
if base.__name__ == "Object" and base.__module__ == "Shiboken":
|
||||||
|
continue
|
||||||
|
baselist.append(self.class_name(base, parts))
|
||||||
|
if base not in all_classes:
|
||||||
|
recurse(base)
|
||||||
|
|
||||||
for cls in classes:
|
for cls in classes:
|
||||||
recurse(cls)
|
recurse(cls)
|
||||||
|
|
||||||
return all_classes.keys()
|
return all_classes.values()
|
||||||
|
|
||||||
def class_name(self, cls, parts=0):
|
def class_name(self, cls, parts=0):
|
||||||
"""
|
"""Given a class object, return a fully-qualified name.
|
||||||
Given a class object, return a fully-qualified name. This
|
|
||||||
works for things I've tested in matplotlib so far, but may not
|
This works for things I've tested in matplotlib so far, but may not be
|
||||||
be completely general.
|
completely general.
|
||||||
"""
|
"""
|
||||||
module = cls.__module__
|
module = cls.__module__
|
||||||
if module == '__builtin__':
|
if module == '__builtin__':
|
||||||
|
|
@ -176,7 +182,7 @@ class InheritanceGraph(object):
|
||||||
"""
|
"""
|
||||||
Get all of the class names involved in the graph.
|
Get all of the class names involved in the graph.
|
||||||
"""
|
"""
|
||||||
return [self.class_name(x) for x in self.all_classes]
|
return [fullname for (_, fullname, _) in self.class_info]
|
||||||
|
|
||||||
# These are the default attrs for graphviz
|
# These are the default attrs for graphviz
|
||||||
default_graph_attrs = {
|
default_graph_attrs = {
|
||||||
|
|
@ -202,7 +208,7 @@ class InheritanceGraph(object):
|
||||||
def _format_graph_attrs(self, attrs):
|
def _format_graph_attrs(self, attrs):
|
||||||
return ''.join(['%s=%s;\n' % x for x in attrs.items()])
|
return ''.join(['%s=%s;\n' % x for x in attrs.items()])
|
||||||
|
|
||||||
def generate_dot(self, name, parts=0, urls={}, env=None,
|
def generate_dot(self, name, urls={}, env=None,
|
||||||
graph_attrs={}, node_attrs={}, edge_attrs={}):
|
graph_attrs={}, node_attrs={}, edge_attrs={}):
|
||||||
"""
|
"""
|
||||||
Generate a graphviz dot graph from the classes that
|
Generate a graphviz dot graph from the classes that
|
||||||
|
|
@ -230,28 +236,17 @@ class InheritanceGraph(object):
|
||||||
res.append('digraph %s {\n' % name)
|
res.append('digraph %s {\n' % name)
|
||||||
res.append(self._format_graph_attrs(g_attrs))
|
res.append(self._format_graph_attrs(g_attrs))
|
||||||
|
|
||||||
for cls in self.all_classes:
|
for name, fullname, bases in self.class_info:
|
||||||
if not self.show_builtins and cls in __builtins__.values():
|
|
||||||
continue
|
|
||||||
|
|
||||||
name = self.class_name(cls, parts)
|
|
||||||
|
|
||||||
# Write the node
|
# Write the node
|
||||||
this_node_attrs = n_attrs.copy()
|
this_node_attrs = n_attrs.copy()
|
||||||
url = urls.get(self.class_name(cls))
|
url = urls.get(fullname)
|
||||||
if url is not None:
|
if url is not None:
|
||||||
this_node_attrs['URL'] = '"%s"' % url
|
this_node_attrs['URL'] = '"%s"' % url
|
||||||
res.append(' "%s" [%s];\n' %
|
res.append(' "%s" [%s];\n' %
|
||||||
(name, self._format_node_attrs(this_node_attrs)))
|
(name, self._format_node_attrs(this_node_attrs)))
|
||||||
|
|
||||||
# Write the edges
|
# Write the edges
|
||||||
for base in cls.__bases__:
|
for base_name in bases:
|
||||||
if base.__name__ == "Object" and base.__module__ == "Shiboken":
|
|
||||||
continue
|
|
||||||
if not self.show_builtins and base in __builtins__.values():
|
|
||||||
continue
|
|
||||||
|
|
||||||
base_name = self.class_name(base, parts)
|
|
||||||
res.append(' "%s" -> "%s" [%s];\n' %
|
res.append(' "%s" -> "%s" [%s];\n' %
|
||||||
(base_name, name,
|
(base_name, name,
|
||||||
self._format_node_attrs(e_attrs)))
|
self._format_node_attrs(e_attrs)))
|
||||||
|
|
@ -283,10 +278,16 @@ class InheritanceDiagram(Directive):
|
||||||
node.document = self.state.document
|
node.document = self.state.document
|
||||||
env = self.state.document.settings.env
|
env = self.state.document.settings.env
|
||||||
class_names = self.arguments[0].split()
|
class_names = self.arguments[0].split()
|
||||||
|
class_role = env.get_domain('py').role('class')
|
||||||
|
# Store the original content for use as a hash
|
||||||
|
node['parts'] = self.options.get('parts', 0)
|
||||||
|
node['content'] = ', '.join(class_names)
|
||||||
|
|
||||||
# Create a graph starting with the list of classes
|
# Create a graph starting with the list of classes
|
||||||
try:
|
try:
|
||||||
graph = InheritanceGraph(class_names, env.currmodule)
|
graph = InheritanceGraph(
|
||||||
|
class_names, env.temp_data.get('py:module'),
|
||||||
|
parts=node['parts'])
|
||||||
except InheritanceException, err:
|
except InheritanceException, err:
|
||||||
return [node.document.reporter.warning(err.args[0],
|
return [node.document.reporter.warning(err.args[0],
|
||||||
line=self.lineno)]
|
line=self.lineno)]
|
||||||
|
|
@ -296,15 +297,12 @@ class InheritanceDiagram(Directive):
|
||||||
# references to real URLs later. These nodes will eventually be
|
# references to real URLs later. These nodes will eventually be
|
||||||
# removed from the doctree after we're done with them.
|
# removed from the doctree after we're done with them.
|
||||||
for name in graph.get_all_class_names():
|
for name in graph.get_all_class_names():
|
||||||
refnodes, x = xfileref_role(
|
refnodes, x = class_role(
|
||||||
'class', ':class:`%s`' % name, name, 0, self.state)
|
'class', ':class:`%s`' % name, name, 0, self.state)
|
||||||
node.extend(refnodes)
|
node.extend(refnodes)
|
||||||
# Store the graph object so we can use it to generate the
|
# Store the graph object so we can use it to generate the
|
||||||
# dot file later
|
# dot file later
|
||||||
node['graph'] = graph
|
node['graph'] = graph
|
||||||
# Store the original content for use as a hash
|
|
||||||
node['parts'] = self.options.get('parts', 0)
|
|
||||||
node['content'] = ', '.join(class_names)
|
|
||||||
return [node]
|
return [node]
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -318,7 +316,6 @@ def html_visit_inheritance_diagram(self, node):
|
||||||
image map.
|
image map.
|
||||||
"""
|
"""
|
||||||
graph = node['graph']
|
graph = node['graph']
|
||||||
parts = node['parts']
|
|
||||||
|
|
||||||
graph_hash = get_graph_hash(node)
|
graph_hash = get_graph_hash(node)
|
||||||
name = 'inheritance%s' % graph_hash
|
name = 'inheritance%s' % graph_hash
|
||||||
|
|
@ -331,7 +328,7 @@ def html_visit_inheritance_diagram(self, node):
|
||||||
elif child.get('refid') is not None:
|
elif child.get('refid') is not None:
|
||||||
urls[child['reftitle']] = '#' + child.get('refid')
|
urls[child['reftitle']] = '#' + child.get('refid')
|
||||||
|
|
||||||
dotcode = graph.generate_dot(name, parts, urls, env=self.builder.env)
|
dotcode = graph.generate_dot(name, urls, env=self.builder.env)
|
||||||
render_dot_html(self, node, dotcode, [], 'inheritance', 'inheritance',
|
render_dot_html(self, node, dotcode, [], 'inheritance', 'inheritance',
|
||||||
alt='Inheritance diagram of ' + node['content'])
|
alt='Inheritance diagram of ' + node['content'])
|
||||||
raise nodes.SkipNode
|
raise nodes.SkipNode
|
||||||
|
|
@ -342,12 +339,11 @@ def latex_visit_inheritance_diagram(self, node):
|
||||||
Output the graph for LaTeX. This will insert a PDF.
|
Output the graph for LaTeX. This will insert a PDF.
|
||||||
"""
|
"""
|
||||||
graph = node['graph']
|
graph = node['graph']
|
||||||
parts = node['parts']
|
|
||||||
|
|
||||||
graph_hash = get_graph_hash(node)
|
graph_hash = get_graph_hash(node)
|
||||||
name = 'inheritance%s' % graph_hash
|
name = 'inheritance%s' % graph_hash
|
||||||
|
|
||||||
dotcode = graph.generate_dot(name, parts, env=self.builder.env,
|
dotcode = graph.generate_dot(name, env=self.builder.env,
|
||||||
graph_attrs={'size': '"6.0,6.0"'})
|
graph_attrs={'size': '"6.0,6.0"'})
|
||||||
render_dot_latex(self, node, dotcode, [], 'inheritance')
|
render_dot_latex(self, node, dotcode, [], 'inheritance')
|
||||||
raise nodes.SkipNode
|
raise nodes.SkipNode
|
||||||
|
|
@ -363,7 +359,8 @@ def setup(app):
|
||||||
inheritance_diagram,
|
inheritance_diagram,
|
||||||
latex=(latex_visit_inheritance_diagram, None),
|
latex=(latex_visit_inheritance_diagram, None),
|
||||||
html=(html_visit_inheritance_diagram, None),
|
html=(html_visit_inheritance_diagram, None),
|
||||||
text=(skip, None))
|
text=(skip, None),
|
||||||
|
man=(skip, None))
|
||||||
app.add_directive('inheritance-diagram', InheritanceDiagram)
|
app.add_directive('inheritance-diagram', InheritanceDiagram)
|
||||||
app.add_config_value('inheritance_graph_attrs', {}, False),
|
app.add_config_value('inheritance_graph_attrs', {}, False),
|
||||||
app.add_config_value('inheritance_node_attrs', {}, False),
|
app.add_config_value('inheritance_node_attrs', {}, False),
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ class Bug617(unittest.TestCase):
|
||||||
|
|
||||||
def testOutOfBounds(self):
|
def testOutOfBounds(self):
|
||||||
e = MyEvent()
|
e = MyEvent()
|
||||||
self.assertEqual(repr(e.type()), '<enum-item Type.#out of bounds# (999)>')
|
self.assertEqual(repr(e.type()), '<enum-item PySide.QtCore.QEvent.Type.#out of bounds# (999)>')
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue