logger.warning() supports node as location parameter

This commit is contained in:
Takeshi KOMIYA 2016-12-27 02:13:56 +09:00
parent e755a8c004
commit 15b46598e2
15 changed files with 77 additions and 84 deletions

View File

@ -161,8 +161,8 @@ class Builder(object):
if candidate:
break
else:
logger.warn_node('no matching candidate for image URI %r' % node['uri'],
node)
logger.warning('no matching candidate for image URI %r', node['uri'],
location=node)
continue
node['uri'] = candidate
else:

View File

@ -4885,7 +4885,7 @@ class CPPDomain(Domain):
class Warner(object):
def warn(self, msg):
if emitWarnings:
logger.warn_node(msg, node)
logger.warning(msg, location=node)
warner = Warner()
parser = DefinitionParser(target, warner, env.config)
try:

View File

@ -787,10 +787,9 @@ class PythonDomain(Domain):
if not matches:
return None
elif len(matches) > 1:
logger.warn_node(
'more than one target found for cross-reference '
'%r: %s' % (target, ', '.join(match[0] for match in matches)),
node)
logger.warning('more than one target found for cross-reference %r: %s',
target, ', '.join(match[0] for match in matches),
location=node)
name, obj = matches[0]
if obj[1] == 'module':

View File

@ -573,8 +573,8 @@ class StandardDomain(Domain):
label = node[0].astext()
if label in self.data['citations']:
path = env.doc2path(self.data['citations'][label][0])
logger.warn_node('duplicate citation %s, other instance in %s' %
(label, path), node)
logger.warning('duplicate citation %s, other instance in %s', label, path,
location=node)
self.data['citations'][label] = (docname, node['ids'][0])
def note_labels(self, env, docname, document):
@ -596,8 +596,9 @@ class StandardDomain(Domain):
# link and object descriptions
continue
if name in labels:
logger.warn_node('duplicate label %s, ' % name + 'other instance '
'in ' + env.doc2path(labels[name][0]), node)
logger.warning('duplicate label %s, ' % name + 'other instance '
'in ' + env.doc2path(labels[name][0]),
location=node)
anonlabels[name] = docname, labelid
if node.tagname == 'section':
sectname = clean_astext(node[0]) # node[0] == title node
@ -688,7 +689,7 @@ class StandardDomain(Domain):
return None
if env.config.numfig is False:
logger.warn_node('numfig is disabled. :numref: is ignored.', node)
logger.warning('numfig is disabled. :numref: is ignored.', location=node)
return contnode
target_node = env.get_doctree(docname).ids.get(labelid)
@ -701,7 +702,8 @@ class StandardDomain(Domain):
if fignumber is None:
return contnode
except ValueError:
logger.warn_node("no number is assigned for %s: %s" % (figtype, labelid), node)
logger.warning("no number is assigned for %s: %s", figtype, labelid,
location=node)
return contnode
try:
@ -711,7 +713,7 @@ class StandardDomain(Domain):
title = env.config.numfig_format.get(figtype, '')
if figname is None and '%{name}' in title:
logger.warn_node('the link has no caption: %s' % title, node)
logger.warning('the link has no caption: %s', title, location=node)
return contnode
else:
fignum = '.'.join(map(str, fignumber))
@ -725,10 +727,10 @@ class StandardDomain(Domain):
# old style format (cf. "Fig.%s")
newtitle = title % fignum
except KeyError as exc:
logger.warn_node('invalid numfig_format: %s (%r)' % (title, exc), node)
logger.warning('invalid numfig_format: %s (%r)', title, exc, location=node)
return contnode
except TypeError:
logger.warn_node('invalid numfig_format: %s' % title, node)
logger.warning('invalid numfig_format: %s', title, location=node)
return contnode
return self.build_reference_node(fromdocname, builder,

View File

@ -902,8 +902,8 @@ class BuildEnvironment(object):
rel_filename, filename = self.relfn2path(targetname, docname)
self.dependencies[docname].add(rel_filename)
if not os.access(filename, os.R_OK):
logger.warn_node('download file not readable: %s' % filename,
node)
logger.warning('download file not readable: %s', filename,
location=node)
continue
uniquename = self.dlfiles.add_file(docname, filename)
node['filename'] = uniquename
@ -921,8 +921,8 @@ class BuildEnvironment(object):
if mimetype not in candidates:
globbed.setdefault(mimetype, []).append(new_imgpath)
except (OSError, IOError) as err:
logger.warn_node('image file %s not readable: %s' %
(filename, err), node)
logger.warning('image file %s not readable: %s', filename, err,
location=node)
for key, files in iteritems(globbed):
candidates[key] = sorted(files, key=len)[0] # select by similarity
@ -934,13 +934,13 @@ class BuildEnvironment(object):
node['candidates'] = candidates = {}
imguri = node['uri']
if imguri.startswith('data:'):
logger.warn_node('image data URI found. some builders might not support', node,
type='image', subtype='data_uri')
logger.warning('image data URI found. some builders might not support',
location=node, type='image', subtype='data_uri')
candidates['?'] = imguri
continue
elif imguri.find('://') != -1:
logger.warn_node('nonlocal image URI found: %s' % imguri, node,
type='image', subtype='nonlocal_uri')
logger.warning('nonlocal image URI found: %s', imguri,
location=node, type='image', subtype='nonlocal_uri')
candidates['?'] = imguri
continue
rel_imgpath, full_imgpath = self.relfn2path(imguri, docname)
@ -969,8 +969,8 @@ class BuildEnvironment(object):
for imgpath in itervalues(candidates):
self.dependencies[docname].add(imgpath)
if not os.access(path.join(self.srcdir, imgpath), os.R_OK):
logger.warn_node('image file not readable: %s' % imgpath,
node)
logger.warning('image file not readable: %s', imgpath,
location=node)
continue
self.images.add_file(docname, imgpath)
@ -1183,7 +1183,8 @@ class BuildEnvironment(object):
(node['refdomain'], typ)
else:
msg = '%r reference target not found: %%(target)s' % typ
logger.warn_node(msg % {'target': target}, node, type='ref', subtype=typ)
logger.warning(msg % {'target': target},
location=node, type='ref', subtype=typ)
def _resolve_doc_reference(self, builder, refdoc, node, contnode):
# type: (Builder, unicode, nodes.Node, nodes.Node) -> nodes.Node
@ -1234,9 +1235,9 @@ class BuildEnvironment(object):
return None
if len(results) > 1:
nice_results = ' or '.join(':%s:' % r[0] for r in results)
logger.warn_node('more than one target found for \'any\' cross-'
'reference %r: could be %s' % (target, nice_results),
node)
logger.warning('more than one target found for \'any\' cross-'
'reference %r: could be %s', target, nice_results,
location=node)
res_role, newnode = results[0]
# Override "any" class with the actual role type to get the styling
# approximately correct.

View File

@ -55,7 +55,7 @@ class IndexEntries(EnvironmentManager):
for entry in node['entries']:
split_index_msg(entry[0], entry[1])
except ValueError as exc:
logger.warn_node(str(exc), node)
logger.warning(str(exc), location=node)
node.parent.remove(node)
else:
for entry in node['entries']:

View File

@ -317,15 +317,13 @@ class Toctree(EnvironmentManager):
refnode.children = [nodes.Text(title)]
if not toc.children:
# empty toc means: no titles will show up in the toctree
logger.warn_node(
'toctree contains reference to document %r that '
'doesn\'t have a title: no link will be generated'
% ref, toctreenode)
logger.warning('toctree contains reference to document %r that '
'doesn\'t have a title: no link will be generated',
ref, location=toctreenode)
except KeyError:
# this is raised if the included file does not exist
logger.warn_node(
'toctree contains reference to nonexisting document %r'
% ref, toctreenode)
logger.warning('toctree contains reference to nonexisting document %r',
ref, location=toctreenode)
else:
# if titles_only is given, only keep the main title and
# sub-toctrees

View File

@ -26,8 +26,9 @@ def register_sections_as_label(app, document):
sectname = clean_astext(node[0])
if name in labels:
logger.warn_node('duplicate label %s, ' % name + 'other instance '
'in ' + app.env.doc2path(labels[name][0]), node)
logger.warning('duplicate label %s, ' % name + 'other instance '
'in ' + app.env.doc2path(labels[name][0]),
location=node)
anonlabels[name] = docname, labelid
labels[name] = docname, labelid, sectname

View File

@ -100,7 +100,8 @@ def process_todos(app, doctree):
})
if env.config.todo_emit_warnings:
logger.warn_node("TODO entry found: %s" % node[1].astext(), node)
logger.warning("TODO entry found: %s", node[1].astext(),
location=node)
class TodoList(Directive):

View File

@ -181,7 +181,7 @@ class AutoIndexUpgrader(Transform):
if 'entries' in node and any(len(entry) == 4 for entry in node['entries']):
msg = ('4 column based index found. '
'It might be a bug of extensions you use: %r' % node['entries'])
logger.warn_node(msg, node)
logger.warning(msg, location=node)
for i, entry in enumerate(node['entries']):
if len(entry) == 4:
node['entries'][i] = entry + (None,)

View File

@ -274,8 +274,8 @@ class Locale(Transform):
old_foot_refs = node.traverse(is_autonumber_footnote_ref)
new_foot_refs = patch.traverse(is_autonumber_footnote_ref)
if len(old_foot_refs) != len(new_foot_refs):
logger.warn_node('inconsistent footnote references in '
'translated message', node)
logger.warning('inconsistent footnote references in translated message',
location=node)
old_foot_namerefs = {} # type: Dict[unicode, List[nodes.footnote_reference]]
for r in old_foot_refs:
old_foot_namerefs.setdefault(r.get('refname'), []).append(r)
@ -309,7 +309,8 @@ class Locale(Transform):
old_refs = node.traverse(is_refnamed_ref)
new_refs = patch.traverse(is_refnamed_ref)
if len(old_refs) != len(new_refs):
logger.warn_node('inconsistent references in translated message', node)
logger.warning('inconsistent references in translated message',
location=node)
old_ref_names = [r['refname'] for r in old_refs]
new_ref_names = [r['refname'] for r in new_refs]
orphans = list(set(old_ref_names) - set(new_ref_names))
@ -337,7 +338,8 @@ class Locale(Transform):
new_refs = patch.traverse(is_refnamed_footnote_ref)
refname_ids_map = {}
if len(old_refs) != len(new_refs):
logger.warn_node('inconsistent references in translated message', node)
logger.warning('inconsistent references in translated message',
location=node)
for old in old_refs:
refname_ids_map[old["refname"]] = old["ids"]
for new in new_refs:
@ -352,7 +354,8 @@ class Locale(Transform):
new_refs = patch.traverse(addnodes.pending_xref)
xref_reftarget_map = {}
if len(old_refs) != len(new_refs):
logger.warn_node('inconsistent term references in translated message', node)
logger.warning('inconsistent term references in translated message',
location=node)
def get_ref_key(node):
# type: (nodes.Node) -> Tuple[unicode, unicode, unicode]

View File

@ -16,6 +16,7 @@ from contextlib import contextmanager
from collections import defaultdict
from six import PY2, StringIO
from docutils import nodes
from docutils.utils import get_source_line
from sphinx.errors import SphinxWarning
@ -92,23 +93,6 @@ class SphinxWarningLogRecord(logging.LogRecord):
class SphinxLoggerAdapter(logging.LoggerAdapter):
"""LoggerAdapter allowing ``type`` and ``subtype`` keywords."""
def warn_node(self, message, node, **kwargs):
# type: (unicode, nodes.Node, Any) -> None
"""Emit a warning for specific node.
:param message: a message of warning
:param node: a node related with the warning
"""
(source, line) = get_source_line(node)
if source and line:
kwargs['location'] = "%s:%s" % (source, line)
elif source:
kwargs['location'] = "%s:" % source
elif line:
kwargs['location'] = "<unknown>:%s" % line
self.warning(message, **kwargs)
def log(self, level, msg, *args, **kwargs):
# type: (Union[int, str], unicode, Any, Any) -> None
if isinstance(level, int):
@ -374,6 +358,16 @@ class WarningLogRecordTranslator(logging.Filter):
record.location = '%s' % self.app.env.doc2path(docname)
else:
record.location = None
elif isinstance(location, nodes.Node):
(source, line) = get_source_line(location)
if source and line:
record.location = "%s:%s" % (source, line)
elif source:
record.location = "%s:" % source
elif line:
record.location = "<unknown>:%s" % line
else:
record.location = None
elif location and ':' not in location:
record.location = '%s' % self.app.env.doc2path(location)

View File

@ -362,8 +362,8 @@ def process_only_nodes(doctree, tags):
try:
ret = tags.eval_condition(node['expr'])
except Exception as err:
logger.warn_node('exception while evaluating only '
'directive expression: %s' % err, node)
logger.warning('exception while evaluating only directive expression: %s', err,
location=node)
node.replace_self(node.children or nodes.comment())
else:
if ret:

View File

@ -302,7 +302,7 @@ class HTMLTranslator(BaseTranslator):
if figtype:
if len(node['ids']) == 0:
msg = 'Any IDs not assigned for %s node' % node.tagname
logger.warn_node(msg, node)
logger.warning(msg, location=node)
else:
append_fignumber(figtype, node['ids'][0])
@ -525,8 +525,8 @@ class HTMLTranslator(BaseTranslator):
if not ('width' in node and 'height' in node):
size = get_image_size(os.path.join(self.builder.srcdir, olduri))
if size is None:
logger.warn_node('Could not obtain image size. '
':scale: option is ignored.', node)
logger.warning('Could not obtain image size. :scale: option is ignored.',
location=node)
else:
if 'width' not in node:
node['width'] = str(size[0])

View File

@ -199,30 +199,24 @@ def test_warning_location(app, status, warning):
assert 'index.txt:10: WARNING: message2' in warning.getvalue()
logger.warning('message3', location=None)
assert '\x1b[31mWARNING: message3' in warning.getvalue() # \x1b[31m = darkred
@with_app()
def test_warn_node(app, status, warning):
logging.setup(app, status, warning)
logger = logging.getLogger(__name__)
assert colorize('darkred', 'WARNING: message3') in warning.getvalue()
node = nodes.Node()
node.source, node.line = ('index.txt', 10)
logger.warn_node('message1', node)
assert 'index.txt:10: WARNING: message1' in warning.getvalue()
logger.warning('message4', location=node)
assert 'index.txt:10: WARNING: message4' in warning.getvalue()
node.source, node.line = ('index.txt', None)
logger.warn_node('message2', node)
assert 'index.txt:: WARNING: message2' in warning.getvalue()
logger.warning('message5', location=node)
assert 'index.txt:: WARNING: message5' in warning.getvalue()
node.source, node.line = (None, 10)
logger.warn_node('message3', node)
assert '<unknown>:10: WARNING: message3' in warning.getvalue()
logger.warning('message6', location=node)
assert '<unknown>:10: WARNING: message6' in warning.getvalue()
node.source, node.line = (None, None)
logger.warn_node('message4', node)
assert '\x1b[31mWARNING: message4' in warning.getvalue() # \x1b[31m = darkred
logger.warning('message7', location=node)
assert colorize('darkred', 'WARNING: message7') in warning.getvalue()
@with_app()