Commits

Georg Brandl committed 6f6aa47 Merge

merge with trunk

Comments (0)

Files changed (24)

 1f4cba6a285ae9042762fb7cdcf88c6db55b9da7 0.1.61843
 6d93c72d97d9e3cc7d2f3c03f279af0c7b1e85ff 0.1.61798
 17af190a72e157f767e30a284f49bdcd2b5a3689 0.1.61611
+24a2061063212f1951507a35ed589a55cd9dd962 0.6.4
 * Added ``htmltitle`` block in layout template.
 
 
-Release 0.6.4 (in development)
+Release 0.6.5 (in development)
 ==============================
 
+* #321: Fix link generation in the LaTeX builder.
+
+
+Release 0.6.4 (Jan 12, 2010)
+============================
+
+* 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.

doc/_templates/index.html

   <p>
     The <a href="http://docs.python.org/dev/">Python documentation</a> and
     this page are different examples of Sphinx in use.
-    You can also download a <a href="http://sphinx.pocoo.org/sphinx.pdf">PDF version</a>
-    of the Sphinx documentation, generated from the LaTeX Sphinx produces.
+    You can also download PDF versions of the Sphinx documentation:
+    a <a href="http://sphinx.pocoo.org/sphinx.pdf">version</a> generated from
+    the LaTeX Sphinx produces, and a
+    <a href="http://sphinx.pocoo.org/sphinx-rst2pdf.pdf">version</a> generated by rst2pdf.
   </p>
   <p>
     For examples of how Sphinx source files look, use the &#8220;Show source&#8221;
    <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
 come from the power and straightforwardness of reStructuredText and its
 parsing and translating suite, the Docutils.
 
-Although it is still under constant development, the following features
-are already present, work fine and can be seen "in action" in the Python docs:
+Among its features are the following:
 
-* Output formats: HTML (including Windows HTML Help), plain text and LaTeX,
-  for printable PDF versions
+* Output formats: HTML (including derivative formats such as HTML Help, Epub
+  and Qt Help), plain text and LaTeX or direct PDF output using rst2pdf
 * Extensive cross-references: semantic markup and automatic links
   for functions, classes, glossary terms and similar pieces of information
 * Hierarchical structure: easy definition of a document tree, with automatic
   links to siblings, parents and children
 * Automatic indices: general index as well as a module index
 * Code handling: automatic highlighting using the Pygments highlighter
+* Flexible HTML output using the Jinja 2 templating engine
 * Various extensions are available, e.g. for automatic testing of snippets
-  and inclusion of appropriately formatted docstrings.
+  and inclusion of appropriately formatted docstrings
+* Setuptools integration
 
 A development egg can be found `here
 <http://bitbucket.org/birkenfeld/sphinx/get/tip.gz#egg=Sphinx-dev>`_.

sphinx/__init__.py

File contents unchanged.

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:

sphinx/builders/html.py

     embedded = False  # for things like HTML help or Qt help: suppresses sidebar
 
     # This is a class attribute because it is mutated by Sphinx.add_javascript.
-    script_files = ['_static/jquery.js', '_static/doctools.js']
+    script_files = ['_static/jquery.js', '_static/underscore.js',
+                    '_static/doctools.js']
     # Dito for this one.
     css_files = []
 
         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

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.")
+                return
             self.info("done")
 
     def assemble_doctree(self, indexfile, toctree_only, appendices):

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

sphinx/domains/std.py

             docname, labelid = self.data['objects'].get((typ, target), ('', ''))
             if not docname:
                 if typ == 'term':
-                    env.warn(node['refdoc'],
+                    env.warn(node.get('refdoc', fromdocname),
                              'term not in glossary: %s' % target, node.line)
                 return None
             else:

sphinx/environment.py

 
             typ = node['reftype']
             target = node['reftarget']
+            refdoc = node.get('refdoc', fromdocname)
 
             try:
                 if node.has_key('refdomain') and node['refdomain']:
                         docname, labelid = self.anonlabels.get(target, ('',''))
                         sectname = node.astext()
                         if not docname:
-                            self.warn(node['refdoc'], 'undefined label: %s' %
+                            self.warn(refdoc, 'undefined label: %s' %
                                       target, node.line)
                     else:
                         # reference to named label; the final node will
                         docname, labelid, sectname = self.labels.get(target,
                                                                      ('','',''))
                         if not docname:
-                            self.warn(
-                                node['refdoc'],
+                            self.warn(refdoc,
                                 'undefined label: %s' % target + ' -- if you '
                                 'don\'t give a link caption the label must '
                                 'precede a section header.', node.line)
                 elif typ == 'doc':
                     # directly reference to document by source name;
                     # can be absolute or relative
-                    docname = docname_join(node['refdoc'], target)
+                    docname = docname_join(refdoc, target)
                     if docname not in self.all_docs:
-                        self.warn(node['refdoc'],
+                        self.warn(refdoc,
                                   'unknown document: %s' % docname, node.line)
                     else:
                         if node['refexplicit']:
                     # keywords are oddballs: they are referenced by named labels
                     docname, labelid, _ = self.labels.get(target, ('','',''))
                     if not docname:
-                        #self.warn(node['refdoc'],
-                        #          'unknown keyword: %s' % target)
+                        #self.warn(refdoc, 'unknown keyword: %s' % target)
                         pass
                     else:
                         newnode = make_refnode(builder, fromdocname, docname,
         return parent_str
 
 
+class ConfigError(SphinxError):
+    category = 'Configuration error'
+
+
 class ThemeError(SphinxError):
     category = 'Theme error'
 

sphinx/ext/autosummary/templates/autosummary/module.rst

    .. rubric:: Exceptions
 
    .. autosummary::
-   {% for item in classes %}
+   {% for item in exceptions %}
       {{ item }}
    {%- endfor %}
    {% endif %}

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

sphinx/themes/basic/static/doctools.js

  */
 
 /**
+ * select a different prefix for underscore
+ */
+$u = _.noConflict();
+
+/**
  * make the code below compatible with browsers without
  * an installed firebug like debugger
 if (!window.console || !console.firebug) {
       result[key] = [value];
   }
   return result;
-}
+};
 
 /**
  * small function to check if an array contains
       return true;
   }
   return false;
-}
+};
 
 /**
  * highlight a given string on a jquery object by wrapping it in
   return this.each(function() {
     highlight(this);
   });
-}
+};
 
 /**
  * Small JavaScript module for the documentation.

sphinx/themes/basic/static/searchtools.js

     var tmp = query.split(/\s+/);
     var object = (tmp.length == 1) ? tmp[0].toLowerCase() : null;
     for (var i = 0; i < tmp.length; i++) {
-      if (stopwords.indexOf(tmp[i]) != -1 || tmp[i].match(/^\d+$/)) {
+      if ($u.indexOf(stopwords, tmp[i]) != -1 || tmp[i].match(/^\d+$/)) {
         // skip this word
         continue;
       }

sphinx/themes/basic/static/underscore.js

+(function(){var j=this,n=j._,i=function(a){this._wrapped=a},m=typeof StopIteration!=="undefined"?StopIteration:"__break__",b=j._=function(a){return new i(a)};if(typeof exports!=="undefined")exports._=b;var k=Array.prototype.slice,o=Array.prototype.unshift,p=Object.prototype.toString,q=Object.prototype.hasOwnProperty,r=Object.prototype.propertyIsEnumerable;b.VERSION="0.5.5";b.each=function(a,c,d){try{if(a.forEach)a.forEach(c,d);else if(b.isArray(a)||b.isArguments(a))for(var e=0,f=a.length;e<f;e++)c.call(d,
+a[e],e,a);else{var g=b.keys(a);f=g.length;for(e=0;e<f;e++)c.call(d,a[g[e]],g[e],a)}}catch(h){if(h!=m)throw h;}return a};b.map=function(a,c,d){if(a&&b.isFunction(a.map))return a.map(c,d);var e=[];b.each(a,function(f,g,h){e.push(c.call(d,f,g,h))});return e};b.reduce=function(a,c,d,e){if(a&&b.isFunction(a.reduce))return a.reduce(b.bind(d,e),c);b.each(a,function(f,g,h){c=d.call(e,c,f,g,h)});return c};b.reduceRight=function(a,c,d,e){if(a&&b.isFunction(a.reduceRight))return a.reduceRight(b.bind(d,e),c);
+var f=b.clone(b.toArray(a)).reverse();b.each(f,function(g,h){c=d.call(e,c,g,h,a)});return c};b.detect=function(a,c,d){var e;b.each(a,function(f,g,h){if(c.call(d,f,g,h)){e=f;b.breakLoop()}});return e};b.select=function(a,c,d){if(a&&b.isFunction(a.filter))return a.filter(c,d);var e=[];b.each(a,function(f,g,h){c.call(d,f,g,h)&&e.push(f)});return e};b.reject=function(a,c,d){var e=[];b.each(a,function(f,g,h){!c.call(d,f,g,h)&&e.push(f)});return e};b.all=function(a,c,d){c=c||b.identity;if(a&&b.isFunction(a.every))return a.every(c,
+d);var e=true;b.each(a,function(f,g,h){(e=e&&c.call(d,f,g,h))||b.breakLoop()});return e};b.any=function(a,c,d){c=c||b.identity;if(a&&b.isFunction(a.some))return a.some(c,d);var e=false;b.each(a,function(f,g,h){if(e=c.call(d,f,g,h))b.breakLoop()});return e};b.include=function(a,c){if(b.isArray(a))return b.indexOf(a,c)!=-1;var d=false;b.each(a,function(e){if(d=e===c)b.breakLoop()});return d};b.invoke=function(a,c){var d=b.rest(arguments,2);return b.map(a,function(e){return(c?e[c]:e).apply(e,d)})};b.pluck=
+function(a,c){return b.map(a,function(d){return d[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a))return Math.max.apply(Math,a);var e={computed:-Infinity};b.each(a,function(f,g,h){g=c?c.call(d,f,g,h):f;g>=e.computed&&(e={value:f,computed:g})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);var e={computed:Infinity};b.each(a,function(f,g,h){g=c?c.call(d,f,g,h):f;g<e.computed&&(e={value:f,computed:g})});return e.value};b.sortBy=function(a,c,d){return b.pluck(b.map(a,
+function(e,f,g){return{value:e,criteria:c.call(d,e,f,g)}}).sort(function(e,f){e=e.criteria;f=f.criteria;return e<f?-1:e>f?1:0}),"value")};b.sortedIndex=function(a,c,d){d=d||b.identity;for(var e=0,f=a.length;e<f;){var g=e+f>>1;d(a[g])<d(c)?(e=g+1):(f=g)}return e};b.toArray=function(a){if(!a)return[];if(a.toArray)return a.toArray();if(b.isArray(a))return a;if(b.isArguments(a))return k.call(a);return b.values(a)};b.size=function(a){return b.toArray(a).length};b.first=function(a,c,d){return c&&!d?k.call(a,
+0,c):a[0]};b.rest=function(a,c,d){return k.call(a,b.isUndefined(c)||d?1:c)};b.last=function(a){return a[a.length-1]};b.compact=function(a){return b.select(a,function(c){return!!c})};b.flatten=function(a){return b.reduce(a,[],function(c,d){if(b.isArray(d))return c.concat(b.flatten(d));c.push(d);return c})};b.without=function(a){var c=b.rest(arguments);return b.select(a,function(d){return!b.include(c,d)})};b.uniq=function(a,c){return b.reduce(a,[],function(d,e,f){if(0==f||(c===true?b.last(d)!=e:!b.include(d,
+e)))d.push(e);return d})};b.intersect=function(a){var c=b.rest(arguments);return b.select(b.uniq(a),function(d){return b.all(c,function(e){return b.indexOf(e,d)>=0})})};b.zip=function(){for(var a=b.toArray(arguments),c=b.max(b.pluck(a,"length")),d=new Array(c),e=0;e<c;e++)d[e]=b.pluck(a,String(e));return d};b.indexOf=function(a,c){if(a.indexOf)return a.indexOf(c);for(var d=0,e=a.length;d<e;d++)if(a[d]===c)return d;return-1};b.lastIndexOf=function(a,c){if(a.lastIndexOf)return a.lastIndexOf(c);for(var d=
+a.length;d--;)if(a[d]===c)return d;return-1};b.range=function(a,c,d){var e=b.toArray(arguments),f=e.length<=1;a=f?0:e[0];c=f?e[0]:e[1];d=e[2]||1;e=Math.ceil((c-a)/d);if(e<=0)return[];e=new Array(e);f=a;for(var g=0;1;f+=d){if((d>0?f-c:c-f)>=0)return e;e[g++]=f}};b.bind=function(a,c){var d=b.rest(arguments,2);return function(){return a.apply(c||j,d.concat(b.toArray(arguments)))}};b.bindAll=function(a){var c=b.rest(arguments);if(c.length==0)c=b.functions(a);b.each(c,function(d){a[d]=b.bind(a[d],a)});
+return a};b.delay=function(a,c){var d=b.rest(arguments,2);return setTimeout(function(){return a.apply(a,d)},c)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(b.rest(arguments)))};b.wrap=function(a,c){return function(){var d=[a].concat(b.toArray(arguments));return c.apply(c,d)}};b.compose=function(){var a=b.toArray(arguments);return function(){for(var c=b.toArray(arguments),d=a.length-1;d>=0;d--)c=[a[d].apply(this,c)];return c[0]}};b.keys=function(a){if(b.isArray(a))return b.range(0,a.length);
+var c=[];for(var d in a)q.call(a,d)&&c.push(d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=function(a){return b.select(b.keys(a),function(c){return b.isFunction(a[c])}).sort()};b.extend=function(a,c){for(var d in c)a[d]=c[d];return a};b.clone=function(a){if(b.isArray(a))return a.slice(0);return b.extend({},a)};b.tap=function(a,c){c(a);return a};b.isEqual=function(a,c){if(a===c)return true;var d=typeof a;if(d!=typeof c)return false;if(a==c)return true;if(!a&&c||a&&!c)return false;
+if(a.isEqual)return a.isEqual(c);if(b.isDate(a)&&b.isDate(c))return a.getTime()===c.getTime();if(b.isNaN(a)&&b.isNaN(c))return true;if(b.isRegExp(a)&&b.isRegExp(c))return a.source===c.source&&a.global===c.global&&a.ignoreCase===c.ignoreCase&&a.multiline===c.multiline;if(d!=="object")return false;if(a.length&&a.length!==c.length)return false;d=b.keys(a);var e=b.keys(c);if(d.length!=e.length)return false;for(var f in a)if(!b.isEqual(a[f],c[f]))return false;return true};b.isEmpty=function(a){return b.keys(a).length==
+0};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=function(a){return!!(a&&a.concat&&a.unshift)};b.isArguments=function(a){return a&&b.isNumber(a.length)&&!b.isArray(a)&&!r.call(a,"length")};b.isFunction=function(a){return!!(a&&a.constructor&&a.call&&a.apply)};b.isString=function(a){return!!(a===""||a&&a.charCodeAt&&a.substr)};b.isNumber=function(a){return p.call(a)==="[object Number]"};b.isDate=function(a){return!!(a&&a.getTimezoneOffset&&a.setUTCFullYear)};b.isRegExp=function(a){return!!(a&&
+a.test&&a.exec&&(a.ignoreCase||a.ignoreCase===false))};b.isNaN=function(a){return b.isNumber(a)&&isNaN(a)};b.isNull=function(a){return a===null};b.isUndefined=function(a){return typeof a=="undefined"};b.noConflict=function(){j._=n;return this};b.identity=function(a){return a};b.breakLoop=function(){throw m;};var s=0;b.uniqueId=function(a){var c=s++;return a?a+c:c};b.template=function(a,c){a=new Function("obj","var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('"+a.replace(/[\r\t\n]/g,
+" ").replace(/'(?=[^%]*%>)/g,"\t").split("'").join("\\'").split("\t").join("'").replace(/<%=(.+?)%>/g,"',$1,'").split("<%").join("');").split("%>").join("p.push('")+"');}return p.join('');");return c?a(c):a};b.forEach=b.each;b.foldl=b.inject=b.reduce;b.foldr=b.reduceRight;b.filter=b.select;b.every=b.all;b.some=b.any;b.head=b.first;b.tail=b.rest;b.methods=b.functions;var l=function(a,c){return c?b(a).chain():a};b.each(b.functions(b),function(a){var c=b[a];i.prototype[a]=function(){var d=b.toArray(arguments);
+o.call(d,this._wrapped);return l(c.apply(b,d),this._chain)}});b.each(["pop","push","reverse","shift","sort","splice","unshift"],function(a){var c=Array.prototype[a];i.prototype[a]=function(){c.apply(this._wrapped,arguments);return l(this._wrapped,this._chain)}});b.each(["concat","join","slice"],function(a){var c=Array.prototype[a];i.prototype[a]=function(){return l(c.apply(this._wrapped,arguments),this._chain)}});i.prototype.chain=function(){this._chain=true;return this};i.prototype.value=function(){return this._wrapped}})();

sphinx/themes/default/static/default.css_t

     display: inline;
 }
 
+div.admonition p {
+    margin-bottom: 5px;
+}
+
+div.admonition pre {
+    margin-bottom: 5px;
+}
+
+div.admonition ul, div.admonition ol {
+    margin-bottom: 5px;
+}
+
 div.note {
     background-color: #eee;
     border: 1px solid #ccc;

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

sphinx/writers/latex.py

             self.body.append('\\href{%s}{' % self.encode_uri(uri))
             self.context.append('}')
         elif uri.startswith('#'):
-            self.body.append('\\hyperlink{%s}{' % uri[1:])
+            # references to labels
+            self.body.append('\\hyperlink{%s}{' % self.idescape(uri[1:]))
             self.context.append('}')
         elif uri.startswith('%'):
+            # references to documents or labels inside documents
             hashindex = uri.find('#')
             targetname = (hashindex == -1) and '--doc-' + uri[1:] \
                                            or uri[hashindex+1:]
-            self.body.append('\\hyperlink{%s}{' % targetname)
+            self.body.append('\\hyperlink{%s}{' % self.idescape(targetname))
             self.context.append('}')
         elif uri.startswith('@token'):
             if self.in_production_list:

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]

utils/check_sources.py

                 yield lno+1, '"%s" used' % word
 
 
-bad_tags = ('<u>', '<s>', '<strike>'
-            '<center>', '<big>', '<small>', '<font')
+bad_tags = ('<u>', '<s>', '<strike>', '<center>', '<font')
 
 @checker('.html')
 def check_xhtml(fn, lines):