merge with 0.6

This commit is contained in:
Georg Brandl 2010-01-12 10:47:29 +00:00
commit 8bb4d4320d
11 changed files with 118 additions and 12 deletions

View File

@ -79,6 +79,11 @@ Release 1.0 (in development)
Release 0.6.4 (in development) 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. * 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

@ -53,6 +53,39 @@ github pages
<http://github.com/michaeljones/sphinx-to-github/tree/master>`_ to prepare <http://github.com/michaeljones/sphinx-to-github/tree/master>`_ to prepare
Sphinx HTML output. 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 .. _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 .. _xhtml to reST: http://docutils.sourceforge.net/sandbox/xhtml2rest/xhtml2rest.py

View File

@ -92,6 +92,7 @@ class Sphinx(object):
# read config # read config
self.tags = Tags(tags) self.tags = Tags(tags)
self.config = Config(confdir, CONFIG_FILENAME, confoverrides, self.tags) self.config = Config(confdir, CONFIG_FILENAME, confoverrides, self.tags)
self.config.check_unicode(self.warn)
# load all extension modules # load all extension modules
for extension in self.config.extensions: for extension in self.config.extensions:

View File

@ -723,7 +723,14 @@ class StandaloneHTMLBuilder(Builder):
self.app.emit('html-page-context', pagename, templatename, self.app.emit('html-page-context', pagename, templatename,
ctx, event_arg) ctx, event_arg)
try:
output = self.templates.render(templatename, ctx) 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: if not outfilename:
outfilename = self.get_outfilename(pagename) outfilename = self.get_outfilename(pagename)
# outfilename's path is in general different from self.outdir # outfilename's path is in general different from self.outdir

View File

@ -102,7 +102,13 @@ class LaTeXBuilder(Builder):
doctree.settings.title = title doctree.settings.title = title
doctree.settings.docname = docname doctree.settings.docname = docname
doctree.settings.docclass = docclass doctree.settings.docclass = docclass
try:
docwriter.write(doctree, destination) 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") self.info("done")
def assemble_doctree(self, indexfile, toctree_only, appendices): def assemble_doctree(self, indexfile, toctree_only, appendices):

View File

@ -198,10 +198,13 @@ def main(argv):
tbpath = save_traceback() tbpath = save_traceback()
print >>error, red('The full traceback has been saved ' print >>error, red('The full traceback has been saved '
'in %s, if you want to report the ' '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 ' print >>error, ('Please also report this if it was a user '
'error, so that a better error message ' 'error, so that a better error message '
'can be provided next time.') 'can be provided next time.')
print >>error, ('Send reports to sphinx-dev@googlegroups.com. ' print >>error, (
'Thanks!') '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 return 1

View File

@ -10,9 +10,13 @@
""" """
import os import os
import re
from os import path from os import path
from sphinx.util import make_filename from sphinx.util import make_filename
from sphinx.errors import ConfigError
nonascii_re = re.compile(r'[\x80-\xff]')
class Config(object): class Config(object):
@ -135,20 +139,34 @@ class Config(object):
self.values = Config.config_values.copy() self.values = Config.config_values.copy()
config = {} config = {}
if dirname is not None: if dirname is not None:
config['__file__'] = path.join(dirname, filename) config_file = path.join(dirname, filename)
config['__file__'] = config_file
config['tags'] = tags config['tags'] = tags
olddir = os.getcwd() olddir = os.getcwd()
try: try:
os.chdir(dirname) os.chdir(dirname)
execfile(config['__file__'], config) execfile(config['__file__'], config)
except SyntaxError, err:
raise ConfigError('There is a syntax error in your '
'configuration file: ' + str(err))
finally: finally:
os.chdir(olddir) os.chdir(olddir)
self._raw_config = config self._raw_config = config
# these two must be preinitialized because extensions can add their # these two must be preinitialized because extensions can add their
# own config values # own config values
self.setup = config.get('setup', None) self.setup = config.get('setup', None)
self.extensions = config.get('extensions', []) 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): def init_values(self):
config = self._raw_config config = self._raw_config
for valname, value in self.overrides.iteritems(): for valname, value in self.overrides.iteritems():

View File

@ -44,5 +44,9 @@ class ExtensionError(SphinxError):
return parent_str return parent_str
class ConfigError(SphinxError):
category = 'Configuration error'
class ThemeError(SphinxError): class ThemeError(SphinxError):
category = 'Theme error' category = 'Theme error'

View File

@ -24,7 +24,7 @@ from docutils import nodes
from docutils.parsers.rst import directives from docutils.parsers.rst import directives
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
@ -113,6 +113,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)
@ -129,10 +133,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))

View File

@ -32,6 +32,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+')

View File

@ -12,7 +12,8 @@
from util import * 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', @with_app(confoverrides={'master_doc': 'master', 'nonexisting_value': 'True',
@ -77,3 +78,19 @@ def test_extension_values(app):
'html_title', 'x', True) 'html_title', 'x', True)
raises_msg(ExtensionError, 'already present', app.add_config_value, raises_msg(ExtensionError, 'already present', app.add_config_value,
'value_from_ext', 'x', True) '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]