]> git.llucax.com Git - z.facultad/75.00/informe.git/blob - ext/graphviz.py
Actualizar extensión aafig a 0.2
[z.facultad/75.00/informe.git] / ext / graphviz.py
1 # -*- coding: utf-8 -*-
2 """
3     sphinx.ext.graphviz
4     ~~~~~~~~~~~~~~~~~~~
5
6     Allow graphviz-formatted graphs to be included in Sphinx-generated
7     documents inline.
8
9     :copyright: Copyright 2007-2009 by the Sphinx team, see AUTHORS.
10     :license: BSD, see LICENSE for details.
11 """
12
13 import os
14 import re
15 import sys
16 import posixpath
17 from os import path
18 from subprocess import Popen, PIPE
19 try:
20     from hashlib import sha1 as sha
21 except ImportError:
22     from sha import sha
23
24 from docutils import nodes
25
26 from sphinx.errors import SphinxError
27 from sphinx.util import ensuredir
28 from sphinx.util.compat import Directive
29
30
31 mapname_re = re.compile(r'<map id="(.*?)"')
32
33
34 class GraphvizError(SphinxError):
35     category = 'Graphviz error'
36
37
38 class graphviz(nodes.General, nodes.Element):
39     pass
40
41
42 class Graphviz(Directive):
43     """
44     Directive to insert arbitrary dot markup.
45     """
46     has_content = True
47     required_arguments = 0
48     optional_arguments = 0
49     final_argument_whitespace = False
50     option_spec = {}
51
52     def run(self):
53         node = graphviz()
54         node['code'] = '\n'.join(self.content)
55         node['options'] = []
56         return [node]
57
58
59 class GraphvizSimple(Directive):
60     """
61     Directive to insert arbitrary dot markup.
62     """
63     has_content = True
64     required_arguments = 1
65     optional_arguments = 0
66     final_argument_whitespace = False
67     option_spec = {}
68
69     def run(self):
70         node = graphviz()
71         node['code'] = '%s %s {\n%s\n}\n' % \
72                        (self.name, self.arguments[0], '\n'.join(self.content))
73         node['options'] = []
74         return [node]
75
76
77 def render_dot(self, code, options, format, prefix='graphviz'):
78     """
79     Render graphviz code into a PNG or PDF output file.
80     """
81     hashkey = code.encode('utf-8') + str(options) + \
82               str(self.builder.config.graphviz_dot_args)
83     fname = '%s-%s.%s' % (prefix, sha(hashkey).hexdigest(), format)
84     if hasattr(self.builder, 'imgpath'):
85         # HTML
86         relfn = posixpath.join(self.builder.imgpath, fname)
87         outfn = path.join(self.builder.outdir, '_images', fname)
88     else:
89         # LaTeX
90         relfn = fname
91         outfn = path.join(self.builder.outdir, fname)
92
93     if path.isfile(outfn):
94         return relfn, outfn
95
96     if hasattr(self.builder, '_graphviz_warned_dot') or \
97        hasattr(self.builder, '_graphviz_warned_ps2pdf'):
98         return None
99
100     ensuredir(path.dirname(outfn))
101
102     dot_args = [self.builder.config.graphviz_dot]
103     dot_args.extend(self.builder.config.graphviz_dot_args)
104     dot_args.extend(options)
105     dot_args.extend(['-T' + format, '-o' + outfn])
106     if format == 'png':
107         dot_args.extend(['-Tcmapx', '-o%s.map' % outfn])
108     try:
109         p = Popen(dot_args, stdout=PIPE, stdin=PIPE, stderr=PIPE)
110     except OSError, err:
111         if err.errno != 2:   # No such file or directory
112             raise
113         self.builder.warn('dot command %r cannot be run (needed for graphviz '
114                           'output), check the graphviz_dot setting' %
115                           self.builder.config.graphviz_dot)
116         self.builder._graphviz_warned_dot = True
117         return None
118     # graphviz expects UTF-8 by default
119     if isinstance(code, unicode):
120         code = code.encode('utf-8')
121     stdout, stderr = p.communicate(code)
122     if p.returncode != 0:
123         raise GraphvizError('dot exited with error:\n[stderr]\n%s\n'
124                             '[stdout]\n%s' % (stderr, stdout))
125     return relfn, outfn
126
127
128 def render_dot_html(self, node, code, options, prefix='graphviz', imgcls=None):
129     try:
130         fname, outfn = render_dot(self, code, options, 'png', prefix)
131     except GraphvizError, exc:
132         self.builder.warn('dot code %r: ' % code + str(exc))
133         raise nodes.SkipNode
134
135     self.body.append(self.starttag(node, 'p', CLASS='graphviz'))
136     if fname is None:
137         self.body.append(self.encode(code))
138     else:
139         mapfile = open(outfn + '.map', 'rb')
140         try:
141             imgmap = mapfile.readlines()
142         finally:
143             mapfile.close()
144         imgcss = imgcls and 'class="%s"' % imgcls or ''
145         if len(imgmap) == 2:
146             # nothing in image map (the lines are <map> and </map>)
147             self.body.append('<img src="%s" alt="%s" %s/>\n' %
148                              (fname, self.encode(code).strip(), imgcss))
149         else:
150             # has a map: get the name of the map and connect the parts
151             mapname = mapname_re.match(imgmap[0]).group(1)
152             self.body.append('<img src="%s" alt="%s" usemap="#%s" %s/>\n' %
153                              (fname, self.encode(code).strip(),
154                               mapname, imgcss))
155             self.body.extend(imgmap)
156     self.body.append('</p>\n')
157     raise nodes.SkipNode
158
159
160 def html_visit_graphviz(self, node):
161     render_dot_html(self, node, node['code'], node['options'])
162
163
164 def render_dot_latex(self, node, code, options, prefix='graphviz'):
165     try:
166         fname, outfn = render_dot(self, code, options, 'pdf', prefix)
167     except GraphvizError, exc:
168         self.builder.warn('dot code %r: ' % code + str(exc))
169         raise nodes.SkipNode
170
171     if fname is not None:
172         self.body.append('\\includegraphics[]{%s}' % fname)
173     raise nodes.SkipNode
174
175
176 def latex_visit_graphviz(self, node):
177     render_dot_latex(self, node, node['code'], node['options'])
178
179 def setup(app):
180     app.add_node(graphviz,
181                  html=(html_visit_graphviz, None),
182                  latex=(latex_visit_graphviz, None))
183     app.add_directive('graphviz', Graphviz)
184     app.add_directive('graph', GraphvizSimple)
185     app.add_directive('digraph', GraphvizSimple)
186     app.add_config_value('graphviz_dot', 'dot', 'html')
187     app.add_config_value('graphviz_dot_args', [], 'html')