Commits

Georg Brandl  committed 1030c1d Merge

merge with 0.6

  • Participants
  • Parent commits 25cafc4, 2a22e62

Comments (0)

Files changed (12)

 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.
+
 * Restore compatibility with Pygments >= 1.2.
 
 * #295: Fix escaping of hyperref targets in LaTeX output.
    <http://github.com/michaeljones/sphinx-to-github/tree/master>`_ 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() }}
+      <script type="text/javascript">
+        var _gaq = _gaq || [];
+        _gaq.push(['_setAccount', 'XXX account number XXX']);
+        _gaq.push(['_trackPageview']);
+      </script>
+      {% endblock %}
+
+      {% block footer %}
+      {{ super() }}
+      <div class="footer">This page uses <a href="http://analytics.google.com/">
+      Google Analytics</a> to collect statistics. You can disable it by blocking
+      the JavaScript coming from www.google-analytics.com.
+      <script type="text/javascript">
+        (function() {
+          var ga = document.createElement('script');
+          ga.src = ('https:' == document.location.protocol ?
+                    'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
+          ga.setAttribute('async', 'true');
+          document.documentElement.firstChild.appendChild(ga);
+        })();
+      </script>
+      </div>
+      {% 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

File sphinx/application.py

         # 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:

File sphinx/builders/html.py

         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

File sphinx/builders/latex.py

             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):

File sphinx/cmdline.py

                 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 '
+                    '<http://groups.google.com/group/sphinx-dev/>,\n'
+                    'or report them in the tracker at '
+                    '<http://bitbucket.org/birkenfeld/sphinx/issues/>. Thanks!')
             return 1

File sphinx/config.py

 """
 
 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):
         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():

File sphinx/environment.py

File contents unchanged.

File sphinx/errors.py

         return parent_str
 
 
+class ConfigError(SphinxError):
+    category = 'Configuration error'
+
+
 class ThemeError(SphinxError):
     category = 'Theme error'

File sphinx/ext/graphviz.py

 from docutils.parsers.rst import directives
 
 from sphinx.errors import SphinxError
-from sphinx.util import ensuredir, ENOENT
+from sphinx.util import ensuredir, ENOENT, EPIPE
 from sphinx.util.compat import Directive
 
 
 
     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)
                           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))

File sphinx/util/__init__.py

 # 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+')

File tests/test_config.py

 
 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',
                '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]