1# Copyright (c) 2003-2013 LOGILAB S.A. (Paris, FRANCE). 2# This program is free software; you can redistribute it and/or modify it under 3# the terms of the GNU General Public License as published by the Free Software 4# Foundation; either version 2 of the License, or (at your option) any later 5# version. 6# 7# This program is distributed in the hope that it will be useful, but WITHOUT 8# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 9# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 10# 11# You should have received a copy of the GNU General Public License along with 12# this program; if not, write to the Free Software Foundation, Inc., 13# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 14"""Plain text reporters: 15 16:text: the default one grouping messages by module 17:colorized: an ANSI colorized text reporter 18""" 19from __future__ import print_function 20 21import warnings 22 23from logilab.common.ureports import TextWriter 24from logilab.common.textutils import colorize_ansi 25 26from pylint.interfaces import IReporter 27from pylint.reporters import BaseReporter 28import six 29 30TITLE_UNDERLINES = ['', '=', '-', '.'] 31 32 33class TextReporter(BaseReporter): 34 """reports messages and layouts in plain text""" 35 36 __implements__ = IReporter 37 name = 'text' 38 extension = 'txt' 39 line_format = '{C}:{line:3d},{column:2d}: {msg} ({symbol})' 40 41 def __init__(self, output=None): 42 BaseReporter.__init__(self, output) 43 self._modules = set() 44 self._template = None 45 46 def on_set_current_module(self, module, filepath): 47 self._template = six.text_type(self.linter.config.msg_template or self.line_format) 48 49 def write_message(self, msg): 50 """Convenience method to write a formated message with class default template""" 51 self.writeln(msg.format(self._template)) 52 53 def handle_message(self, msg): 54 """manage message of different type and in the context of path""" 55 if msg.module not in self._modules: 56 if msg.module: 57 self.writeln('************* Module %s' % msg.module) 58 self._modules.add(msg.module) 59 else: 60 self.writeln('************* ') 61 self.write_message(msg) 62 63 def _display(self, layout): 64 """launch layouts display""" 65 print(file=self.out) 66 TextWriter().format(layout, self.out) 67 68 69class ParseableTextReporter(TextReporter): 70 """a reporter very similar to TextReporter, but display messages in a form 71 recognized by most text editors : 72 73 <filename>:<linenum>:<msg> 74 """ 75 name = 'parseable' 76 line_format = '{path}:{line}: [{msg_id}({symbol}), {obj}] {msg}' 77 78 def __init__(self, output=None): 79 warnings.warn('%s output format is deprecated. This is equivalent ' 80 'to --msg-template=%s' % (self.name, self.line_format), 81 DeprecationWarning) 82 TextReporter.__init__(self, output) 83 84 85class VSTextReporter(ParseableTextReporter): 86 """Visual studio text reporter""" 87 name = 'msvs' 88 line_format = '{path}({line}): [{msg_id}({symbol}){obj}] {msg}' 89 90 91class ColorizedTextReporter(TextReporter): 92 """Simple TextReporter that colorizes text output""" 93 94 name = 'colorized' 95 COLOR_MAPPING = { 96 "I" : ("green", None), 97 'C' : (None, "bold"), 98 'R' : ("magenta", "bold, italic"), 99 'W' : ("blue", None), 100 'E' : ("red", "bold"), 101 'F' : ("red", "bold, underline"), 102 'S' : ("yellow", "inverse"), # S stands for module Separator 103 } 104 105 def __init__(self, output=None, color_mapping=None): 106 TextReporter.__init__(self, output) 107 self.color_mapping = color_mapping or \ 108 dict(ColorizedTextReporter.COLOR_MAPPING) 109 110 def _get_decoration(self, msg_id): 111 """Returns the tuple color, style associated with msg_id as defined 112 in self.color_mapping 113 """ 114 try: 115 return self.color_mapping[msg_id[0]] 116 except KeyError: 117 return None, None 118 119 def handle_message(self, msg): 120 """manage message of different types, and colorize output 121 using ansi escape codes 122 """ 123 if msg.module not in self._modules: 124 color, style = self._get_decoration('S') 125 if msg.module: 126 modsep = colorize_ansi('************* Module %s' % msg.module, 127 color, style) 128 else: 129 modsep = colorize_ansi('************* %s' % msg.module, 130 color, style) 131 self.writeln(modsep) 132 self._modules.add(msg.module) 133 color, style = self._get_decoration(msg.C) 134 135 msg = msg._replace( 136 **{attr: colorize_ansi(getattr(msg, attr), color, style) 137 for attr in ('msg', 'symbol', 'category', 'C')}) 138 self.write_message(msg) 139 140 141def register(linter): 142 """Register the reporter classes with the linter.""" 143 linter.register_reporter(TextReporter) 144 linter.register_reporter(ParseableTextReporter) 145 linter.register_reporter(VSTextReporter) 146 linter.register_reporter(ColorizedTextReporter) 147