Source

pylint / pylint / reporters / text.py

Full commit
# Copyright (c) 2003-2007 Sylvain Thenault (thenault@gmail.com).
# Copyright (c) 2003-2012 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
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
"""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 sys

from logilab.common.ureports import TextWriter
from logilab.common.textutils import colorize_ansi

from pylint.interfaces import IReporter
from pylint.reporters import BaseReporter

TITLE_UNDERLINES = ['', '=', '-', '.']


class TextReporter(BaseReporter):
    """reports messages and layouts in plain text
    """

    __implements__ = IReporter
    extension = 'txt'

    def __init__(self, output=sys.stdout):
        BaseReporter.__init__(self, output)
        self._modules = {}

    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
            else:
                self.writeln('************* %s' % module)
        if obj:
            obj = ':%s' % obj
        if self.include_ids:
            sigle = msg_id
        else:
            sigle = msg_id[0]
        self.writeln('%s:%3s,%s%s: %s' % (sigle, line, col_offset, obj, msg))

    def _display(self, layout):
        """launch layouts display"""
        print >> self.out
        TextWriter().format(layout, self.out)


class ParseableTextReporter(TextReporter):
    """a reporter very similar to TextReporter, but display messages in a form
    recognized by most text editors :

    <filename>:<linenum>:<msg>
    """
    line_format = '%(path)s:%(line)s: [%(sigle)s%(obj)s] %(msg)s'

    def __init__(self, output=sys.stdout, relative=True):
        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
        if self.include_ids:
            sigle = msg_id
        else:
            sigle = msg_id[0]
        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'

class ColorizedTextReporter(TextReporter):
    """Simple TextReporter that colorizes text output"""

    COLOR_MAPPING = {
        "I" : ("green", None),
        'C' : (None, "bold"),
        'R' : ("magenta", "bold, italic"),
        'W' : ("blue", None),
        'E' : ("red", "bold"),
        'F' : ("red", "bold, underline"),
        'S' : ("yellow", "inverse"), # S stands for module Separator
    }

    def __init__(self, output=sys.stdout, color_mapping = None):
        TextReporter.__init__(self, output)
        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
        """
        try:
            return self.color_mapping[msg_id[0]]
        except KeyError:
            return None, None

    def add_message(self, msg_id, location, msg):
        """manage message of different types, and colorize output
        using ansi escape codes
        """
        module, obj, line, _ = location[1:]
        if module not in self._modules:
            color, style = self._get_decoration('S')
            if module:
                modsep = colorize_ansi('************* Module %s' % module,
                                       color, style)
            else:
                modsep = colorize_ansi('************* %s' % module,
                                       color, style)
            self.writeln(modsep)
            self._modules[module] = 1
        if obj:
            obj = ':%s' % obj
        if self.include_ids:
            sigle = msg_id
        else:
            sigle = msg_id[0]
        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))