diff --git a/CHANGES b/CHANGES index e165f2912..7209b3b5d 100644 --- a/CHANGES +++ b/CHANGES @@ -120,6 +120,14 @@ New features added Release 0.5.2 (in development) ============================== +* Use a new RFC base URL, since rfc.org seems down. + +* Fix a crash in the todolist directive when no todo items are + defined. + +* Don't call LaTeX or dvipng over and over again if it was not + found once, and use text-only latex as a substitute in that case. + * Fix problems with footnotes in the LaTeX output. * Prevent double hyphens becoming en-dashes in literal code in diff --git a/sphinx/application.py b/sphinx/application.py index 6840629db..b59a9353b 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -18,14 +18,8 @@ from cStringIO import StringIO from docutils import nodes from docutils.parsers.rst import directives, roles -import sphinx -from sphinx.roles import xfileref_role, innernodetypes -from sphinx.config import Config -from sphinx.builders import BUILTIN_BUILDERS -from sphinx.directives import desc_directive, target_directive, additional_xref_types -from sphinx.environment import SphinxStandaloneReader -from sphinx.util.console import bold - +# create the error classes before importing the rest of Sphinx, so that +# they can be imported in a circular fashion class SphinxError(Exception): """ @@ -55,6 +49,15 @@ class ExtensionError(SphinxError): return parent_str +import sphinx +from sphinx.roles import xfileref_role, innernodetypes +from sphinx.config import Config +from sphinx.builders import BUILTIN_BUILDERS +from sphinx.directives import desc_directive, target_directive, additional_xref_types +from sphinx.environment import SphinxStandaloneReader +from sphinx.util.console import bold + + # List of all known core events. Maps name to arguments description. events = { 'builder-inited': '', diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py index 0b2946ae5..3b3abaa8b 100644 --- a/sphinx/builders/html.py +++ b/sphinx/builders/html.py @@ -26,6 +26,7 @@ from sphinx.util import SEP, os_path, relative_uri, ensuredir, \ movefile, ustrftime from sphinx.search import js_index from sphinx.builders import Builder, ENV_PICKLE_FILENAME +from sphinx.application import SphinxError from sphinx.highlighting import PygmentsBridge from sphinx.util.console import bold from sphinx.writers.html import HTMLWriter, HTMLTranslator, SmartyPantsHTMLTranslator @@ -631,7 +632,6 @@ class JSONHTMLBuilder(SerializingHTMLBuilder): def init(self): if json is None: - from sphinx.application import SphinxError raise SphinxError('The module simplejson (or json in Python >= 2.6) ' 'is not available. The JSONHTMLBuilder builder ' 'will not work.') diff --git a/sphinx/environment.py b/sphinx/environment.py index fccecf07c..36009f80a 100644 --- a/sphinx/environment.py +++ b/sphinx/environment.py @@ -46,12 +46,13 @@ from sphinx import addnodes from sphinx.util import movefile, get_matching_docs, SEP, ustrftime, \ docname_join, FilenameUniqDict, url_re from sphinx.directives import additional_xref_types +from sphinx.application import SphinxError default_settings = { 'embed_stylesheet': False, 'cloak_email_addresses': True, 'pep_base_url': 'http://www.python.org/dev/peps/', - 'rfc_base_url': 'http://rfc.net/', + 'rfc_base_url': 'http://tools.ietf.org/html/', 'input_encoding': 'utf-8', 'doctitle_xform': False, 'sectsubtitle_xform': False, @@ -545,7 +546,6 @@ class BuildEnvironment: pub.publish() doctree = pub.document except UnicodeError, err: - from sphinx.application import SphinxError raise SphinxError(str(err)) self.filter_messages(doctree) self.process_dependencies(docname, doctree) diff --git a/sphinx/ext/pngmath.py b/sphinx/ext/pngmath.py index dc1d2ee8d..5b7f280a5 100644 --- a/sphinx/ext/pngmath.py +++ b/sphinx/ext/pngmath.py @@ -82,6 +82,11 @@ def render_math(self, math): depth = read_png_depth(outfn) return relfn, depth + # if latex or dvipng has failed once, don't bother to try again + if hasattr(self.builder, '_mathpng_warned_latex') or \ + hasattr(self.builder, '_mathpng_warned_dvipng'): + return None, None + latex = DOC_HEAD + self.builder.config.pngmath_latex_preamble latex += (use_preview and DOC_BODY_PREVIEW or DOC_BODY) % math if isinstance(latex, unicode): @@ -116,12 +121,11 @@ def render_math(self, math): except OSError, err: if err.errno != 2: # No such file or directory raise - if not hasattr(self.builder, '_mathpng_warned_latex'): - self.builder.warn('LaTeX command %r cannot be run (needed for math ' - 'display), check the pngmath_latex setting' % - self.builder.config.pngmath_latex) - self.builder._mathpng_warned_latex = True - return relfn, None + self.builder.warn('LaTeX command %r cannot be run (needed for math ' + 'display), check the pngmath_latex setting' % + self.builder.config.pngmath_latex) + self.builder._mathpng_warned_latex = True + return None, None finally: chdir(curdir) @@ -145,12 +149,11 @@ def render_math(self, math): except OSError, err: if err.errno != 2: # No such file or directory raise - if not hasattr(self.builder, '_mathpng_warned_dvipng'): - self.builder.warn('dvipng command %r cannot be run (needed for math ' - 'display), check the pngmath_dvipng setting' % - self.builder.config.pngmath_dvipng) - self.builder._mathpng_warned_dvipng = True - return relfn, None + self.builder.warn('dvipng command %r cannot be run (needed for math ' + 'display), check the pngmath_dvipng setting' % + self.builder.config.pngmath_dvipng) + self.builder._mathpng_warned_dvipng = True + return None, None stdout, stderr = p.communicate() if p.returncode != 0: raise MathExtError('dvipng exited with error:\n[stderr]\n%s\n[stdout]\n%s' @@ -185,9 +188,15 @@ def html_visit_math(self, node): sm.walkabout(self) self.builder.warn('display latex %r: ' % node['latex'] + str(exc)) raise nodes.SkipNode - self.body.append('%s' % - (fname, self.encode(node['latex']).strip(), - depth and 'style="vertical-align: %dpx" ' % (-depth) or '')) + if fname is None: + # something failed -- use text-only as a bad substitute + self.body.append('%s' % + self.encode(node['latex']).strip()) + else: + self.body.append( + '%s' % + (fname, self.encode(node['latex']).strip(), + depth and 'style="vertical-align: %dpx" ' % (-depth) or '')) raise nodes.SkipNode def html_visit_displaymath(self, node): @@ -207,8 +216,13 @@ def html_visit_displaymath(self, node): self.body.append('

') if node['number']: self.body.append('(%s)' % node['number']) - self.body.append('%s\n' % - (fname, self.encode(node['latex']).strip())) + if fname is None: + # something failed -- use text-only as a bad substitute + self.body.append('%s' % + self.encode(node['latex']).strip()) + else: + self.body.append('%s\n' % + (fname, self.encode(node['latex']).strip())) self.body.append('

') raise nodes.SkipNode diff --git a/sphinx/ext/todo.py b/sphinx/ext/todo.py index dac906604..c8c6412ce 100644 --- a/sphinx/ext/todo.py +++ b/sphinx/ext/todo.py @@ -61,6 +61,9 @@ def process_todo_nodes(app, doctree, fromdocname): # Augment each todo with a backlink to the original location. env = app.builder.env + if not hasattr(env, 'todo_all_todos'): + env.todo_all_todos = [] + for node in doctree.traverse(todolist): if not app.config['todo_include_todos']: node.replace_self([]) diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 9af682286..e1fbea133 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -22,6 +22,7 @@ from docutils.writers.latex2e import Babel from sphinx import addnodes from sphinx import highlighting from sphinx.locale import admonitionlabels, versionlabels +from sphinx.application import SphinxError from sphinx.util import ustrftime from sphinx.util.texescape import tex_escape_map from sphinx.util.smartypants import educateQuotesLatex @@ -65,6 +66,9 @@ FOOTER = r''' class collected_footnote(nodes.footnote): """Footnotes that are collected are assigned this class.""" +class UnsupportedError(SphinxError): + category = 'Markup is unsupported in LaTeX' + class LaTeXWriter(writers.Writer): @@ -210,6 +214,7 @@ class LaTeXTranslator(nodes.NodeVisitor): self.highlightlinenothreshold = sys.maxint self.written_ids = set() self.footnotestack = [] + self.curfilestack = [] if self.elements['docclass'] == 'manual': if builder.config.latex_use_parts: self.top_sectionlevel = 0 @@ -234,6 +239,7 @@ class LaTeXTranslator(nodes.NodeVisitor): def visit_document(self, node): self.footnotestack.append(self.collect_footnotes(node)) + self.curfilestack.append(node['file']) if self.first_document == 1: # the first document is all the regular content ... self.body.append(BEGIN_DOC % self.elements) @@ -268,6 +274,7 @@ class LaTeXTranslator(nodes.NodeVisitor): self.footnotestack.append(self.collect_footnotes(node)) # also add a document target self.body.append('\\hypertarget{--doc-%s}{}' % node['docname']) + self.curfilestack.append(node['file']) def collect_footnotes(self, node): fnotes = {} @@ -287,6 +294,7 @@ class LaTeXTranslator(nodes.NodeVisitor): def depart_start_of_file(self, node): self.footnotestack.pop() + self.curfilestack.pop() def visit_highlightlang(self, node): self.highlightlang = node['lang'] @@ -366,9 +374,10 @@ class LaTeXTranslator(nodes.NodeVisitor): try: self.body.append(r'\%s{' % self.sectionnames[self.sectionlevel]) except IndexError: - from sphinx.application import SphinxError - raise SphinxError('too many nesting section levels for LaTeX, ' - 'at heading: %s' % node.astext()) + raise UnsupportedError( + '%s:%s: too many nesting section levels for ' + 'LaTeX, at heading: %s' % (self.curfilestack[-1], + node.line or '', node.astext())) self.context.append('}\n') elif isinstance(parent, (nodes.topic, nodes.sidebar)): self.body.append(r'\textbf{') @@ -570,7 +579,8 @@ class LaTeXTranslator(nodes.NodeVisitor): def visit_table(self, node): if self.table: - raise NotImplementedError('Nested tables are not supported.') + raise UnsupportedError('%s:%s: nested tables are not yet implemented.' % + (self.curfilestack[-1], node.line or '')) self.table = Table() self.tablebody = [] # Redirect body output until table is finished. @@ -636,8 +646,9 @@ class LaTeXTranslator(nodes.NodeVisitor): def visit_entry(self, node): if node.has_key('morerows') or node.has_key('morecols'): - raise NotImplementedError('Column or row spanning cells are ' - 'not implemented.') + raise UnsupportedError('%s:%s: column or row spanning cells are ' + 'not yet implemented.' % + (self.curfilestack[-1], node.line or '')) if self.table.col > 0: self.body.append(' & ') self.table.col += 1