# Copyright (c) 2003-2014 LOGILAB S.A. (Paris, FRANCE). # http://www.logilab.fr/ -- mailto:contact@logilab.fr # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ %prog [options] module_or_package Check that a module satisfies a coding standard (and more !). %prog --help Display this help message and exit. %prog --help-msg [,] Display help messages about given message identifiers and exit. """ # import this first to avoid builtin namespace pollution from pylint.checkers import utils import functools import sys import os import tokenize from warnings import warn from logilab.common.configuration import UnsupportedAction, OptionsManagerMixIn from logilab.common.optik_ext import check_csv from logilab.common.modutils import load_module_from_name, get_module_part from logilab.common.interface import implements from logilab.common.textutils import splitstrip from logilab.common.ureports import Table, Text, Section from logilab.common.__pkginfo__ import version as common_version from astroid import MANAGER, nodes, AstroidBuildingException from astroid.__pkginfo__ import version as astroid_version from pylint.utils import ( MSG_TYPES, OPTION_RGX, PyLintASTWalker, UnknownMessage, MessagesHandlerMixIn, ReportsHandlerMixIn, EmptyReport, WarningScope, expand_modules, tokenize_module) from pylint.interfaces import IRawChecker, ITokenChecker, IAstroidChecker from pylint.checkers import (BaseTokenChecker, table_lines_from_stats, initialize as checkers_initialize) from pylint.reporters import initialize as reporters_initialize from pylint import config from pylint.__pkginfo__ import version def _get_python_path(filepath): dirname = os.path.dirname(os.path.realpath( os.path.expanduser(filepath))) while True: if not os.path.exists(os.path.join(dirname, "__init__.py")): return dirname old_dirname = dirname dirname = os.path.dirname(dirname) if old_dirname == dirname: return os.getcwd() # Python Linter class ######################################################### MSGS = { 'F0001': ('%s', 'fatal', 'Used when an error occurred preventing the analysis of a \ module (unable to find it for instance).'), 'F0002': ('%s: %s', 'astroid-error', 'Used when an unexpected error occurred while building the ' 'Astroid representation. This is usually accompanied by a ' 'traceback. Please report such errors !'), 'F0003': ('ignored builtin module %s', 'ignored-builtin-module', 'Used to indicate that the user asked to analyze a builtin ' 'module which has been skipped.'), 'F0004': ('unexpected inferred value %s', 'unexpected-inferred-value', 'Used to indicate that some value of an unexpected type has been ' 'inferred.'), 'F0010': ('error while code parsing: %s', 'parse-error', 'Used when an exception occured while building the Astroid ' 'representation which could be handled by astroid.'), 'I0001': ('Unable to run raw checkers on built-in module %s', 'raw-checker-failed', 'Used to inform that a built-in module has not been checked ' 'using the raw checkers.'), 'I0010': ('Unable to consider inline option %r', 'bad-inline-option', 'Used when an inline option is either badly formatted or can\'t ' 'be used inside modules.'), 'I0011': ('Locally disabling %s', 'locally-disabled', 'Used when an inline option disables a message or a messages ' 'category.'), 'I0012': ('Locally enabling %s', 'locally-enabled', 'Used when an inline option enables a message or a messages ' 'category.'), 'I0013': ('Ignoring entire file', 'file-ignored', 'Used to inform that the file will not be checked'), 'I0014': ('Used deprecated directive "pylint:disable-all" or ' '"pylint:disable=all"', 'deprecated-disable-all', 'You should preferably use "pylint:skip-file" as this directive ' 'has a less confusing name. Do this only if you are sure that ' 'all people running Pylint on your code have version >= 0.26'), 'I0020': ('Suppressed %s (from line %d)', 'suppressed-message', 'A message was triggered on a line, but suppressed explicitly ' 'by a disable= comment in the file. This message is not ' 'generated for messages that are ignored due to configuration ' 'settings.'), 'I0021': ('Useless suppression of %s', 'useless-suppression', 'Reported when a message is explicitly disabled for a line or ' 'a block of code, but never triggered.'), 'I0022': ('Deprecated pragma "pylint:disable-msg" or "pylint:enable-msg"', 'deprecated-pragma', 'You should preferably use "pylint:disable" or "pylint:enable" ' 'instead of the deprecated suppression pragma style ' '"pylint:disable-msg" or "pylint:enable-msg"'), 'E0001': ('%s', 'syntax-error', 'Used when a syntax error is raised for a module.'), 'E0011': ('Unrecognized file option %r', 'unrecognized-inline-option', 'Used when an unknown inline option is encountered.'), 'E0012': ('Bad option value %r', 'bad-option-value', 'Used when a bad value for an inline option is encountered.'), } class PyLinter(OptionsManagerMixIn, MessagesHandlerMixIn, ReportsHandlerMixIn, BaseTokenChecker): """lint Python modules using external checkers. This is the main checker controlling the other ones and the reports generation. It is itself both a raw checker and an astroid checker in order to: * handle message activation / deactivation at the module level * handle some basic but necessary stats'data (number of classes, methods...) IDE plugins developpers: you may have to call `astroid.builder.MANAGER.astroid_cache.clear()` accross run if you want to ensure the latest code version is actually checked. """ __implements__ = (ITokenChecker,) name = 'master' priority = 0 level = 0 msgs = MSGS may_be_disabled = False @staticmethod def make_options(): return (('ignore', {'type' : 'csv', 'metavar' : '[,...]', 'dest' : 'black_list', 'default' : ('CVS',), 'help' : 'Add files or directories to the blacklist. ' 'They should be base names, not paths.'}), ('persistent', {'default': True, 'type' : 'yn', 'metavar' : '', 'level': 1, 'help' : 'Pickle collected data for later comparisons.'}), ('load-plugins', {'type' : 'csv', 'metavar' : '', 'default' : (), 'level': 1, 'help' : 'List of plugins (as comma separated values of ' 'python modules names) to load, usually to register ' 'additional checkers.'}), ('output-format', {'default': 'text', 'type': 'string', 'metavar' : '', 'short': 'f', 'group': 'Reports', 'help' : 'Set the output format. Available formats are text,' ' parseable, colorized, msvs (visual studio) and html. You ' 'can also give a reporter class, eg mypackage.mymodule.' 'MyReporterClass.'}), ('files-output', {'default': 0, 'type' : 'yn', 'metavar' : '', 'group': 'Reports', 'level': 1, 'help' : 'Put messages in a separate file for each module / ' 'package specified on the command line instead of printing ' 'them on stdout. Reports (if any) will be written in a file ' 'name "pylint_global.[txt|html]".'}), ('reports', {'default': 1, 'type' : 'yn', 'metavar' : '', 'short': 'r', 'group': 'Reports', 'help' : 'Tells whether to display a full report or only the ' 'messages'}), ('evaluation', {'type' : 'string', 'metavar' : '', 'group': 'Reports', 'level': 1, 'default': '10.0 - ((float(5 * error + warning + refactor + ' 'convention) / statement) * 10)', 'help' : 'Python expression which should return a note less \ than 10 (10 is the highest note). You have access to the variables errors \ warning, statement which respectively contain the number of errors / warnings\ messages and the total number of statements analyzed. This is used by the \ global evaluation report (RP0004).'}), ('comment', {'default': 0, 'type' : 'yn', 'metavar' : '', 'group': 'Reports', 'level': 1, 'help' : 'Add a comment according to your evaluation note. ' 'This is used by the global evaluation report (RP0004).'}), ('enable', {'type' : 'csv', 'metavar': '', 'short': 'e', 'group': 'Messages control', 'help' : 'Enable the message, report, category or checker with the ' 'given id(s). You can either give multiple identifier ' 'separated by comma (,) or put this option multiple time. ' 'See also the "--disable" option for examples. '}), ('disable', {'type' : 'csv', 'metavar': '', 'short': 'd', 'group': 'Messages control', 'help' : 'Disable the message, report, category or checker ' 'with the given id(s). You can either give multiple identifiers' ' separated by comma (,) or put this option multiple times ' '(only on the command line, not in the configuration file ' 'where it should appear only once).' 'You can also use "--disable=all" to disable everything first ' 'and then reenable specific checks. For example, if you want ' 'to run only the similarities checker, you can use ' '"--disable=all --enable=similarities". ' 'If you want to run only the classes checker, but have no ' 'Warning level messages displayed, use' '"--disable=all --enable=classes --disable=W"'}), ('msg-template', {'type' : 'string', 'metavar': '