', re.MULTILINE)
doctestopt_re = re.compile(r'#\s*doctest:.+$', re.MULTILINE)
@@ -231,6 +233,8 @@ Results of doctest builder run on %s
self.info(text, nonl=True)
if self.app.quiet:
self.warn(text)
+ if isinstance(text, bytes):
+ text = force_decode(text, None)
self.outfile.write(text)
def get_target_uri(self, docname, typ=None):
@@ -375,8 +379,13 @@ Doctest summary
for code in group.tests:
if len(code) == 1:
# ordinary doctests (code/output interleaved)
- test = parser.get_doctest(code[0].code, {}, group.name,
- filename, code[0].lineno)
+ try:
+ test = parser.get_doctest(code[0].code, {}, group.name,
+ filename, code[0].lineno)
+ except Exception:
+ self.warn('ignoring invalid doctest code: %r' % code[0].code,
+ '%s:%s' % (filename, code[0].lineno))
+ continue
if not test.examples:
continue
for example in test.examples:
diff --git a/sphinx/ext/graphviz.py b/sphinx/ext/graphviz.py
index dc3b2623f..9c2012c78 100644
--- a/sphinx/ext/graphviz.py
+++ b/sphinx/ext/graphviz.py
@@ -298,14 +298,16 @@ def texinfo_visit_graphviz(self, node):
def text_visit_graphviz(self, node):
if 'alt' in node.attributes:
self.add_text(_('[graph: %s]') % node['alt'])
- self.add_text(_('[graph]'))
+ else:
+ self.add_text(_('[graph]'))
raise nodes.SkipNode
def man_visit_graphviz(self, node):
if 'alt' in node.attributes:
- self.body.append(_('[graph: %s]') % node['alt'] + '\n')
- self.body.append(_('[graph]'))
+ self.body.append(_('[graph: %s]') % node['alt'])
+ else:
+ self.body.append(_('[graph]'))
raise nodes.SkipNode
diff --git a/sphinx/ext/inheritance_diagram.py b/sphinx/ext/inheritance_diagram.py
index a2490486a..7dc57ab12 100644
--- a/sphinx/ext/inheritance_diagram.py
+++ b/sphinx/ext/inheritance_diagram.py
@@ -39,6 +39,7 @@ r"""
import re
import sys
import inspect
+import __builtin__
try:
from hashlib import md5
except ImportError:
@@ -142,7 +143,7 @@ class InheritanceGraph(object):
displayed node names.
"""
all_classes = {}
- builtins = __builtins__.values()
+ builtins = vars(__builtin__).values()
def recurse(cls):
if not show_builtins and cls in builtins:
diff --git a/sphinx/highlighting.py b/sphinx/highlighting.py
index bf21ac64a..2f61c1ef1 100644
--- a/sphinx/highlighting.py
+++ b/sphinx/highlighting.py
@@ -10,7 +10,6 @@
"""
import sys
-import cgi
import re
import textwrap
@@ -20,6 +19,7 @@ except ImportError:
# parser is not available on Jython
parser = None
+from sphinx.util.pycompat import htmlescape
from sphinx.util.texescape import tex_hl_escape_map_new
from sphinx.ext import doctest
@@ -105,7 +105,7 @@ class PygmentsBridge(object):
def unhighlighted(self, source):
if self.dest == 'html':
- return '' + cgi.escape(source) + '
\n'
+ return '' + htmlescape(source) + '
\n'
else:
# first, escape highlighting characters like Pygments does
source = source.translate(escape_hl_chars)
@@ -153,7 +153,7 @@ class PygmentsBridge(object):
else:
return True
- def highlight_block(self, source, lang, warn=None, **kwargs):
+ def highlight_block(self, source, lang, warn=None, force=False, **kwargs):
if not isinstance(source, unicode):
source = source.decode()
if not pygments:
@@ -164,12 +164,14 @@ class PygmentsBridge(object):
if source.startswith('>>>'):
# interactive session
lexer = lexers['pycon']
- else:
+ elif not force:
# maybe Python -- try parsing it
if self.try_parse(source):
lexer = lexers['python']
else:
return self.unhighlighted(source)
+ else:
+ lexer = lexers['python']
elif lang in ('python3', 'py3') and source.startswith('>>>'):
# for py3, recognize interactive sessions, but do not try parsing...
lexer = lexers['pycon3']
diff --git a/sphinx/setup_command.py b/sphinx/setup_command.py
index ebbcf27b8..c001b58ca 100644
--- a/sphinx/setup_command.py
+++ b/sphinx/setup_command.py
@@ -81,6 +81,7 @@ class BuildDoc(Command):
self.fresh_env = self.all_files = False
self.source_dir = self.build_dir = None
self.builder = 'html'
+ self.project = ''
self.version = ''
self.release = ''
self.today = ''
@@ -125,6 +126,8 @@ class BuildDoc(Command):
else:
status_stream = sys.stdout
confoverrides = {}
+ if self.project:
+ confoverrides['project'] = self.project
if self.version:
confoverrides['version'] = self.version
if self.release:
diff --git a/sphinx/util/inspect.py b/sphinx/util/inspect.py
index f5c8911da..b5c3db598 100644
--- a/sphinx/util/inspect.py
+++ b/sphinx/util/inspect.py
@@ -16,6 +16,7 @@ import sys
inspect = __import__('inspect')
from sphinx.util import force_decode
+from sphinx.util.pycompat import bytes
if sys.version_info >= (2, 5):
@@ -89,4 +90,6 @@ def safe_repr(object):
s = repr(object)
except Exception:
raise ValueError
- return force_decode(s, None).replace('\n', ' ')
+ if isinstance(s, bytes):
+ return force_decode(s, None).replace('\n', ' ')
+ return s.replace('\n', ' ')
diff --git a/sphinx/util/nodes.py b/sphinx/util/nodes.py
index c2b7edf4d..dbedb7f2f 100644
--- a/sphinx/util/nodes.py
+++ b/sphinx/util/nodes.py
@@ -179,8 +179,12 @@ def set_source_info(directive, node):
directive.state_machine.get_source_and_line(directive.lineno)
def set_role_source_info(inliner, lineno, node):
+ try:
node.source, node.line = \
inliner.reporter.locator(lineno)
+ except AttributeError:
+ # docutils 0.9+
+ node.source, node.line = inliner.reporter.get_source_and_line(lineno)
# monkey-patch Node.__contains__ to get consistent "in" operator behavior
# across docutils versions
diff --git a/sphinx/util/pycompat.py b/sphinx/util/pycompat.py
index cd9f6e2fc..9e081b02f 100644
--- a/sphinx/util/pycompat.py
+++ b/sphinx/util/pycompat.py
@@ -64,6 +64,11 @@ else:
return s.encode('ascii', 'backslashreplace')
+try:
+ from html import escape as htmlescape
+except ImportError:
+ from cgi import escape as htmlescape
+
# ------------------------------------------------------------------------------
# Missing builtins and itertools in Python < 2.6
diff --git a/sphinx/websupport/__init__.py b/sphinx/websupport/__init__.py
index 61b63cab2..72864a17b 100644
--- a/sphinx/websupport/__init__.py
+++ b/sphinx/websupport/__init__.py
@@ -9,7 +9,6 @@
:license: BSD, see LICENSE for details.
"""
-import cgi
import sys
import cPickle as pickle
import posixpath
@@ -22,6 +21,7 @@ from docutils.core import publish_parts
from sphinx.application import Sphinx
from sphinx.util.osutil import ensuredir
from sphinx.util.jsonimpl import dumps as dump_json
+from sphinx.util.pycompat import htmlescape
from sphinx.websupport import errors
from sphinx.websupport.search import BaseSearch, SEARCH_ADAPTERS
from sphinx.websupport.storage import StorageBackend
@@ -452,5 +452,5 @@ class WebSupport(object):
ret = publish_parts(text, writer_name='html',
settings_overrides=settings)['fragment']
except Exception:
- ret = cgi.escape(text)
+ ret = htmlescape(text)
return ret
diff --git a/sphinx/websupport/storage/differ.py b/sphinx/websupport/storage/differ.py
index 33fe54f34..fb3b8dc95 100644
--- a/sphinx/websupport/storage/differ.py
+++ b/sphinx/websupport/storage/differ.py
@@ -10,9 +10,10 @@
"""
import re
-from cgi import escape
from difflib import Differ
+from sphinx.util.pycompat import htmlescape
+
class CombinedHtmlDiff(object):
"""Create an HTML representation of the differences between two pieces
@@ -21,7 +22,7 @@ class CombinedHtmlDiff(object):
highlight_regex = re.compile(r'([\+\-\^]+)')
def __init__(self, source, proposal):
- proposal = escape(proposal)
+ proposal = htmlescape(proposal)
differ = Differ()
self.diff = list(differ.compare(source.splitlines(1),
diff --git a/sphinx/writers/html.py b/sphinx/writers/html.py
index 787b31059..b6e305f7a 100644
--- a/sphinx/writers/html.py
+++ b/sphinx/writers/html.py
@@ -65,6 +65,8 @@ class HTMLTranslator(BaseTranslator):
self.permalink_text = self.permalink_text and u'\u00B6' or ''
self.permalink_text = self.encode(self.permalink_text)
self.secnumber_suffix = builder.config.html_secnumber_suffix
+ self.param_separator = ''
+ self._table_row_index = 0
def visit_start_of_file(self, node):
# only occurs in the single-file builder
@@ -233,12 +235,13 @@ class HTMLTranslator(BaseTranslator):
lang = self.highlightlang
linenos = node.rawsource.count('\n') >= \
self.highlightlinenothreshold - 1
+ highlight_args = node.get('highlight_args', {})
if node.has_key('language'):
# code-block directives
lang = node['language']
+ highlight_args['force'] = True
if node.has_key('linenos'):
linenos = node['linenos']
- highlight_args = node.get('highlight_args', {})
def warner(msg):
self.builder.warn(msg, (self.builder.current_docname, node.line))
highlighted = self.highlighter.highlight_block(
diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py
index c9a5381e7..f2ebad360 100644
--- a/sphinx/writers/latex.py
+++ b/sphinx/writers/latex.py
@@ -1299,12 +1299,13 @@ class LaTeXTranslator(nodes.NodeVisitor):
code = self.verbatim.rstrip('\n')
lang = self.hlsettingstack[-1][0]
linenos = code.count('\n') >= self.hlsettingstack[-1][1] - 1
+ highlight_args = node.get('highlight_args', {})
if 'language' in node:
# code-block directives
lang = node['language']
+ highlight_args['force'] = True
if 'linenos' in node:
linenos = node['linenos']
- highlight_args = node.get('highlight_args', {})
def warner(msg):
self.builder.warn(msg, (self.curfilestack[-1], node.line))
hlcode = self.highlighter.highlight_block(code, lang, warn=warner,
diff --git a/tests/test_build_html.py b/tests/test_build_html.py
index 4e25167f3..a38806a86 100644
--- a/tests/test_build_html.py
+++ b/tests/test_build_html.py
@@ -258,7 +258,7 @@ if pygments:
r'def'),
(".//div[@class='inc-tab3 highlight-text']//pre",
r'-| |-'),
- (".//div[@class='inc-tab8 highlight-python']//pre",
+ (".//div[@class='inc-tab8 highlight-python']//pre/span",
r'-| |-'),
])
HTML_XPATH['subdir/includes.html'].extend([
@@ -328,7 +328,11 @@ def test_html(app):
for fname, paths in HTML_XPATH.iteritems():
parser = NslessParser()
parser.entity.update(htmlentitydefs.entitydefs)
- etree = ET.parse(os.path.join(app.outdir, fname), parser)
+ fp = open(os.path.join(app.outdir, fname))
+ try:
+ etree = ET.parse(fp, parser)
+ finally:
+ fp.close()
for path, check in paths:
yield check_xpath, etree, fname, path, check