diff options
author | Anthony Truchet <anthony.truchet@logilab.fr> | 2013-07-30 18:02:48 +0200 |
---|---|---|
committer | Anthony Truchet <anthony.truchet@logilab.fr> | 2013-07-30 18:02:48 +0200 |
commit | da271bd68f2b79f3480c3efb5f3344ed35fd618e (patch) | |
tree | ac340c5e171f6536a1a16052ff6ad19749b7a8b9 /reporters | |
parent | f5fb829be4799fedd0baae5714c52c1a233805e9 (diff) | |
download | pylint-da271bd68f2b79f3480c3efb5f3344ed35fd618e.tar.gz |
Templating mecanism for text reporters.
This changeset introduces a reporters.Message class to represent
messages with their attached data. Those messages object can then
be formatted accordingto some template.
A template can be specified on the command line through the
msg-template option.
This deprecates parseable and msvc output format, and kill --symbols
and --include-ids option.
Diffstat (limited to 'reporters')
-rw-r--r-- | reporters/__init__.py | 54 | ||||
-rw-r--r-- | reporters/html.py | 11 | ||||
-rw-r--r-- | reporters/text.py | 88 |
3 files changed, 76 insertions, 77 deletions
diff --git a/reporters/__init__.py b/reporters/__init__.py index 3e87aed..0b80c4e 100644 --- a/reporters/__init__.py +++ b/reporters/__init__.py @@ -13,7 +13,11 @@ # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. """utilities methods and classes for reporters""" -import sys, locale +import sys +import locale +import os + +from pylint.utils import MSG_TYPES from pylint import utils @@ -33,6 +37,27 @@ def diff_string(old, new): return diff_str +class Message(object): + """This class represent a message to be issued by the reporters""" + + def __init__(self, reporter, msg_id, location, msg): + self.msg_id = msg_id + self.abspath, self.module, self.obj, self.line, self.column = location + self.path = self.abspath.replace(reporter.path_strip_prefix, '') + self.msg = msg + self.C = msg_id[0] + self.category = MSG_TYPES[msg_id[0]] + self.symbol = reporter.linter.check_message_id(msg_id).symbol + + def format(self, template): + """Format the message according to the given template. + + The template format is the one of the format method : + cf. http://docs.python.org/2/library/string.html#formatstrings + """ + return template.format(**(self.__dict__)) + + class BaseReporter(object): """base class for reporters @@ -43,28 +68,19 @@ class BaseReporter(object): def __init__(self, output=None): self.linter = None - self.include_ids = None - self.symbols = None + # self.include_ids = None # Deprecated + # self.symbols = None # Deprecated self.section = 0 self.out = None self.out_encoding = None self.set_output(output) + # Build the path prefix to strip to get relative paths + self.path_strip_prefix = os.getcwd() + os.sep - def make_sigle(self, msg_id): - """generate a short prefix for a message. - - The sigle can include the id, the symbol, or both, or it can just be - the message class. - """ - if self.include_ids: - sigle = msg_id - else: - sigle = msg_id[0] - if self.symbols: - symbol = self.linter.check_message_id(msg_id).symbol - if symbol: - sigle += '(%s)' % symbol - return sigle + def add_message(self, msg_id, location, msg): + """Client API to send a message""" + # Shall we store the message objects somewhere, do some validity checking ? + raise NotImplementedError def set_output(self, output=None): """set output stream""" @@ -93,7 +109,7 @@ class BaseReporter(object): def display_results(self, layout): """display results encapsulated in the layout tree""" self.section = 0 - if self.include_ids and hasattr(layout, 'report_id'): + if hasattr(layout, 'report_id'): layout.children[0].children[0].data += ' (%s)' % layout.report_id self._display(layout) diff --git a/reporters/html.py b/reporters/html.py index 23c1d18..a51e0e7 100644 --- a/reporters/html.py +++ b/reporters/html.py @@ -1,5 +1,4 @@ -# Copyright (c) 2003-2006 Sylvain Thenault (thenault@gmail.com). -# Copyright (c) 2003-2011 LOGILAB S.A. (Paris, FRANCE). +# Copyright (c) 2003-2013 LOGILAB S.A. (Paris, FRANCE). # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later @@ -20,7 +19,7 @@ from cgi import escape from logilab.common.ureports import HTMLWriter, Section, Table from pylint.interfaces import IReporter -from pylint.reporters import BaseReporter +from pylint.reporters import BaseReporter, Message class HTMLReporter(BaseReporter): @@ -36,9 +35,9 @@ class HTMLReporter(BaseReporter): def add_message(self, msg_id, location, msg): """manage message of different type and in the context of path""" - module, obj, line, col_offset = location[1:] - sigle = self.make_sigle(msg_id) - self.msgs += [sigle, module, obj, str(line), str(col_offset), escape(msg)] + msg = Message(self, msg_id, location, msg) + self.msgs += (msg.category, msg.module, msg.obj, + str(msg.line), str(msg.column), escape(msg.msg)) def set_output(self, output=None): """set output stream diff --git a/reporters/text.py b/reporters/text.py index 54e13a0..b024a0f 100644 --- a/reporters/text.py +++ b/reporters/text.py @@ -14,49 +14,51 @@ """Plain text reporters: :text: the default one grouping messages by module -:parseable: - standard parseable output with full module path on each message (for - editor integration) :colorized: an ANSI colorized text reporter - """ -import os +import os.path as osp +import warnings from logilab.common.ureports import TextWriter from logilab.common.textutils import colorize_ansi from pylint.interfaces import IReporter -from pylint.reporters import BaseReporter +from pylint.reporters import BaseReporter, Message TITLE_UNDERLINES = ['', '=', '-', '.'] class TextReporter(BaseReporter): - """reports messages and layouts in plain text - """ - + """reports messages and layouts in plain text""" + __implements__ = IReporter name = 'text' extension = 'txt' + line_format = '{msg_id}({symbol}):{line:3d},{column}: {obj}: {msg}' def __init__(self, output=None): BaseReporter.__init__(self, output) self._modules = {} + self._template = None + + def on_set_current_module(self, module, filepath): + self._template = unicode(self.linter.config.msg_template or self.line_format) + + def write_message(self, m, template=None): + """Convenience method to write a formated message with class default template""" + self.writeln(m.format(self._template)) def add_message(self, msg_id, location, msg): """manage message of different type and in the context of path""" - module, obj, line, col_offset = location[1:] - if module not in self._modules: - if module: - self.writeln('************* Module %s' % module) - self._modules[module] = 1 + m = Message(self, msg_id, location, msg) + if m.module not in self._modules: + if m.module: + self.writeln('************* Module %s' % m.module) + self._modules[m.module] = 1 else: - self.writeln('************* %s' % module) - if obj: - obj = ':%s' % obj - sigle = self.make_sigle(msg_id) - self.writeln('%s:%3s,%s%s: %s' % (sigle, line, col_offset, obj, msg)) + self.writeln('************* ') + self.write_message(m) def _display(self, layout): """launch layouts display""" @@ -71,38 +73,24 @@ class ParseableTextReporter(TextReporter): <filename>:<linenum>:<msg> """ name = 'parseable' - - line_format = '%(path)s:%(line)s: [%(sigle)s%(obj)s] %(msg)s' + line_format = '{path}:{line}: [{msg_id}({symbol}), {obj}] {msg}' def __init__(self, output=None, relative=True): + warnings.warn('%s output format is deprecated. This is equivalent to --msg-template=%s' + % (self.name, self.line_format)) TextReporter.__init__(self, output) - if relative: - self._prefix = os.getcwd() + os.sep - else: - self._prefix = '' - - def add_message(self, msg_id, location, msg): - """manage message of different type and in the context of path""" - path, _, obj, line, _ = location - if obj: - obj = ', %s' % obj - sigle = self.make_sigle(msg_id) - if self._prefix: - path = path.replace(self._prefix, '') - self.writeln(self.line_format % locals()) class VSTextReporter(ParseableTextReporter): """Visual studio text reporter""" - line_format = '%(path)s(%(line)s): [%(sigle)s%(obj)s] %(msg)s' - name = 'msvs' + line_format = '{path}({line}): [{msg_id}({symbol}){obj}] {msg}' + class ColorizedTextReporter(TextReporter): """Simple TextReporter that colorizes text output""" name = 'colorized' - COLOR_MAPPING = { "I" : ("green", None), 'C' : (None, "bold"), @@ -118,7 +106,6 @@ class ColorizedTextReporter(TextReporter): self.color_mapping = color_mapping or \ dict(ColorizedTextReporter.COLOR_MAPPING) - def _get_decoration(self, msg_id): """Returns the tuple color, style associated with msg_id as defined in self.color_mapping @@ -132,24 +119,21 @@ class ColorizedTextReporter(TextReporter): """manage message of different types, and colorize output using ansi escape codes """ - module, obj, line, _ = location[1:] - if module not in self._modules: + m = Message(self, msg_id, location, msg) + if m.module not in self._modules: color, style = self._get_decoration('S') - if module: - modsep = colorize_ansi('************* Module %s' % module, + if m.module: + modsep = colorize_ansi('************* Module %s' % m.module, color, style) else: - modsep = colorize_ansi('************* %s' % module, + modsep = colorize_ansi('************* %s' % m.module, color, style) self.writeln(modsep) - self._modules[module] = 1 - if obj: - obj = ':%s' % obj - sigle = self.make_sigle(msg_id) - color, style = self._get_decoration(sigle) - msg = colorize_ansi(msg, color, style) - sigle = colorize_ansi(sigle, color, style) - self.writeln('%s:%3s%s: %s' % (sigle, line, obj, msg)) + self._modules[m.module] = 1 + color, style = self._get_decoration(m.C) + for attr in ('msg', 'symbol', 'category', 'C'): + setattr(m, attr, colorize_ansi(getattr(m, attr), color, style)) + self.write_message(m) def register(linter): |