#316: catch "broken pipe" OSErrors when communicating with graphviz; get stdout/stderr anyway. This happens e.g. when dot does not support the selected output format.

This commit is contained in:
Georg Brandl 2010-01-12 09:55:07 +00:00
parent 403b01f38b
commit c8321d3020
3 changed files with 21 additions and 6 deletions

View File

@ -1,6 +1,9 @@
Release 0.6.4 (in development) Release 0.6.4 (in development)
============================== ==============================
* #316: Catch OSErrors occurring when calling graphviz with
arguments it doesn't understand.
* Restore compatibility with Pygments >= 1.2. * Restore compatibility with Pygments >= 1.2.
* #295: Fix escaping of hyperref targets in LaTeX output. * #295: Fix escaping of hyperref targets in LaTeX output.

View File

@ -22,7 +22,7 @@ except ImportError:
from docutils import nodes from docutils import nodes
from sphinx.errors import SphinxError from sphinx.errors import SphinxError
from sphinx.util import ensuredir, ENOENT from sphinx.util import ensuredir, ENOENT, EPIPE
from sphinx.util.compat import Directive from sphinx.util.compat import Directive
@ -102,6 +102,10 @@ def render_dot(self, code, options, format, prefix='graphviz'):
ensuredir(path.dirname(outfn)) ensuredir(path.dirname(outfn))
# graphviz expects UTF-8 by default
if isinstance(code, unicode):
code = code.encode('utf-8')
dot_args = [self.builder.config.graphviz_dot] dot_args = [self.builder.config.graphviz_dot]
dot_args.extend(self.builder.config.graphviz_dot_args) dot_args.extend(self.builder.config.graphviz_dot_args)
dot_args.extend(options) dot_args.extend(options)
@ -118,10 +122,17 @@ def render_dot(self, code, options, format, prefix='graphviz'):
self.builder.config.graphviz_dot) self.builder.config.graphviz_dot)
self.builder._graphviz_warned_dot = True self.builder._graphviz_warned_dot = True
return None, None return None, None
# graphviz expects UTF-8 by default try:
if isinstance(code, unicode): # Graphviz may close standard input when an error occurs,
code = code.encode('utf-8') # resulting in a broken pipe on communicate()
stdout, stderr = p.communicate(code) stdout, stderr = p.communicate(code)
except OSError, err:
if err.errno != EPIPE:
raise
# in this case, read the standard output and standard error streams
# directly, to get the error message(s)
stdout, stderr = p.stdout.read(), p.stderr.read()
p.wait()
if p.returncode != 0: if p.returncode != 0:
raise GraphvizError('dot exited with error:\n[stderr]\n%s\n' raise GraphvizError('dot exited with error:\n[stderr]\n%s\n'
'[stdout]\n%s' % (stderr, stdout)) '[stdout]\n%s' % (stderr, stdout))
@ -131,7 +142,7 @@ def render_dot(self, code, options, format, prefix='graphviz'):
def render_dot_html(self, node, code, options, prefix='graphviz', def render_dot_html(self, node, code, options, prefix='graphviz',
imgcls=None, alt=None): imgcls=None, alt=None):
try: try:
fname, outfn = render_dot(self, code, options, 'png', prefix) fname, outfn = render_dot(self, code, options, 'pnf', prefix)
except GraphvizError, exc: except GraphvizError, exc:
self.builder.warn('dot code %r: ' % code + str(exc)) self.builder.warn('dot code %r: ' % code + str(exc))
raise nodes.SkipNode raise nodes.SkipNode

View File

@ -29,6 +29,7 @@ import sphinx
# Errnos that we need. # Errnos that we need.
EEXIST = getattr(errno, 'EEXIST', 0) EEXIST = getattr(errno, 'EEXIST', 0)
ENOENT = getattr(errno, 'ENOENT', 0) ENOENT = getattr(errno, 'ENOENT', 0)
EPIPE = getattr(errno, 'EPIPE', 0)
# Generally useful regular expressions. # Generally useful regular expressions.
ws_re = re.compile(r'\s+') ws_re = re.compile(r'\s+')