From a4ca76db7e43d76eba79e3dbd9955dba3ff26e1e Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Thu, 7 Jan 2010 14:35:24 +0100 Subject: [PATCH 1/5] Fix long line. --- sphinx/environment.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sphinx/environment.py b/sphinx/environment.py index 5c9b45f0a..e21364268 100644 --- a/sphinx/environment.py +++ b/sphinx/environment.py @@ -1232,7 +1232,8 @@ class BuildEnvironment: # keywords are referenced by named labels docname, labelid, _ = self.labels.get(target, ('','','')) if not docname: - #self.warn(node['refdoc'], 'unknown keyword: %s' % target) + #self.warn(node['refdoc'], + # 'unknown keyword: %s' % target) newnode = contnode else: newnode = nodes.reference('', '') From ebe51c181e7d30ee24a7a02f67ca72deca5ae3bf Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Thu, 7 Jan 2010 15:33:47 +0100 Subject: [PATCH 2/5] Add a "how do I do google analytics" entry, thanks tonfa. --- doc/faq.rst | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/doc/faq.rst b/doc/faq.rst index 34502dc41..54aef384c 100644 --- a/doc/faq.rst +++ b/doc/faq.rst @@ -53,6 +53,39 @@ github pages `_ to prepare Sphinx HTML output. +Google Analytics + You can use a custom ``layout.html`` template, like this: + + .. code-block:: html+django + + {% extends "!layout.html" %} + + {%- block extrahead %} + {{ super() }} + + {% endblock %} + + {% block footer %} + {{ super() }} + + {% endblock %} + .. _api role: http://git.savannah.gnu.org/cgit/kenozooid.git/tree/doc/extapi.py .. _xhtml to reST: http://docutils.sourceforge.net/sandbox/xhtml2rest/xhtml2rest.py From 403b01f38b187eb17ec69196aa14e246f9c726da Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Tue, 12 Jan 2010 09:43:34 +0000 Subject: [PATCH 3/5] #315: update bug reporting information. --- sphinx/cmdline.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sphinx/cmdline.py b/sphinx/cmdline.py index 8a069b325..dc3269e23 100644 --- a/sphinx/cmdline.py +++ b/sphinx/cmdline.py @@ -198,10 +198,13 @@ def main(argv): tbpath = save_traceback() print >>error, red('The full traceback has been saved ' 'in %s, if you want to report the ' - 'issue to the author.' % tbpath) + 'issue to the developers.' % tbpath) print >>error, ('Please also report this if it was a user ' 'error, so that a better error message ' 'can be provided next time.') - print >>error, ('Send reports to sphinx-dev@googlegroups.com. ' - 'Thanks!') + print >>error, ( + 'Either send bugs to the mailing list at ' + ',\n' + 'or report them in the tracker at ' + '. Thanks!') return 1 From c8321d3020760fb2ec1c51df8bb91e436096172c Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Tue, 12 Jan 2010 09:55:07 +0000 Subject: [PATCH 4/5] #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+') From 43d08313a0ecb0b331179c4875cf83728b4d9665 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Tue, 12 Jan 2010 10:45:38 +0000 Subject: [PATCH 5/5] Improve the handling of non-Unicode strings in the configuration: warn about non-ascii bytestrings, and give nicer messages if unicode errors occur. --- CHANGES | 2 ++ sphinx/application.py | 1 + sphinx/builders/html.py | 9 ++++++++- sphinx/builders/latex.py | 8 +++++++- sphinx/config.py | 20 +++++++++++++++++++- sphinx/errors.py | 4 ++++ tests/test_config.py | 19 ++++++++++++++++++- 7 files changed, 59 insertions(+), 4 deletions(-) diff --git a/CHANGES b/CHANGES index 119950f22..6bb149feb 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ Release 0.6.4 (in development) ============================== +* Improve the handling of non-Unicode strings in the configuration. + * #316: Catch OSErrors occurring when calling graphviz with arguments it doesn't understand. diff --git a/sphinx/application.py b/sphinx/application.py index 581e0fc6e..7d5c54392 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -92,6 +92,7 @@ class Sphinx(object): # read config self.tags = Tags(tags) self.config = Config(confdir, CONFIG_FILENAME, confoverrides, self.tags) + self.config.check_unicode(self.warn) # load all extension modules for extension in self.config.extensions: diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py index 6eff890cf..04f070707 100644 --- a/sphinx/builders/html.py +++ b/sphinx/builders/html.py @@ -656,7 +656,14 @@ class StandaloneHTMLBuilder(Builder): self.app.emit('html-page-context', pagename, templatename, ctx, event_arg) - output = self.templates.render(templatename, ctx) + try: + output = self.templates.render(templatename, ctx) + except UnicodeError: + self.warn("a Unicode error occurred when rendering the page %s. " + "Please make sure all config values that contain " + "non-ASCII content are Unicode strings." % pagename) + return + if not outfilename: outfilename = self.get_outfilename(pagename) # outfilename's path is in general different from self.outdir diff --git a/sphinx/builders/latex.py b/sphinx/builders/latex.py index 0db30d553..eed4787d5 100644 --- a/sphinx/builders/latex.py +++ b/sphinx/builders/latex.py @@ -102,7 +102,13 @@ class LaTeXBuilder(Builder): doctree.settings.title = title doctree.settings.docname = docname doctree.settings.docclass = docclass - docwriter.write(doctree, destination) + try: + docwriter.write(doctree, destination) + except UnicodeError: + self.warn("a Unicode error occurred when writing the output. " + "Please make sure all config values that contain " + "non-ASCII content are Unicode strings." % pagename) + return self.info("done") def assemble_doctree(self, indexfile, toctree_only, appendices): diff --git a/sphinx/config.py b/sphinx/config.py index ee1bfb5fa..990849c93 100644 --- a/sphinx/config.py +++ b/sphinx/config.py @@ -10,9 +10,13 @@ """ import os +import re from os import path from sphinx.util import make_filename +from sphinx.errors import ConfigError + +nonascii_re = re.compile(r'[\x80-\xff]') class Config(object): @@ -112,20 +116,34 @@ class Config(object): self.values = Config.config_values.copy() config = {} if dirname is not None: - config['__file__'] = path.join(dirname, filename) + config_file = path.join(dirname, filename) + config['__file__'] = config_file config['tags'] = tags olddir = os.getcwd() try: os.chdir(dirname) execfile(config['__file__'], config) + except SyntaxError, err: + raise ConfigError('There is a syntax error in your ' + 'configuration file: ' + str(err)) finally: os.chdir(olddir) + self._raw_config = config # these two must be preinitialized because extensions can add their # own config values self.setup = config.get('setup', None) self.extensions = config.get('extensions', []) + def check_unicode(self, warn): + # check all string values for non-ASCII characters in + # bytestrings, since that can + for name, value in self._raw_config.iteritems(): + if isinstance(value, str) and nonascii_re.search(value): + warn('the config value %r is set to a string with non-ASCII ' + 'characters; this can lead to Unicode errors occurring. ' + 'Please use Unicode strings, e.g. u"Content".' % name) + def init_values(self): config = self._raw_config for valname, value in self.overrides.iteritems(): diff --git a/sphinx/errors.py b/sphinx/errors.py index 684101c68..4e62b1af1 100644 --- a/sphinx/errors.py +++ b/sphinx/errors.py @@ -44,5 +44,9 @@ class ExtensionError(SphinxError): return parent_str +class ConfigError(SphinxError): + category = 'Configuration error' + + class ThemeError(SphinxError): category = 'Theme error' diff --git a/tests/test_config.py b/tests/test_config.py index 76f7920b6..346e66c9a 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -12,7 +12,8 @@ from util import * -from sphinx.application import ExtensionError +from sphinx.config import Config +from sphinx.errors import ExtensionError, ConfigError @with_app(confoverrides={'master_doc': 'master', 'nonexisting_value': 'True', @@ -77,3 +78,19 @@ def test_extension_values(app): 'html_title', 'x', True) raises_msg(ExtensionError, 'already present', app.add_config_value, 'value_from_ext', 'x', True) + + +@with_tempdir +def test_errors_warnings(dir): + # test the error for syntax errors in the config file + write_file(dir / 'conf.py', 'project = \n') + raises_msg(ConfigError, 'conf.py', Config, dir, 'conf.py', {}, None) + + # test the warning for bytestrings with non-ascii content + write_file(dir / 'conf.py', '# -*- coding: latin-1\nproject = "foo\xe4"\n') + cfg = Config(dir, 'conf.py', {}, None) + warned = [False] + def warn(msg): + warned[0] = True + cfg.check_unicode(warn) + assert warned[0]