summaryrefslogtreecommitdiff
path: root/sphinx/ext/graphviz.py
diff options
context:
space:
mode:
Diffstat (limited to 'sphinx/ext/graphviz.py')
-rw-r--r--sphinx/ext/graphviz.py85
1 files changed, 41 insertions, 44 deletions
diff --git a/sphinx/ext/graphviz.py b/sphinx/ext/graphviz.py
index 028560b1..71e7ba65 100644
--- a/sphinx/ext/graphviz.py
+++ b/sphinx/ext/graphviz.py
@@ -15,14 +15,14 @@ import codecs
import posixpath
from os import path
from subprocess import Popen, PIPE
-try:
- from hashlib import sha1 as sha
-except ImportError:
- from sha import sha
+from hashlib import sha1
+from six import text_type
from docutils import nodes
from docutils.parsers.rst import directives
+from docutils.statemachine import ViewList
+import sphinx
from sphinx.errors import SphinxError
from sphinx.locale import _
from sphinx.util.osutil import ensuredir, ENOENT, EPIPE, EINVAL
@@ -40,6 +40,20 @@ class graphviz(nodes.General, nodes.Element):
pass
+def figure_wrapper(directive, node, caption):
+ figure_node = nodes.figure('', node)
+
+ parsed = nodes.Element()
+ directive.state.nested_parse(ViewList([caption], source=''),
+ directive.content_offset, parsed)
+ caption_node = nodes.caption(parsed[0].rawsource, '',
+ *parsed[0].children)
+ caption_node.source = parsed[0].source
+ caption_node.line = parsed[0].line
+ figure_node += caption_node
+ return figure_node
+
+
class Graphviz(Directive):
"""
Directive to insert arbitrary dot markup.
@@ -85,9 +99,12 @@ class Graphviz(Directive):
node['options'] = []
if 'alt' in self.options:
node['alt'] = self.options['alt']
- if 'caption' in self.options:
- node['caption'] = self.options['caption']
node['inline'] = 'inline' in self.options
+
+ caption = self.options.get('caption')
+ if caption and not node['inline']:
+ node = figure_wrapper(self, node, caption)
+
return [node]
@@ -112,9 +129,12 @@ class GraphvizSimple(Directive):
node['options'] = []
if 'alt' in self.options:
node['alt'] = self.options['alt']
- if 'caption' in self.options:
- node['caption'] = self.options['caption']
node['inline'] = 'inline' in self.options
+
+ caption = self.options.get('caption')
+ if caption and not node['inline']:
+ node = figure_wrapper(self, node, caption)
+
return [node]
@@ -125,15 +145,9 @@ def render_dot(self, code, options, format, prefix='graphviz'):
str(self.builder.config.graphviz_dot_args)
).encode('utf-8')
- fname = '%s-%s.%s' % (prefix, sha(hashkey).hexdigest(), format)
- if hasattr(self.builder, 'imgpath'):
- # HTML
- relfn = posixpath.join(self.builder.imgpath, fname)
- outfn = path.join(self.builder.outdir, '_images', fname)
- else:
- # LaTeX
- relfn = fname
- outfn = path.join(self.builder.outdir, fname)
+ fname = '%s-%s.%s' % (prefix, sha1(hashkey).hexdigest(), format)
+ relfn = posixpath.join(self.builder.imgpath, fname)
+ outfn = path.join(self.builder.outdir, self.builder.imagedir, fname)
if path.isfile(outfn):
return relfn, outfn
@@ -145,7 +159,7 @@ def render_dot(self, code, options, format, prefix='graphviz'):
ensuredir(path.dirname(outfn))
# graphviz expects UTF-8 by default
- if isinstance(code, unicode):
+ if isinstance(code, text_type):
code = code.encode('utf-8')
dot_args = [self.builder.config.graphviz_dot]
@@ -156,7 +170,7 @@ def render_dot(self, code, options, format, prefix='graphviz'):
dot_args.extend(['-Tcmapx', '-o%s.map' % outfn])
try:
p = Popen(dot_args, stdout=PIPE, stdin=PIPE, stderr=PIPE)
- except OSError, err:
+ except OSError as err:
if err.errno != ENOENT: # No such file or directory
raise
self.builder.warn('dot command %r cannot be run (needed for graphviz '
@@ -168,7 +182,7 @@ def render_dot(self, code, options, format, prefix='graphviz'):
# Graphviz may close standard input when an error occurs,
# resulting in a broken pipe on communicate()
stdout, stderr = p.communicate(code)
- except (OSError, IOError), err:
+ except (OSError, IOError) as err:
if err.errno not in (EPIPE, EINVAL):
raise
# in this case, read the standard output and standard error streams
@@ -192,7 +206,7 @@ def render_dot_html(self, node, code, options, prefix='graphviz',
raise GraphvizError("graphviz_output_format must be one of 'png', "
"'svg', but is %r" % format)
fname, outfn = render_dot(self, code, options, format, prefix)
- except GraphvizError, exc:
+ except GraphvizError as exc:
self.builder.warn('dot code %r: ' % code + str(exc))
raise nodes.SkipNode
@@ -228,9 +242,6 @@ def render_dot_html(self, node, code, options, prefix='graphviz',
self.body.append('<img src="%s" alt="%s" usemap="#%s" %s/>\n' %
(fname, alt, mapname, imgcss))
self.body.extend([item.decode('utf-8') for item in imgmap])
- if node.get('caption') and not inline:
- self.body.append('</p>\n<p class="caption">')
- self.body.append(self.encode(node['caption']))
self.body.append('</%s>\n' % wrapper)
raise nodes.SkipNode
@@ -243,7 +254,7 @@ def html_visit_graphviz(self, node):
def render_dot_latex(self, node, code, options, prefix='graphviz'):
try:
fname, outfn = render_dot(self, code, options, 'pdf', prefix)
- except GraphvizError, exc:
+ except GraphvizError as exc:
self.builder.warn('dot code %r: ' % code + str(exc))
raise nodes.SkipNode
@@ -254,18 +265,8 @@ def render_dot_latex(self, node, code, options, prefix='graphviz'):
para_separator = '\n'
if fname is not None:
- caption = node.get('caption')
- # XXX add ids from previous target node
- if caption and not inline:
- self.body.append('\n\\begin{figure}[h!]')
- self.body.append('\n\\begin{center}')
- self.body.append('\n\\caption{%s}' % self.encode(caption))
- self.body.append('\n\\includegraphics{%s}' % fname)
- self.body.append('\n\\end{center}')
- self.body.append('\n\\end{figure}\n')
- else:
- self.body.append('%s\\includegraphics{%s}%s' %
- (para_separator, fname, para_separator))
+ self.body.append('%s\\includegraphics{%s}%s' %
+ (para_separator, fname, para_separator))
raise nodes.SkipNode
@@ -276,16 +277,11 @@ def latex_visit_graphviz(self, node):
def render_dot_texinfo(self, node, code, options, prefix='graphviz'):
try:
fname, outfn = render_dot(self, code, options, 'png', prefix)
- except GraphvizError, exc:
+ except GraphvizError as exc:
self.builder.warn('dot code %r: ' % code + str(exc))
raise nodes.SkipNode
if fname is not None:
- self.body.append('\n\n@float\n')
- caption = node.get('caption')
- if caption:
- self.body.append('@caption{%s}\n' % self.escape_arg(caption))
- self.body.append('@image{%s,,,[graphviz],png}\n'
- '@end float\n\n' % fname[:-4])
+ self.body.append('@image{%s,,,[graphviz],png}\n' % fname[:-4])
raise nodes.SkipNode
def texinfo_visit_graphviz(self, node):
@@ -321,3 +317,4 @@ def setup(app):
app.add_config_value('graphviz_dot', 'dot', 'html')
app.add_config_value('graphviz_dot_args', [], 'html')
app.add_config_value('graphviz_output_format', 'png', 'html')
+ return {'version': sphinx.__version__, 'parallel_read_safe': True}