summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorg Brandl <georg@python.org>2011-09-23 09:46:24 +0200
committerGeorg Brandl <georg@python.org>2011-09-23 09:46:24 +0200
commit6639612d9c5d7919bebce9790a2e3fbbfb6d3414 (patch)
treef139be5f44c251ed99b0d2a43afbd047d8d8f279
parent600b915d287a12ffdd68a29e15f9f10ff9461a67 (diff)
downloadsphinx-6639612d9c5d7919bebce9790a2e3fbbfb6d3414.tar.gz
Fix #648: Fix line numbers reported in warnings about undefined references.
-rw-r--r--CHANGES3
-rw-r--r--sphinx/directives/code.py6
-rw-r--r--sphinx/directives/other.py17
-rw-r--r--sphinx/domains/c.py5
-rw-r--r--sphinx/domains/cpp.py11
-rw-r--r--sphinx/domains/javascript.py5
-rw-r--r--sphinx/domains/python.py14
-rw-r--r--sphinx/domains/rst.py10
-rw-r--r--sphinx/domains/std.py5
-rw-r--r--sphinx/environment.py63
-rw-r--r--sphinx/ext/doctest.py3
-rw-r--r--sphinx/ext/extlinks.py8
-rw-r--r--sphinx/ext/ifconfig.py3
-rw-r--r--sphinx/ext/intersphinx.py2
-rw-r--r--sphinx/ext/mathbase.py3
-rw-r--r--sphinx/ext/oldcmarkup.py4
-rw-r--r--sphinx/ext/todo.py8
-rw-r--r--sphinx/roles.py4
-rw-r--r--sphinx/util/nodes.py28
-rw-r--r--tests/test_build_html.py4
20 files changed, 113 insertions, 93 deletions
diff --git a/CHANGES b/CHANGES
index 6e37d743..690354a6 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,9 @@
Release 1.0.8 (Sep 23, 2011)
============================
+* #648: Fix line numbers reported in warnings about undefined
+ references.
+
* #696, #666: Fix C++ array definitions and template arguments
that are not type names.
diff --git a/sphinx/directives/code.py b/sphinx/directives/code.py
index 6073a7de..ca2ea61b 100644
--- a/sphinx/directives/code.py
+++ b/sphinx/directives/code.py
@@ -17,6 +17,7 @@ from docutils.parsers.rst import Directive, directives
from sphinx import addnodes
from sphinx.util import parselinenos
+from sphinx.util.nodes import set_source_info
class Highlight(Directive):
@@ -64,7 +65,7 @@ class CodeBlock(Directive):
literal = nodes.literal_block(code, code)
literal['language'] = self.arguments[0]
literal['linenos'] = 'linenos' in self.options
- literal.line = self.lineno
+ set_source_info(self, literal)
return [literal]
@@ -186,8 +187,7 @@ class LiteralInclude(Directive):
if self.options.get('tab-width'):
text = text.expandtabs(self.options['tab-width'])
retnode = nodes.literal_block(text, text, source=fn)
- retnode.line = 1
- retnode.attributes['line_number'] = self.lineno
+ set_source_info(self, retnode)
if self.options.get('language', ''):
retnode['language'] = self.options['language']
if 'linenos' in self.options:
diff --git a/sphinx/directives/other.py b/sphinx/directives/other.py
index f59a29e1..606c559b 100644
--- a/sphinx/directives/other.py
+++ b/sphinx/directives/other.py
@@ -15,7 +15,7 @@ from docutils.parsers.rst import Directive, directives
from sphinx import addnodes
from sphinx.locale import pairindextypes, _
from sphinx.util import url_re, docname_join
-from sphinx.util.nodes import explicit_title_re
+from sphinx.util.nodes import explicit_title_re, set_source_info
from sphinx.util.compat import make_admonition
from sphinx.util.matching import patfilter
@@ -101,6 +101,7 @@ class TocTree(Directive):
subnode['hidden'] = 'hidden' in self.options
subnode['numbered'] = 'numbered' in self.options
subnode['titlesonly'] = 'titlesonly' in self.options
+ set_source_info(self, subnode)
wrappernode = nodes.compound(classes=['toctree-wrapper'])
wrappernode.append(subnode)
ret.append(wrappernode)
@@ -205,6 +206,7 @@ class VersionChange(Directive):
def run(self):
node = addnodes.versionmodified()
node.document = self.state.document
+ set_source_info(self, node)
node['type'] = self.name
node['version'] = self.arguments[0]
if len(self.arguments) == 2:
@@ -217,7 +219,8 @@ class VersionChange(Directive):
else:
ret = [node]
env = self.state.document.settings.env
- env.note_versionchange(node['type'], node['version'], node, self.lineno)
+ # XXX should record node.source as well
+ env.note_versionchange(node['type'], node['version'], node, node.line)
return ret
@@ -261,7 +264,7 @@ class TabularColumns(Directive):
def run(self):
node = addnodes.tabular_col_spec()
node['spec'] = self.arguments[0]
- node.line = self.lineno
+ set_source_info(self, node)
return [node]
@@ -360,7 +363,7 @@ class Only(Directive):
def run(self):
node = addnodes.only()
node.document = self.state.document
- node.line = self.lineno
+ set_source_info(self, node)
node['expr'] = self.arguments[0]
self.state.nested_parse(self.content, self.content_offset, node,
match_titles=1)
@@ -376,10 +379,10 @@ class Include(BaseInclude):
"""
def run(self):
- if self.arguments[0].startswith('/') or \
- self.arguments[0].startswith(os.sep):
+ path = self.arguments[0]
+ if path.startswith('/') or path.startswith(os.sep):
env = self.state.document.settings.env
- self.arguments[0] = os.path.join(env.srcdir, self.arguments[0][1:])
+ self.arguments[0] = os.path.join(env.srcdir, path[1:])
return BaseInclude.run(self)
diff --git a/sphinx/domains/c.py b/sphinx/domains/c.py
index 48fbb36f..253fd345 100644
--- a/sphinx/domains/c.py
+++ b/sphinx/domains/c.py
@@ -159,11 +159,10 @@ class CObject(ObjectDescription):
self.state.document.note_explicit_target(signode)
inv = self.env.domaindata['c']['objects']
if name in inv:
- self.env.warn(
- self.env.docname,
+ self.state_machine.reporter.warning(
'duplicate C object description of %s, ' % name +
'other instance in ' + self.env.doc2path(inv[name][0]),
- self.lineno)
+ line=self.lineno)
inv[name] = (self.env.docname, self.objtype)
indextext = self.get_index_text(name)
diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py
index ca984dab..2f9789fd 100644
--- a/sphinx/domains/cpp.py
+++ b/sphinx/domains/cpp.py
@@ -965,8 +965,7 @@ class CPPObject(ObjectDescription):
rv = self.parse_definition(parser)
parser.assert_end()
except DefinitionError, e:
- self.env.warn(self.env.docname,
- e.description, self.lineno)
+ self.state_machine.reporter.warning(e.description, line=self.lineno)
raise ValueError
self.describe_signature(signode, rv)
@@ -1111,8 +1110,8 @@ class CPPCurrentNamespace(Directive):
prefix = parser.parse_type()
parser.assert_end()
except DefinitionError, e:
- self.env.warn(self.env.docname,
- e.description, self.lineno)
+ self.state_machine.reporter.warning(e.description,
+ line=self.lineno)
else:
env.temp_data['cpp:prefix'] = prefix
return []
@@ -1186,9 +1185,7 @@ class CPPDomain(Domain):
if not parser.eof or expr is None:
raise DefinitionError('')
except DefinitionError:
- refdoc = node.get('refdoc', fromdocname)
- env.warn(refdoc, 'unparseable C++ definition: %r' % target,
- node.line)
+ env.warn_node('unparseable C++ definition: %r' % target, node)
return None
parent = node['cpp:parent']
diff --git a/sphinx/domains/javascript.py b/sphinx/domains/javascript.py
index e53eb5fd..80d25ad0 100644
--- a/sphinx/domains/javascript.py
+++ b/sphinx/domains/javascript.py
@@ -86,12 +86,11 @@ class JSObject(ObjectDescription):
self.state.document.note_explicit_target(signode)
objects = self.env.domaindata['js']['objects']
if fullname in objects:
- self.env.warn(
- self.env.docname,
+ self.state_machine.reporter.warning(
'duplicate object description of %s, ' % fullname +
'other instance in ' +
self.env.doc2path(objects[fullname][0]),
- self.lineno)
+ line=self.lineno)
objects[fullname] = self.env.docname, self.objtype
indextext = self.get_index_text(objectname, name_obj)
diff --git a/sphinx/domains/python.py b/sphinx/domains/python.py
index 73f0440e..e812b610 100644
--- a/sphinx/domains/python.py
+++ b/sphinx/domains/python.py
@@ -212,13 +212,12 @@ class PyObject(ObjectDescription):
self.state.document.note_explicit_target(signode)
objects = self.env.domaindata['py']['objects']
if fullname in objects:
- self.env.warn(
- self.env.docname,
+ self.state_machine.reporter.warning(
'duplicate object description of %s, ' % fullname +
'other instance in ' +
self.env.doc2path(objects[fullname][0]) +
', use :noindex: for one of them',
- self.lineno)
+ line=self.lineno)
objects[fullname] = (self.env.docname, self.objtype)
indextext = self.get_index_text(modname, name_cls)
@@ -648,11 +647,10 @@ class PythonDomain(Domain):
if not matches:
return None
elif len(matches) > 1:
- env.warn(fromdocname,
- 'more than one target found for cross-reference '
- '%r: %s' % (target,
- ', '.join(match[0] for match in matches)),
- node.line)
+ env.warn_node(
+ 'more than one target found for cross-reference '
+ '%r: %s' % (target, ', '.join(match[0] for match in matches)),
+ node)
name, obj = matches[0]
if obj[1] == 'module':
diff --git a/sphinx/domains/rst.py b/sphinx/domains/rst.py
index 6b3e05ee..770a6f6a 100644
--- a/sphinx/domains/rst.py
+++ b/sphinx/domains/rst.py
@@ -38,12 +38,10 @@ class ReSTMarkup(ObjectDescription):
objects = self.env.domaindata['rst']['objects']
key = (self.objtype, name)
if key in objects:
- self.env.warn(self.env.docname,
- 'duplicate description of %s %s, ' %
- (self.objtype, name) +
- 'other instance in ' +
- self.env.doc2path(objects[key]),
- self.lineno)
+ self.state_machine.reporter.warning(
+ 'duplicate description of %s %s, ' % (self.objtype, name) +
+ 'other instance in ' + self.env.doc2path(objects[key]),
+ line=self.lineno)
objects[key] = self.env.docname
indextext = self.get_index_text(self.objtype, name)
if indextext:
diff --git a/sphinx/domains/std.py b/sphinx/domains/std.py
index b9da29b8..389134cc 100644
--- a/sphinx/domains/std.py
+++ b/sphinx/domains/std.py
@@ -408,9 +408,8 @@ class StandardDomain(Domain):
# link and object descriptions
continue
if name in labels:
- env.warn(docname, 'duplicate label %s, ' % name +
- 'other instance in ' + env.doc2path(labels[name][0]),
- node.line)
+ env.warn_node('duplicate label %s, ' % name + 'other instance '
+ 'in ' + env.doc2path(labels[name][0]), node)
anonlabels[name] = docname, labelid
if node.tagname == 'section':
sectname = clean_astext(node[0]) # node[0] == title node
diff --git a/sphinx/environment.py b/sphinx/environment.py
index b2fb529f..465c8825 100644
--- a/sphinx/environment.py
+++ b/sphinx/environment.py
@@ -25,7 +25,7 @@ from itertools import izip, groupby
from docutils import nodes
from docutils.io import FileInput, NullOutput
from docutils.core import Publisher
-from docutils.utils import Reporter, relative_path
+from docutils.utils import Reporter, relative_path, get_source_line
from docutils.readers import standalone
from docutils.parsers.rst import roles, directives
from docutils.parsers.rst.languages import en as english
@@ -37,7 +37,7 @@ from docutils.transforms.parts import ContentsFilter
from sphinx import addnodes
from sphinx.util import url_re, get_matching_docs, docname_join, \
FilenameUniqDict
-from sphinx.util.nodes import clean_astext, make_refnode
+from sphinx.util.nodes import clean_astext, make_refnode, WarningStream
from sphinx.util.osutil import movefile, SEP, ustrftime
from sphinx.util.matching import compile_matchers
from sphinx.util.pycompat import all
@@ -76,14 +76,6 @@ default_substitutions = set([
dummy_reporter = Reporter('', 4, 4)
-class WarningStream(object):
- def __init__(self, warnfunc):
- self.warnfunc = warnfunc
- def write(self, text):
- if text.strip():
- self.warnfunc(text, None, '')
-
-
class NoUri(Exception):
"""Raised by get_relative_uri if there is no URI available."""
pass
@@ -342,6 +334,9 @@ class BuildEnvironment:
# strange argument order is due to backwards compatibility
self._warnfunc(msg, (docname, lineno))
+ def warn_node(self, msg, node):
+ self._warnfunc(msg, '%s:%s' % get_source_line(node))
+
def clear_doc(self, docname):
"""Remove all traces of a source file in the inventory."""
if docname in self.all_docs:
@@ -792,8 +787,8 @@ class BuildEnvironment:
filepath = path.normpath(path.join(docdir, node['reftarget']))
self.dependencies.setdefault(docname, set()).add(filepath)
if not os.access(path.join(self.srcdir, filepath), os.R_OK):
- self.warn(docname, 'download file not readable: %s' % filepath,
- getattr(node, 'line', None))
+ self.warn_node('download file not readable: %s' % filepath,
+ node)
continue
uniquename = self.dlfiles.add_file(docname, filepath)
node['filename'] = uniquename
@@ -811,8 +806,7 @@ class BuildEnvironment:
node['candidates'] = candidates = {}
imguri = node['uri']
if imguri.find('://') != -1:
- self.warn(docname, 'nonlocal image URI found: %s' % imguri,
- node.line)
+ self.warn_node('nonlocal image URI found: %s' % imguri, node)
candidates['?'] = imguri
continue
# imgpath is the image path *from srcdir*
@@ -838,9 +832,8 @@ class BuildEnvironment:
finally:
f.close()
except (OSError, IOError), err:
- self.warn(docname, 'image file %s not '
- 'readable: %s' % (filename, err),
- node.line)
+ self.warn_node('image file %s not readable: %s' %
+ (filename, err), node)
if imgtype:
candidates['image/' + imgtype] = new_imgpath
else:
@@ -850,8 +843,8 @@ class BuildEnvironment:
for imgpath in candidates.itervalues():
self.dependencies.setdefault(docname, set()).add(imgpath)
if not os.access(path.join(self.srcdir, imgpath), os.R_OK):
- self.warn(docname, 'image file not readable: %s' % imgpath,
- node.line)
+ self.warn_node('image file not readable: %s' % imgpath,
+ node)
continue
self.images.add_file(docname, imgpath)
@@ -974,9 +967,9 @@ class BuildEnvironment:
for node in document.traverse(nodes.citation):
label = node[0].astext()
if label in self.citations:
- self.warn(docname, 'duplicate citation %s, ' % label +
- 'other instance in %s' % self.doc2path(
- self.citations[label][0]), node.line)
+ self.warn_node('duplicate citation %s, ' % label +
+ 'other instance in %s' % self.doc2path(
+ self.citations[label][0]), node)
self.citations[label] = (docname, node['ids'][0])
def note_toctree(self, docname, toctreenode):
@@ -1243,15 +1236,15 @@ class BuildEnvironment:
refnode.children = [nodes.Text(title)]
if not toc.children:
# empty toc means: no titles will show up in the toctree
- self.warn(docname,
- 'toctree contains reference to document '
- '%r that doesn\'t have a title: no link '
- 'will be generated' % ref, toctreenode.line)
+ self.warn_node(
+ 'toctree contains reference to document %r that '
+ 'doesn\'t have a title: no link will be generated'
+ % ref, toctreenode)
except KeyError:
# this is raised if the included file does not exist
- self.warn(docname, 'toctree contains reference to '
- 'nonexisting document %r' % ref,
- toctreenode.line)
+ self.warn_node(
+ 'toctree contains reference to nonexisting document %r'
+ % ref, toctreenode)
else:
# if titles_only is given, only keep the main title and
# sub-toctrees
@@ -1332,8 +1325,7 @@ class BuildEnvironment:
# can be absolute or relative
docname = docname_join(refdoc, target)
if docname not in self.all_docs:
- self.warn(refdoc,
- 'unknown document: %s' % docname, node.line)
+ self.warn_node('unknown document: %s' % docname, node)
warned = True
else:
if node['refexplicit']:
@@ -1349,8 +1341,7 @@ class BuildEnvironment:
elif typ == 'citation':
docname, labelid = self.citations.get(target, ('', ''))
if not docname:
- self.warn(refdoc,
- 'citation not found: %s' % target, node.line)
+ self.warn_node('citation not found: %s' % target, node)
warned = True
else:
newnode = make_refnode(builder, fromdocname, docname,
@@ -1370,7 +1361,7 @@ class BuildEnvironment:
else:
msg = '%s reference target not found: ' \
'%%(target)s' % typ
- self.warn(refdoc, msg % {'target': target}, node.line)
+ self.warn_node(msg % {'target': target}, node)
except NoUri:
newnode = contnode
node.replace_self(newnode or contnode)
@@ -1379,8 +1370,8 @@ class BuildEnvironment:
try:
ret = builder.tags.eval_condition(node['expr'])
except Exception, err:
- self.warn(fromdocname, 'exception while evaluating only '
- 'directive expression: %s' % err, node.line)
+ self.warn_node('exception while evaluating only '
+ 'directive expression: %s' % err, node)
node.replace_self(node.children)
else:
if ret:
diff --git a/sphinx/ext/doctest.py b/sphinx/ext/doctest.py
index dcee09f5..a981b9bc 100644
--- a/sphinx/ext/doctest.py
+++ b/sphinx/ext/doctest.py
@@ -23,6 +23,7 @@ from docutils import nodes
from docutils.parsers.rst import directives
from sphinx.builders import Builder
+from sphinx.util.nodes import set_source_info
from sphinx.util.compat import Directive
from sphinx.util.console import bold
@@ -63,7 +64,7 @@ class TestDirective(Directive):
else:
groups = ['default']
node = nodetype(code, code, testnodetype=self.name, groups=groups)
- node.line = self.lineno
+ set_source_info(self, node)
if test is not None:
# only save if it differs from code
node['test'] = test
diff --git a/sphinx/ext/extlinks.py b/sphinx/ext/extlinks.py
index 910354a2..9f60cded 100644
--- a/sphinx/ext/extlinks.py
+++ b/sphinx/ext/extlinks.py
@@ -36,10 +36,10 @@ def make_link_role(base_url, prefix):
try:
full_url = base_url % part
except (TypeError, ValueError):
- env = inliner.document.settings.env
- env.warn(env.docname, 'unable to expand %s extlink with base '
- 'URL %r, please make sure the base contains \'%%s\' '
- 'exactly once' % (typ, base_url))
+ inliner.reporter.warning(
+ 'unable to expand %s extlink with base URL %r, please make '
+ 'sure the base contains \'%%s\' exactly once'
+ % (typ, base_url), line=lineno)
full_url = base_url + part
if not has_explicit_title:
if prefix is None:
diff --git a/sphinx/ext/ifconfig.py b/sphinx/ext/ifconfig.py
index 5698ca28..50c7bbef 100644
--- a/sphinx/ext/ifconfig.py
+++ b/sphinx/ext/ifconfig.py
@@ -22,6 +22,7 @@
from docutils import nodes
+from sphinx.util.nodes import set_source_info
from sphinx.util.compat import Directive
@@ -39,7 +40,7 @@ class IfConfig(Directive):
def run(self):
node = ifconfig()
node.document = self.state.document
- node.line = self.lineno
+ set_source_info(self, node)
node['expr'] = self.arguments[0]
self.state.nested_parse(self.content, self.content_offset,
node, match_titles=1)
diff --git a/sphinx/ext/intersphinx.py b/sphinx/ext/intersphinx.py
index 64a747c9..4e1ca980 100644
--- a/sphinx/ext/intersphinx.py
+++ b/sphinx/ext/intersphinx.py
@@ -151,7 +151,7 @@ def load_mappings(app):
# new format
name, (uri, inv) = key, value
if not name.isalnum():
- env.warn('intersphinx identifier %r is not alphanumeric' % name)
+ app.warn('intersphinx identifier %r is not alphanumeric' % name)
else:
# old format, no name
name, uri, inv = None, key, value
diff --git a/sphinx/ext/mathbase.py b/sphinx/ext/mathbase.py
index e7ea82d7..fc849584 100644
--- a/sphinx/ext/mathbase.py
+++ b/sphinx/ext/mathbase.py
@@ -12,6 +12,7 @@
from docutils import nodes, utils
from docutils.parsers.rst import directives
+from sphinx.util.nodes import set_source_info
from sphinx.util.compat import Directive
@@ -69,7 +70,7 @@ class MathDirective(Directive):
node['nowrap'] = 'nowrap' in self.options
node['docname'] = self.state.document.settings.env.docname
ret = [node]
- node.line = self.lineno
+ set_source_info(self, node)
if hasattr(self, 'src'):
node.source = self.src
if node['label']:
diff --git a/sphinx/ext/oldcmarkup.py b/sphinx/ext/oldcmarkup.py
index 2bf9b65d..cfc95ba4 100644
--- a/sphinx/ext/oldcmarkup.py
+++ b/sphinx/ext/oldcmarkup.py
@@ -31,7 +31,7 @@ class OldCDirective(Directive):
def run(self):
env = self.state.document.settings.env
if not env.app._oldcmarkup_warned:
- env.warn(env.docname, WARNING_MSG, self.lineno)
+ self.state_machine.reporter.warning(WARNING_MSG, line=self.lineno)
env.app._oldcmarkup_warned = True
newname = 'c:' + self.name[1:]
newdir = env.lookup_domain_element('directive', newname)[0]
@@ -45,7 +45,7 @@ def old_crole(typ, rawtext, text, lineno, inliner, options={}, content=[]):
if not typ:
typ = env.config.default_role
if not env.app._oldcmarkup_warned:
- env.warn(env.docname, WARNING_MSG)
+ inliner.reporter.warning(WARNING_MSG, line=lineno)
env.app._oldcmarkup_warned = True
newtyp = 'c:' + typ[1:]
newrole = env.lookup_domain_element('role', newtyp)[0]
diff --git a/sphinx/ext/todo.py b/sphinx/ext/todo.py
index 2ba9d5e1..c18d70c8 100644
--- a/sphinx/ext/todo.py
+++ b/sphinx/ext/todo.py
@@ -16,6 +16,7 @@ from docutils import nodes
from sphinx.locale import _
from sphinx.environment import NoUri
+from sphinx.util.nodes import set_source_info
from sphinx.util.compat import Directive, make_admonition
class todo_node(nodes.Admonition, nodes.Element): pass
@@ -41,7 +42,7 @@ class Todo(Directive):
ad = make_admonition(todo_node, self.name, [_('Todo')], self.options,
self.content, self.lineno, self.content_offset,
self.block_text, self.state, self.state_machine)
- ad[0].line = self.lineno
+ set_source_info(self, ad[0])
return [targetnode] + ad
@@ -61,6 +62,7 @@ def process_todos(app, doctree):
targetnode = None
env.todo_all_todos.append({
'docname': env.docname,
+ 'source': node.source or env.doc2path(env.docname),
'lineno': node.line,
'todo': node.deepcopy(),
'target': targetnode,
@@ -105,9 +107,9 @@ def process_todo_nodes(app, doctree, fromdocname):
for todo_info in env.todo_all_todos:
para = nodes.paragraph(classes=['todo-source'])
- filename = env.doc2path(todo_info['docname'], base=None)
description = _('(The <<original entry>> is located in '
- ' %s, line %d.)') % (filename, todo_info['lineno'])
+ ' %s, line %d.)') % \
+ (todo_info['source'], todo_info['lineno'])
desc1 = description[:description.find('<<')]
desc2 = description[description.find('>>')+2:]
para += nodes.Text(desc1, desc1)
diff --git a/sphinx/roles.py b/sphinx/roles.py
index 32d02da1..e3d41299 100644
--- a/sphinx/roles.py
+++ b/sphinx/roles.py
@@ -18,7 +18,7 @@ from docutils.parsers.rst import roles
from sphinx import addnodes
from sphinx.locale import _
from sphinx.util import ws_re
-from sphinx.util.nodes import split_explicit_title
+from sphinx.util.nodes import split_explicit_title, set_role_source_info
generic_docroles = {
@@ -126,7 +126,7 @@ class XRefRole(object):
refnode = self.nodeclass(rawtext, reftype=role, refdomain=domain,
refexplicit=has_explicit_title)
# we may need the line number for warnings
- refnode.line = lineno
+ set_role_source_info(inliner, lineno, refnode)
title, target = self.process_link(
env, refnode, has_explicit_title, title, target)
# now that the target and title are finally determined, set them
diff --git a/sphinx/util/nodes.py b/sphinx/util/nodes.py
index fd6a2f83..b7b5073d 100644
--- a/sphinx/util/nodes.py
+++ b/sphinx/util/nodes.py
@@ -13,10 +13,23 @@ import re
import types
from docutils import nodes
+from docutils.statemachine import StateMachine
from sphinx import addnodes
+class WarningStream(object):
+
+ def __init__(self, warnfunc):
+ self.warnfunc = warnfunc
+ self._re = re.compile(r'\((DEBUG|INFO|WARNING|ERROR|SEVERE)/[0-4]\)')
+
+ def write(self, text):
+ text = text.strip()
+ if text:
+ self.warnfunc(self._re.sub(r'\1:', text), None, '')
+
+
# \x00 means the "<" was backslash-escaped
explicit_title_re = re.compile(r'^(.+?)\s*(?<!\x00)<(.*?)>$', re.DOTALL)
caption_ref_re = explicit_title_re # b/w compat alias
@@ -91,6 +104,21 @@ def make_refnode(builder, fromdocname, todocname, targetid, child, title=None):
node.append(child)
return node
+
+if hasattr(StateMachine, 'get_source_and_line'):
+ def set_source_info(directive, node):
+ node.source, node.line = \
+ directive.state_machine.get_source_and_line(directive.lineno)
+ def set_role_source_info(inliner, lineno, node):
+ node.source, node.line = \
+ inliner.reporter.locator(lineno)
+else:
+ # docutils <= 0.6 compatibility
+ def set_source_info(directive, node):
+ node.line = directive.lineno
+ def set_role_source_info(inliner, lineno, node):
+ node.line = lineno
+
# monkey-patch Node.traverse to get more speed
# traverse() is called so many times during a build that it saves
# on average 20-25% overall build time!
diff --git a/tests/test_build_html.py b/tests/test_build_html.py
index 638dc4af..93aa41d4 100644
--- a/tests/test_build_html.py
+++ b/tests/test_build_html.py
@@ -32,12 +32,12 @@ html_warnfile = StringIO()
ENV_WARNINGS = """\
%(root)s/autodoc_fodder.py:docstring of autodoc_fodder\\.MarkupError:2: \
-\\(WARNING/2\\) Explicit markup ends without a blank line; unexpected \
+WARNING: Explicit markup ends without a blank line; unexpected \
unindent\\.\\n?
%(root)s/images.txt:9: WARNING: image file not readable: foo.png
%(root)s/images.txt:23: WARNING: nonlocal image URI found: \
http://www.python.org/logo.png
-%(root)s/includes.txt:\\d*: \\(WARNING/2\\) Encoding 'utf-8-sig' used for \
+%(root)s/includes.txt:\\d*: WARNING: Encoding 'utf-8-sig' used for \
reading included file u'.*?wrongenc.inc' seems to be wrong, try giving an \
:encoding: option\\n?
%(root)s/includes.txt:4: WARNING: download file not readable: nonexisting.png