From c8321d3020760fb2ec1c51df8bb91e436096172c Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Tue, 12 Jan 2010 09:55:07 +0000 Subject: [PATCH] #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. --- CHANGES | 3 +++ sphinx/ext/graphviz.py | 23 +++++++++++++++++------ sphinx/util/__init__.py | 1 + 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/CHANGES b/CHANGES index c6004c3f0..119950f22 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ 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. * #295: Fix escaping of hyperref targets in LaTeX output. diff --git a/sphinx/ext/graphviz.py b/sphinx/ext/graphviz.py index d3e1bd99e..993d48962 100644 --- a/sphinx/ext/graphviz.py +++ b/sphinx/ext/graphviz.py @@ -22,7 +22,7 @@ except ImportError: from docutils import nodes from sphinx.errors import SphinxError -from sphinx.util import ensuredir, ENOENT +from sphinx.util import ensuredir, ENOENT, EPIPE from sphinx.util.compat import Directive @@ -102,6 +102,10 @@ def render_dot(self, code, options, format, prefix='graphviz'): 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.extend(self.builder.config.graphviz_dot_args) dot_args.extend(options) @@ -118,10 +122,17 @@ def render_dot(self, code, options, format, prefix='graphviz'): self.builder.config.graphviz_dot) self.builder._graphviz_warned_dot = True return None, None - # graphviz expects UTF-8 by default - if isinstance(code, unicode): - code = code.encode('utf-8') - stdout, stderr = p.communicate(code) + try: + # Graphviz may close standard input when an error occurs, + # resulting in a broken pipe on communicate() + 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: raise GraphvizError('dot exited with error:\n[stderr]\n%s\n' '[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', imgcls=None, alt=None): try: - fname, outfn = render_dot(self, code, options, 'png', prefix) + fname, outfn = render_dot(self, code, options, 'pnf', prefix) except GraphvizError, exc: self.builder.warn('dot code %r: ' % code + str(exc)) raise nodes.SkipNode diff --git a/sphinx/util/__init__.py b/sphinx/util/__init__.py index 0b9a1ace0..5745907f4 100644 --- a/sphinx/util/__init__.py +++ b/sphinx/util/__init__.py @@ -29,6 +29,7 @@ import sphinx # Errnos that we need. EEXIST = getattr(errno, 'EEXIST', 0) ENOENT = getattr(errno, 'ENOENT', 0) +EPIPE = getattr(errno, 'EPIPE', 0) # Generally useful regular expressions. ws_re = re.compile(r'\s+')