summaryrefslogtreecommitdiff
path: root/reporters
diff options
context:
space:
mode:
authorAnthony Truchet <anthony.truchet@logilab.fr>2013-07-30 18:02:48 +0200
committerAnthony Truchet <anthony.truchet@logilab.fr>2013-07-30 18:02:48 +0200
commitda271bd68f2b79f3480c3efb5f3344ed35fd618e (patch)
treeac340c5e171f6536a1a16052ff6ad19749b7a8b9 /reporters
parentf5fb829be4799fedd0baae5714c52c1a233805e9 (diff)
downloadpylint-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__.py54
-rw-r--r--reporters/html.py11
-rw-r--r--reporters/text.py88
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):