Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(65)

Unified Diff: third_party/pylint/lint.py

Issue 753543006: pylint: upgrade to 1.4.0 (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/depot_tools.git@master
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/pylint/interfaces.py ('k') | third_party/pylint/pyreverse/diadefslib.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/pylint/lint.py
diff --git a/third_party/pylint/lint.py b/third_party/pylint/lint.py
index 5be37f3499a4835f648c27358d723c6165705fa6..6f762ccf98b4eb362b9db92651d4c762df31b039 100644
--- a/third_party/pylint/lint.py
+++ b/third_party/pylint/lint.py
@@ -25,6 +25,7 @@
Display help messages about given message identifiers and exit.
"""
+from __future__ import print_function
# import this first to avoid builtin namespace pollution
from pylint.checkers import utils #pylint: disable=unused-import
@@ -32,16 +33,24 @@ from pylint.checkers import utils #pylint: disable=unused-import
import sys
import os
import tokenize
+from collections import defaultdict
+from contextlib import contextmanager
from operator import attrgetter
from warnings import warn
-
-from logilab.common.configuration import UnsupportedAction, OptionsManagerMixIn
+from itertools import chain
+try:
+ import multiprocessing
+except ImportError:
+ multiprocessing = None
+
+import six
+from logilab.common.configuration import (
+ UnsupportedAction, OptionsManagerMixIn)
from logilab.common.optik_ext import check_csv
from logilab.common.interface import implements
from logilab.common.textutils import splitstrip, unquote
from logilab.common.ureports import Table, Text, Section
from logilab.common.__pkginfo__ import version as common_version
-
from astroid import MANAGER, AstroidBuildingException
from astroid.__pkginfo__ import version as astroid_version
from astroid.modutils import load_module_from_name, get_module_part
@@ -50,21 +59,37 @@ from pylint.utils import (
MSG_TYPES, OPTION_RGX,
PyLintASTWalker, UnknownMessage, MessagesHandlerMixIn, ReportsHandlerMixIn,
MessagesStore, FileState, EmptyReport,
- expand_modules, tokenize_module)
-from pylint.interfaces import IRawChecker, ITokenChecker, IAstroidChecker
+ expand_modules, tokenize_module, Message)
+from pylint.interfaces import IRawChecker, ITokenChecker, IAstroidChecker, CONFIDENCE_LEVELS
from pylint.checkers import (BaseTokenChecker,
table_lines_from_stats,
initialize as checkers_initialize)
-from pylint.reporters import initialize as reporters_initialize
+from pylint.reporters import initialize as reporters_initialize, CollectingReporter
from pylint import config
-
from pylint.__pkginfo__ import version
+def _get_new_args(message):
+ location = (
+ message.abspath,
+ message.path,
+ message.module,
+ message.obj,
+ message.line,
+ message.column,
+ )
+ return (
+ message.msg_id,
+ message.symbol,
+ location,
+ message.msg,
+ message.confidence,
+ )
def _get_python_path(filepath):
- dirname = os.path.dirname(os.path.realpath(
- os.path.expanduser(filepath)))
+ dirname = os.path.realpath(os.path.expanduser(filepath))
+ if not os.path.isdir(dirname):
+ dirname = os.path.dirname(dirname)
while True:
if not os.path.exists(os.path.join(dirname, "__init__.py")):
return dirname
@@ -74,6 +99,20 @@ def _get_python_path(filepath):
return os.getcwd()
+def _merge_stats(stats):
+ merged = {}
+ for stat in stats:
+ for key, item in six.iteritems(stat):
+ if key not in merged:
+ merged[key] = item
+ else:
+ if isinstance(item, dict):
+ merged[key].update(item)
+ else:
+ merged[key] = merged[key] + item
+ return merged
+
+
# Python Linter class #########################################################
MSGS = {
@@ -147,12 +186,63 @@ MSGS = {
def _deprecated_option(shortname, opt_type):
- def _warn_deprecated(option, optname, *args):
+ def _warn_deprecated(option, optname, *args): # pylint: disable=unused-argument
sys.stderr.write('Warning: option %s is deprecated and ignored.\n' % (optname,))
return {'short': shortname, 'help': 'DEPRECATED', 'hide': True,
'type': opt_type, 'action': 'callback', 'callback': _warn_deprecated}
+if multiprocessing is not None:
+ class ChildLinter(multiprocessing.Process): # pylint: disable=no-member
+ def run(self):
+ tasks_queue, results_queue, config = self._args # pylint: disable=no-member
+
+ for file_or_module in iter(tasks_queue.get, 'STOP'):
+ result = self._run_linter(config, file_or_module[0])
+ try:
+ results_queue.put(result)
+ except Exception as ex:
+ print("internal error with sending report for module %s" % file_or_module, file=sys.stderr)
+ print(ex, file=sys.stderr)
+ results_queue.put({})
+
+ def _run_linter(self, config, file_or_module):
+ linter = PyLinter()
+
+ # Register standard checkers.
+ linter.load_default_plugins()
+ # Load command line plugins.
+ # TODO linter.load_plugin_modules(self._plugins)
+
+ linter.disable('pointless-except')
+ linter.disable('suppressed-message')
+ linter.disable('useless-suppression')
+
+ # TODO(cpopa): the sub-linters will not know all the options
+ # because they are not available here, as they are patches to
+ # PyLinter options. The following is just a hack to handle
+ # just a part of the options available in the Run class.
+
+ if 'disable_msg' in config:
+ # Disable everything again. We don't have access
+ # to the original linter though.
+ for msgid in config['disable_msg']:
+ linter.disable(msgid)
+ for key in set(config) - set(dict(linter.options)):
+ del config[key]
+
+ config['jobs'] = 1 # Child does not parallelize any further.
+ linter.load_configuration(**config)
+ linter.set_reporter(CollectingReporter())
+
+ # Run the checks.
+ linter.check(file_or_module)
+
+ msgs = [_get_new_args(m) for m in linter.reporter.messages]
+ return (file_or_module, linter.file_state.base_name, linter.current_name,
+ msgs, linter.stats, linter.msg_status)
+
+
class PyLinter(OptionsManagerMixIn, MessagesHandlerMixIn, ReportsHandlerMixIn,
BaseTokenChecker):
"""lint Python modules using external checkers.
@@ -174,7 +264,6 @@ class PyLinter(OptionsManagerMixIn, MessagesHandlerMixIn, ReportsHandlerMixIn,
priority = 0
level = 0
msgs = MSGS
- may_be_disabled = False
@staticmethod
def make_options():
@@ -238,6 +327,15 @@ class PyLinter(OptionsManagerMixIn, MessagesHandlerMixIn, ReportsHandlerMixIn,
'help' : 'Add a comment according to your evaluation note. '
'This is used by the global evaluation report (RP0004).'}),
+ ('confidence',
+ {'type' : 'multiple_choice', 'metavar': '<levels>',
+ 'default': '',
+ 'choices': [c.name for c in CONFIDENCE_LEVELS],
+ 'group': 'Messages control',
+ 'help' : 'Only show warnings with the listed confidence levels.'
+ ' Leave empty to show all. Valid levels: %s' % (
+ ', '.join(c.name for c in CONFIDENCE_LEVELS),)}),
+
('enable',
{'type' : 'csv', 'metavar': '<msg ids>',
'short': 'e',
@@ -275,6 +373,27 @@ class PyLinter(OptionsManagerMixIn, MessagesHandlerMixIn, ReportsHandlerMixIn,
('include-ids', _deprecated_option('i', 'yn')),
('symbols', _deprecated_option('s', 'yn')),
+
+ ('jobs',
+ {'type' : 'int', 'metavar': '<n-processes>',
+ 'short': 'j',
+ 'default': 1,
+ 'help' : '''Use multiple processes to speed up Pylint.''',
+ }),
+
+ ('unsafe-load-any-extension',
+ {'type': 'yn', 'metavar': '<yn>', 'default': False, 'hide': True,
+ 'help': ('Allow loading of arbitrary C extensions. Extensions'
+ ' are imported into the active Python interpreter and'
+ ' may run arbitrary code.')}),
+
+ ('extension-pkg-whitelist',
+ {'type': 'csv', 'metavar': '<pkg[,pkg]>', 'default': [],
+ 'help': ('A comma-separated list of package or module names'
+ ' from where C extensions may be loaded. Extensions are'
+ ' loading into the active Python interpreter and may run'
+ ' arbitrary code')}
+ ),
)
option_groups = (
@@ -291,7 +410,8 @@ class PyLinter(OptionsManagerMixIn, MessagesHandlerMixIn, ReportsHandlerMixIn,
self.reporter = None
self._reporter_name = None
self._reporters = {}
- self._checkers = {}
+ self._checkers = defaultdict(list)
+ self._pragma_lineno = {}
self._ignore_file = False
# visit variables
self.file_state = FileState()
@@ -338,17 +458,6 @@ class PyLinter(OptionsManagerMixIn, MessagesHandlerMixIn, ReportsHandlerMixIn,
if not self.reporter:
self._load_reporter()
- def prepare_import_path(self, args):
- """Prepare sys.path for running the linter checks."""
- if len(args) == 1:
- sys.path.insert(0, _get_python_path(args[0]))
- else:
- sys.path.insert(0, os.getcwd())
-
- def cleanup_import_path(self):
- """Revert any changes made to sys.path in prepare_import_path."""
- sys.path.pop(0)
-
def load_plugin_modules(self, modnames):
"""take a list of module names which are pylint plugins and load
and register them
@@ -404,12 +513,24 @@ class PyLinter(OptionsManagerMixIn, MessagesHandlerMixIn, ReportsHandlerMixIn,
try:
BaseTokenChecker.set_option(self, optname, value, action, optdict)
except UnsupportedAction:
- print >> sys.stderr, 'option %s can\'t be read from config file' % \
- optname
+ print('option %s can\'t be read from config file' % \
+ optname, file=sys.stderr)
def register_reporter(self, reporter_class):
self._reporters[reporter_class.name] = reporter_class
+ def report_order(self):
+ reports = sorted(self._reports, key=lambda x: getattr(x, 'name', ''))
+ try:
+ # Remove the current reporter and add it
+ # at the end of the list.
+ reports.pop(reports.index(self))
+ except ValueError:
+ pass
+ else:
+ reports.append(self)
+ return reports
+
# checkers manipulation methods ############################################
def register_checker(self, checker):
@@ -418,7 +539,7 @@ class PyLinter(OptionsManagerMixIn, MessagesHandlerMixIn, ReportsHandlerMixIn,
checker is an object implementing IRawChecker or / and IAstroidChecker
"""
assert checker.priority <= 0, 'checker priority can\'t be >= 0'
- self._checkers.setdefault(checker.name, []).append(checker)
+ self._checkers[checker.name].append(checker)
for r_id, r_title, r_cb in checker.reports:
self.register_report(r_id, r_title, r_cb, checker)
self.register_options_provider(checker)
@@ -426,8 +547,13 @@ class PyLinter(OptionsManagerMixIn, MessagesHandlerMixIn, ReportsHandlerMixIn,
self.msgs_store.register_messages(checker)
checker.load_defaults()
+ # Register the checker, but disable all of its messages.
+ # TODO(cpopa): we should have a better API for this.
+ if not getattr(checker, 'enabled', True):
+ self.disable(checker.name)
+
def disable_noerror_messages(self):
- for msgcat, msgids in self.msgs_store._msgs_by_category.iteritems():
+ for msgcat, msgids in six.iteritems(self.msgs_store._msgs_by_category):
if msgcat == 'E':
for msgid in msgids:
self.enable(msgid)
@@ -437,7 +563,7 @@ class PyLinter(OptionsManagerMixIn, MessagesHandlerMixIn, ReportsHandlerMixIn,
def disable_reporters(self):
"""disable all reporters"""
- for reporters in self._reports.itervalues():
+ for reporters in six.itervalues(self._reports):
for report_id, _title, _cb in reporters:
self.disable_report(report_id)
@@ -456,6 +582,7 @@ class PyLinter(OptionsManagerMixIn, MessagesHandlerMixIn, ReportsHandlerMixIn,
"""process tokens from the current module to search for module/block
level options
"""
+ control_pragmas = {'disable', 'enable'}
for (tok_type, content, start, _, _) in tokens:
if tok_type != tokenize.COMMENT:
continue
@@ -485,6 +612,10 @@ class PyLinter(OptionsManagerMixIn, MessagesHandlerMixIn, ReportsHandlerMixIn,
# found a "(dis|en)able-msg" pragma deprecated suppresssion
self.add_message('deprecated-pragma', line=start[0], args=(opt, opt.replace('-msg', '')))
for msgid in splitstrip(value):
+ # Add the line where a control pragma was encountered.
+ if opt in control_pragmas:
+ self._pragma_lineno[msgid] = start[0]
+
try:
if (opt, msgid) == ('disable', 'all'):
self.add_message('deprecated-pragma', line=start[0], args=('disable=all', 'skip-file'))
@@ -502,7 +633,7 @@ class PyLinter(OptionsManagerMixIn, MessagesHandlerMixIn, ReportsHandlerMixIn,
def get_checkers(self):
"""return all available checkers as a list"""
- return [self] + [c for checkers in self._checkers.itervalues()
+ return [self] + [c for checkers in six.itervalues(self._checkers)
for c in checkers if c is not self]
def prepare_checkers(self):
@@ -523,7 +654,7 @@ class PyLinter(OptionsManagerMixIn, MessagesHandlerMixIn, ReportsHandlerMixIn,
reverse=True)
return neededcheckers
- def should_analyze_file(self, modname, path): # pylint: disable=unused-argument
+ def should_analyze_file(self, modname, path): # pylint: disable=unused-argument, no-self-use
"""Returns whether or not a module should be checked.
This implementation returns True for all python source file, indicating
@@ -551,6 +682,99 @@ class PyLinter(OptionsManagerMixIn, MessagesHandlerMixIn, ReportsHandlerMixIn,
if not isinstance(files_or_modules, (list, tuple)):
files_or_modules = (files_or_modules,)
+
+ if self.config.jobs == 1:
+ self._do_check(files_or_modules)
+ else:
+ # Hack that permits running pylint, on Windows, with -m switch
+ # and with --jobs, as in 'py -2 -m pylint .. --jobs'.
+ # For more details why this is needed,
+ # see Python issue http://bugs.python.org/issue10845.
+
+ mock_main = six.PY2 and __name__ != '__main__' # -m switch
+ if mock_main:
+ sys.modules['__main__'] = sys.modules[__name__]
+ try:
+ self._parallel_check(files_or_modules)
+ finally:
+ if mock_main:
+ sys.modules.pop('__main__')
+
+ def _parallel_task(self, files_or_modules):
+ # Prepare configuration for child linters.
+ config = vars(self.config)
+ childs = []
+ manager = multiprocessing.Manager() # pylint: disable=no-member
+ tasks_queue = manager.Queue() # pylint: disable=no-member
+ results_queue = manager.Queue() # pylint: disable=no-member
+
+ for _ in range(self.config.jobs):
+ cl = ChildLinter(args=(tasks_queue, results_queue, config))
+ cl.start() # pylint: disable=no-member
+ childs.append(cl)
+
+ # send files to child linters
+ for files_or_module in files_or_modules:
+ tasks_queue.put([files_or_module])
+
+ # collect results from child linters
+ failed = False
+ for _ in files_or_modules:
+ try:
+ result = results_queue.get()
+ except Exception as ex:
+ print("internal error while receiving results from child linter",
+ file=sys.stderr)
+ print(ex, file=sys.stderr)
+ failed = True
+ break
+ yield result
+
+ # Stop child linters and wait for their completion.
+ for _ in range(self.config.jobs):
+ tasks_queue.put('STOP')
+ for cl in childs:
+ cl.join()
+
+ if failed:
+ print("Error occured, stopping the linter.", file=sys.stderr)
+ sys.exit(32)
+
+ def _parallel_check(self, files_or_modules):
+ # Reset stats.
+ self.open()
+
+ all_stats = []
+ for result in self._parallel_task(files_or_modules):
+ (
+ file_or_module,
+ self.file_state.base_name,
+ module,
+ messages,
+ stats,
+ msg_status
+ ) = result
+
+ if file_or_module == files_or_modules[-1]:
+ last_module = module
+
+ for msg in messages:
+ msg = Message(*msg)
+ self.set_current_module(module)
+ self.reporter.handle_message(msg)
+
+ all_stats.append(stats)
+ self.msg_status |= msg_status
+
+ self.stats = _merge_stats(chain(all_stats, [self.stats]))
+ self.current_name = last_module
+
+ # Insert stats data to local checkers.
+ for checker in self.get_checkers():
+ if checker is not self:
+ checker.stats = self.stats
+
+ def _do_check(self, files_or_modules):
walker = PyLintASTWalker(self)
checkers = self.prepare_checkers()
tokencheckers = [c for c in checkers if implements(c, ITokenChecker)
@@ -587,7 +811,6 @@ class PyLinter(OptionsManagerMixIn, MessagesHandlerMixIn, ReportsHandlerMixIn,
for msgid, line, args in self.file_state.iter_spurious_suppression_messages(self.msgs_store):
self.add_message(msgid, line, None, args)
# notify global end
- self.set_current_module('')
self.stats['statement'] = walker.nbstatements
checkers.reverse()
for checker in checkers:
@@ -617,28 +840,42 @@ class PyLinter(OptionsManagerMixIn, MessagesHandlerMixIn, ReportsHandlerMixIn,
self.current_file = filepath or modname
self.stats['by_module'][modname] = {}
self.stats['by_module'][modname]['statement'] = 0
- for msg_cat in MSG_TYPES.itervalues():
+ for msg_cat in six.itervalues(MSG_TYPES):
self.stats['by_module'][modname][msg_cat] = 0
def get_ast(self, filepath, modname):
"""return a ast(roid) representation for a module"""
try:
return MANAGER.ast_from_file(filepath, modname, source=True)
- except SyntaxError, ex:
+ except SyntaxError as ex:
self.add_message('syntax-error', line=ex.lineno, args=ex.msg)
- except AstroidBuildingException, ex:
+ except AstroidBuildingException as ex:
self.add_message('parse-error', args=ex)
- except Exception, ex:
+ except Exception as ex: # pylint: disable=broad-except
import traceback
traceback.print_exc()
self.add_message('astroid-error', args=(ex.__class__, ex))
def check_astroid_module(self, astroid, walker, rawcheckers, tokencheckers):
"""check a module from its astroid representation, real work"""
+ try:
+ return self._check_astroid_module(astroid, walker,
+ rawcheckers, tokencheckers)
+ finally:
+ # Close file_stream, if opened, to avoid to open many files.
+ if astroid.file_stream:
+ astroid.file_stream.close()
+ # TODO(cpopa): This is an implementation detail, but it will
+ # be moved in astroid at some point.
+ # We invalidate the cached property, to let the others
+ # modules which relies on this one to get a new file stream.
+ del astroid.file_stream
+
+ def _check_astroid_module(self, astroid, walker, rawcheckers, tokencheckers):
# call raw checkers if possible
try:
tokens = tokenize_module(astroid)
- except tokenize.TokenError, ex:
+ except tokenize.TokenError as ex:
self.add_message('syntax-error', line=ex.args[1][0], args=ex.args[0])
return
@@ -669,10 +906,12 @@ class PyLinter(OptionsManagerMixIn, MessagesHandlerMixIn, ReportsHandlerMixIn,
self.stats = {'by_module' : {},
'by_msg' : {},
}
- for msg_cat in MSG_TYPES.itervalues():
+ MANAGER.always_load_extensions = self.config.unsafe_load_any_extension
+ MANAGER.extension_package_whitelist.update(self.config.extension_pkg_whitelist)
+ for msg_cat in six.itervalues(MSG_TYPES):
self.stats[msg_cat] = 0
- def close(self):
+ def generate_reports(self):
"""close the whole package /module, it's time to make reports !
if persistent run, pickle results for later comparison
@@ -695,6 +934,11 @@ class PyLinter(OptionsManagerMixIn, MessagesHandlerMixIn, ReportsHandlerMixIn,
if self.config.persistent:
config.save_results(self.stats, self.file_state.base_name)
else:
+ if self.config.output_format == 'html':
+ # No output will be emitted for the html
+ # reporter if the file doesn't exist, so emit
+ # the results here.
+ self.reporter.display_results(Section())
self.reporter.on_close(self.stats, {})
# specific reports ########################################################
@@ -708,8 +952,8 @@ class PyLinter(OptionsManagerMixIn, MessagesHandlerMixIn, ReportsHandlerMixIn,
# get a global note for the code
evaluation = self.config.evaluation
try:
- note = eval(evaluation, {}, self.stats)
- except Exception, ex:
+ note = eval(evaluation, {}, self.stats) # pylint: disable=eval-used
+ except Exception as ex: # pylint: disable=broad-except
msg = 'An exception occurred while rating: %s' % ex
else:
stats['global_note'] = note
@@ -737,7 +981,7 @@ def report_messages_stats(sect, stats, _):
# don't print this report when we didn't detected any errors
raise EmptyReport()
in_order = sorted([(value, msg_id)
- for msg_id, value in stats['by_msg'].iteritems()
+ for msg_id, value in six.iteritems(stats['by_msg'])
if not msg_id.startswith('I')])
in_order.reverse()
lines = ('message id', 'occurrences')
@@ -750,18 +994,18 @@ def report_messages_by_module_stats(sect, stats, _):
if len(stats['by_module']) == 1:
# don't print this report when we are analysing a single module
raise EmptyReport()
- by_mod = {}
+ by_mod = defaultdict(dict)
for m_type in ('fatal', 'error', 'warning', 'refactor', 'convention'):
total = stats[m_type]
- for module in stats['by_module'].iterkeys():
+ for module in six.iterkeys(stats['by_module']):
mod_total = stats['by_module'][module][m_type]
if total == 0:
percent = 0
else:
percent = float((mod_total)*100) / total
- by_mod.setdefault(module, {})[m_type] = percent
+ by_mod[module][m_type] = percent
sorted_result = []
- for module, mod_info in by_mod.iteritems():
+ for module, mod_info in six.iteritems(by_mod):
sorted_result.append((mod_info['error'],
mod_info['warning'],
mod_info['refactor'],
@@ -771,8 +1015,9 @@ def report_messages_by_module_stats(sect, stats, _):
sorted_result.reverse()
lines = ['module', 'error', 'warning', 'refactor', 'convention']
for line in sorted_result:
- if line[0] == 0 and line[1] == 0:
- break
+ # Don't report clean modules.
+ if all(entry == 0 for entry in line[:-1]):
+ continue
lines.append(line[-1])
for val in line[:-1]:
lines.append('%.2f' % val)
@@ -783,12 +1028,6 @@ def report_messages_by_module_stats(sect, stats, _):
# utilities ###################################################################
-# this may help to import modules using gettext
-# XXX syt, actually needed since we don't import code?
-
-from logilab.common.compat import builtins
-builtins._ = str
-
class ArgumentPreprocessingError(Exception):
"""Raised if an error occurs during argument preprocessing."""
@@ -828,6 +1067,31 @@ def preprocess_options(args, search_for):
else:
i += 1
+
+@contextmanager
+def fix_import_path(args):
+ """Prepare sys.path for running the linter checks.
+
+ Within this context, each of the given arguments is importable.
+ Paths are added to sys.path in corresponding order to the arguments.
+ We avoid adding duplicate directories to sys.path.
+ `sys.path` is reset to its original value upon exitign this context.
+ """
+ orig = list(sys.path)
+ changes = []
+ for arg in args:
+ path = _get_python_path(arg)
+ if path in changes:
+ continue
+ else:
+ changes.append(path)
+ sys.path[:] = changes + sys.path
+ try:
+ yield
+ finally:
+ sys.path[:] = orig
+
+
class Run(object):
"""helper class to use as main for pylint :
@@ -849,8 +1113,8 @@ group are mutually exclusive.'),
'rcfile': (self.cb_set_rcfile, True),
'load-plugins': (self.cb_add_plugins, True),
})
- except ArgumentPreprocessingError, ex:
- print >> sys.stderr, ex
+ except ArgumentPreprocessingError as ex:
+ print(ex, file=sys.stderr)
sys.exit(32)
self.linter = linter = self.LinterClass((
@@ -879,6 +1143,12 @@ group are mutually exclusive.'),
'group': 'Commands', 'level': 1,
'help' : "Generate pylint's messages."}),
+ ('list-conf-levels',
+ {'action' : 'callback',
+ 'callback' : cb_list_confidence_levels,
+ 'group': 'Commands', 'level': 1,
+ 'help' : "Generate pylint's messages."}),
+
('full-documentation',
{'action' : 'callback', 'metavar': '<msg-id>',
'callback' : self.cb_full_documentation,
@@ -905,6 +1175,12 @@ group are mutually exclusive.'),
'disabled and for others, only the ERROR messages are '
'displayed, and no reports are done by default'''}),
+ ('py3k',
+ {'action' : 'callback', 'callback' : self.cb_python3_porting_mode,
+ 'help' : 'In Python 3 porting mode, all checkers will be '
+ 'disabled and only messages emitted by the porting '
+ 'checker will be displayed'}),
+
('profile',
{'type' : 'yn', 'metavar' : '<y_or_n>',
'default': False, 'hide': True,
@@ -968,28 +1244,42 @@ group are mutually exclusive.'),
linter.set_reporter(reporter)
try:
args = linter.load_command_line_configuration(args)
- except SystemExit, exc:
+ except SystemExit as exc:
if exc.code == 2: # bad options
exc.code = 32
raise
if not args:
- print linter.help()
+ print(linter.help())
+ sys.exit(32)
+
+ if linter.config.jobs < 0:
+ print("Jobs number (%d) should be greater than 0"
+ % linter.config.jobs, file=sys.stderr)
sys.exit(32)
+ if linter.config.jobs > 1 or linter.config.jobs == 0:
+ if multiprocessing is None:
+ print("Multiprocessing library is missing, "
+ "fallback to single process", file=sys.stderr)
+ linter.set_option("jobs", 1)
+ else:
+ if linter.config.jobs == 0:
+ linter.config.jobs = multiprocessing.cpu_count()
+
# insert current working directory to the python path to have a correct
# behaviour
- linter.prepare_import_path(args)
- if self.linter.config.profile:
- print >> sys.stderr, '** profiled run'
- import cProfile, pstats
- cProfile.runctx('linter.check(%r)' % args, globals(), locals(),
- 'stones.prof')
- data = pstats.Stats('stones.prof')
- data.strip_dirs()
- data.sort_stats('time', 'calls')
- data.print_stats(30)
- else:
- linter.check(args)
- linter.cleanup_import_path()
+ with fix_import_path(args):
+ if self.linter.config.profile:
+ print('** profiled run', file=sys.stderr)
+ import cProfile, pstats
+ cProfile.runctx('linter.check(%r)' % args, globals(), locals(),
+ 'stones.prof')
+ data = pstats.Stats('stones.prof')
+ data.strip_dirs()
+ data.sort_stats('time', 'calls')
+ data.print_stats(30)
+ else:
+ linter.check(args)
+ linter.generate_reports()
if exit:
sys.exit(self.linter.msg_status)
@@ -1037,9 +1327,20 @@ group are mutually exclusive.'),
self.linter.msgs_store.list_messages()
sys.exit(0)
+ def cb_python3_porting_mode(self, *args, **kwargs):
+ """Activate only the python3 porting checker."""
+ self.linter.disable('all')
+ self.linter.enable('python3')
+
+
+def cb_list_confidence_levels(option, optname, value, parser):
+ for level in CONFIDENCE_LEVELS:
+ print('%-18s: %s' % level)
+ sys.exit(0)
+
def cb_init_hook(optname, value):
"""exec arbitrary code to set sys.path for instance"""
- exec value
+ exec(value) # pylint: disable=exec-used
if __name__ == '__main__':
« no previous file with comments | « third_party/pylint/interfaces.py ('k') | third_party/pylint/pyreverse/diadefslib.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698