~ubuntu-branches/ubuntu/utopic/pyside/utopic

« back to all changes in this revision

Viewing changes to doc/inheritance_diagram.py

  • Committer: Bazaar Package Importer
  • Author(s): Didier Raboud
  • Date: 2011-02-18 18:01:00 UTC
  • mfrom: (1.2.3 upstream) (6.1.6 experimental)
  • Revision ID: james.westby@ubuntu.com-20110218180100-vaczjij7g08fzfme
Tags: 1.0.0~rc1-1
* New 1.0.0~rc1 upstream release
  - Bump the B-D chain versions:
    + apiextractor to 0.10.0-2~
    + generatorrunner to 0.6.6
    + shiboken to 1.0.0~rc1
* Update patches to ~rc1.
* debian/watch: update to handle Release Candidates too.
* Bump XS-Python-Version to >= 2.6.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
"""
 
1
# -*- coding: utf-8 -*-
 
2
r"""
2
3
    sphinx.ext.inheritance_diagram
3
4
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4
5
 
31
32
    The graph is inserted as a PNG+image map into HTML and a PDF in
32
33
    LaTeX.
33
34
 
34
 
    :copyright: Copyright 2007-2009 by the Sphinx team, see AUTHORS.
 
35
    :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
 
36
    :copyright: Copyright 2010-2011 by the PySide team.
35
37
    :license: BSD, see LICENSE for details.
36
38
"""
37
39
 
39
41
import re
40
42
import sys
41
43
import inspect
42
 
import subprocess
43
44
try:
44
45
    from hashlib import md5
45
46
except ImportError:
48
49
from docutils import nodes
49
50
from docutils.parsers.rst import directives
50
51
 
51
 
from sphinx.roles import xfileref_role
52
52
from sphinx.ext.graphviz import render_dot_html, render_dot_latex
53
53
from sphinx.util.compat import Directive
54
54
 
68
68
    from all the way to the root "object", and then is able to generate a
69
69
    graphviz dot graph from them.
70
70
    """
71
 
    def __init__(self, class_names, currmodule, show_builtins=False):
 
71
    def __init__(self, class_names, currmodule, show_builtins=False, parts=0):
72
72
        """
73
73
        *class_names* is a list of child classes to show bases from.
74
74
 
76
76
        in the graph.
77
77
        """
78
78
        self.class_names = class_names
79
 
        self.classes = self._import_classes(class_names, currmodule)
80
 
        self.all_classes = self._all_classes(self.classes)
81
 
        if len(self.all_classes) == 0:
 
79
        classes = self._import_classes(class_names, currmodule)
 
80
        self.class_info = self._class_info(classes, show_builtins, parts)
 
81
        if not self.class_info:
82
82
            raise InheritanceException('No classes found for '
83
83
                                       'inheritance diagram')
84
 
        self.show_builtins = show_builtins
85
84
 
86
85
    def _import_class_or_module(self, name, currmodule):
87
86
        """
89
88
        """
90
89
        try:
91
90
            path, base = class_sig_re.match(name).groups()
92
 
        except ValueError:
 
91
        except (AttributeError, ValueError):
93
92
            raise InheritanceException('Invalid class or module %r specified '
94
93
                                       'for inheritance diagram' % name)
95
94
 
98
97
 
99
98
        # two possibilities: either it is a module, then import it
100
99
        try:
101
 
            module = __import__(fullname)
 
100
            __import__(fullname)
102
101
            todoc = sys.modules[fullname]
103
102
        except ImportError:
104
 
            # else it is a class, then import the module
105
 
            if not path:
106
 
                if currmodule:
107
 
                    # try the current module
108
 
                    path = currmodule
109
 
                else:
110
 
                    raise InheritanceException(
111
 
                        'Could not import class %r specified for '
112
 
                        'inheritance diagram' % base)
113
103
            try:
114
 
                module = __import__(path)
115
 
                todoc = getattr(sys.modules[path], base)
 
104
                __import__(currmodule)
 
105
                todoc = sys.modules[currmodule]
 
106
                for attr in name.split('.'):
 
107
                    todoc = getattr(todoc, attr)
116
108
            except (ImportError, AttributeError):
117
109
                raise InheritanceException(
118
110
                    'Could not import class or module %r specified for '
119
 
                    'inheritance diagram' % (path + '.' + base))
 
111
                    'inheritance diagram' % (currmodule + '.' + name))
120
112
 
121
113
        # If a class, just return it
122
114
        if inspect.isclass(todoc):
131
123
                                   'not a class or module' % name)
132
124
 
133
125
    def _import_classes(self, class_names, currmodule):
134
 
        """
135
 
        Import a list of classes.
136
 
        """
 
126
        """Import a list of classes."""
137
127
        classes = []
138
128
        for name in class_names:
139
129
            classes.extend(self._import_class_or_module(name, currmodule))
140
130
        return classes
141
131
 
142
 
    def _all_classes(self, classes):
143
 
        """
144
 
        Return a list of all classes that are ancestors of *classes*.
 
132
    def _class_info(self, classes, show_builtins, parts):
 
133
        """Return name and bases for all classes that are ancestors of
 
134
        *classes*.
 
135
 
 
136
        *parts* gives the number of dotted name parts that is removed from the
 
137
        displayed node names.
145
138
        """
146
139
        all_classes = {}
 
140
        builtins = __builtins__.values()
147
141
 
148
142
        def recurse(cls):
149
 
            all_classes[cls] = None
150
 
            for c in cls.__bases__:
151
 
                if c not in all_classes and c.__name__ != "BaseWrapper":
152
 
                    recurse(c)
 
143
            if not show_builtins and cls in builtins:
 
144
                return
 
145
 
 
146
            nodename = self.class_name(cls, parts)
 
147
            fullname = self.class_name(cls, 0)
 
148
 
 
149
            baselist = []
 
150
            all_classes[cls] = (nodename, fullname, baselist)
 
151
            for base in cls.__bases__:
 
152
                if not show_builtins and base in builtins:
 
153
                    continue
 
154
                if  base.__name__ == "Object" and base.__module__ == "Shiboken":
 
155
                    continue
 
156
                baselist.append(self.class_name(base, parts))
 
157
                if base not in all_classes:
 
158
                    recurse(base)
153
159
 
154
160
        for cls in classes:
155
161
            recurse(cls)
156
162
 
157
 
        return all_classes.keys()
 
163
        return all_classes.values()
158
164
 
159
165
    def class_name(self, cls, parts=0):
160
 
        """
161
 
        Given a class object, return a fully-qualified name.  This
162
 
        works for things I've tested in matplotlib so far, but may not
163
 
        be completely general.
 
166
        """Given a class object, return a fully-qualified name.
 
167
 
 
168
        This works for things I've tested in matplotlib so far, but may not be
 
169
        completely general.
164
170
        """
165
171
        module = cls.__module__
166
172
        if module == '__builtin__':
176
182
        """
177
183
        Get all of the class names involved in the graph.
178
184
        """
179
 
        return [self.class_name(x) for x in self.all_classes]
 
185
        return [fullname for (_, fullname, _) in self.class_info]
180
186
 
181
187
    # These are the default attrs for graphviz
182
188
    default_graph_attrs = {
202
208
    def _format_graph_attrs(self, attrs):
203
209
        return ''.join(['%s=%s;\n' % x for x in attrs.items()])
204
210
 
205
 
    def generate_dot(self, name, parts=0, urls={}, env=None,
 
211
    def generate_dot(self, name, urls={}, env=None,
206
212
                     graph_attrs={}, node_attrs={}, edge_attrs={}):
207
213
        """
208
214
        Generate a graphviz dot graph from the classes that
230
236
        res.append('digraph %s {\n' % name)
231
237
        res.append(self._format_graph_attrs(g_attrs))
232
238
 
233
 
        for cls in self.all_classes:
234
 
            if not self.show_builtins and cls in __builtins__.values():
235
 
                continue
236
 
 
237
 
            name = self.class_name(cls, parts)
238
 
 
 
239
        for name, fullname, bases in self.class_info:
239
240
            # Write the node
240
241
            this_node_attrs = n_attrs.copy()
241
 
            url = urls.get(self.class_name(cls))
 
242
            url = urls.get(fullname)
242
243
            if url is not None:
243
244
                this_node_attrs['URL'] = '"%s"' % url
244
245
            res.append('  "%s" [%s];\n' %
245
246
                       (name, self._format_node_attrs(this_node_attrs)))
246
247
 
247
248
            # Write the edges
248
 
            for base in cls.__bases__:
249
 
                if base.__name__ == "BaseWrapper":
250
 
                    continue
251
 
                if not self.show_builtins and base in __builtins__.values():
252
 
                    continue
253
 
 
254
 
                base_name = self.class_name(base, parts)
 
249
            for base_name in bases:
255
250
                res.append('  "%s" -> "%s" [%s];\n' %
256
251
                           (base_name, name,
257
252
                            self._format_node_attrs(e_attrs)))
283
278
        node.document = self.state.document
284
279
        env = self.state.document.settings.env
285
280
        class_names = self.arguments[0].split()
 
281
        class_role = env.get_domain('py').role('class')
 
282
        # Store the original content for use as a hash
 
283
        node['parts'] = self.options.get('parts', 0)
 
284
        node['content'] = ', '.join(class_names)
286
285
 
287
286
        # Create a graph starting with the list of classes
288
287
        try:
289
 
            graph = InheritanceGraph(class_names, env.currmodule)
 
288
            graph = InheritanceGraph(
 
289
                class_names, env.temp_data.get('py:module'),
 
290
                parts=node['parts'])
290
291
        except InheritanceException, err:
291
292
            return [node.document.reporter.warning(err.args[0],
292
293
                                                   line=self.lineno)]
296
297
        # references to real URLs later.  These nodes will eventually be
297
298
        # removed from the doctree after we're done with them.
298
299
        for name in graph.get_all_class_names():
299
 
            refnodes, x = xfileref_role(
 
300
            refnodes, x = class_role(
300
301
                'class', ':class:`%s`' % name, name, 0, self.state)
301
302
            node.extend(refnodes)
302
303
        # Store the graph object so we can use it to generate the
303
304
        # dot file later
304
305
        node['graph'] = graph
305
 
        # Store the original content for use as a hash
306
 
        node['parts'] = self.options.get('parts', 0)
307
 
        node['content'] = ', '.join(class_names)
308
306
        return [node]
309
307
 
310
308
 
318
316
    image map.
319
317
    """
320
318
    graph = node['graph']
321
 
    parts = node['parts']
322
319
 
323
320
    graph_hash = get_graph_hash(node)
324
321
    name = 'inheritance%s' % graph_hash
331
328
        elif child.get('refid') is not None:
332
329
            urls[child['reftitle']] = '#' + child.get('refid')
333
330
 
334
 
    dotcode = graph.generate_dot(name, parts, urls, env=self.builder.env)
 
331
    dotcode = graph.generate_dot(name, urls, env=self.builder.env)
335
332
    render_dot_html(self, node, dotcode, [], 'inheritance', 'inheritance',
336
333
                    alt='Inheritance diagram of ' + node['content'])
337
334
    raise nodes.SkipNode
342
339
    Output the graph for LaTeX.  This will insert a PDF.
343
340
    """
344
341
    graph = node['graph']
345
 
    parts = node['parts']
346
342
 
347
343
    graph_hash = get_graph_hash(node)
348
344
    name = 'inheritance%s' % graph_hash
349
345
 
350
 
    dotcode = graph.generate_dot(name, parts, env=self.builder.env,
 
346
    dotcode = graph.generate_dot(name, env=self.builder.env,
351
347
                                 graph_attrs={'size': '"6.0,6.0"'})
352
348
    render_dot_latex(self, node, dotcode, [], 'inheritance')
353
349
    raise nodes.SkipNode
363
359
        inheritance_diagram,
364
360
        latex=(latex_visit_inheritance_diagram, None),
365
361
        html=(html_visit_inheritance_diagram, None),
366
 
        text=(skip, None))
 
362
        text=(skip, None),
 
363
        man=(skip, None))
367
364
    app.add_directive('inheritance-diagram', InheritanceDiagram)
368
365
    app.add_config_value('inheritance_graph_attrs', {}, False),
369
366
    app.add_config_value('inheritance_node_attrs', {}, False),