summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAshley Whetter <ashley@awhetter.co.uk>2018-02-24 15:19:38 -0800
committerAshley Whetter <ashley@awhetter.co.uk>2019-02-09 13:27:31 -0800
commit8068def24eac8498cc28563b42314b50fac1c5b8 (patch)
tree4a5eb60523ac13846908d410359f4c5f079e015c
parent2ff1a17ea2307be0fcd7754afac83474031197b8 (diff)
downloadpylint-git-8068def24eac8498cc28563b42314b50fac1c5b8.tar.gz
Moved some reporting functions to runner
-rw-r--r--pylint/lint.py245
-rw-r--r--pylint/reporters/text.py2
-rw-r--r--pylint/utils.py41
3 files changed, 160 insertions, 128 deletions
diff --git a/pylint/lint.py b/pylint/lint.py
index 559b078b0..d129eb9af 100644
--- a/pylint/lint.py
+++ b/pylint/lint.py
@@ -570,47 +570,6 @@ class PyLinter(
if hasattr(module, "load_configuration"):
module.load_configuration(self)
- def load_reporter(self):
- name = self.config.output_format.lower()
- if name in self._reporters:
- self.set_reporter(self._reporters[name]())
- else:
- try:
- reporter_class = self._load_reporter_class()
- except (ImportError, AttributeError):
- raise exceptions.InvalidReporterError(name)
- else:
- self.set_reporter(reporter_class())
-
- def _load_reporter_class(self):
- qname = self.config.output_format
- module = modutils.load_module_from_name(modutils.get_module_part(qname))
- class_name = qname.split(".")[-1]
- reporter_class = getattr(module, class_name)
- return reporter_class
-
- def set_reporter(self, reporter):
- """set the reporter used to display messages and reports"""
- self.reporter = reporter
- reporter.linter = self
-
- def register_reporter(self, reporter_class):
- self._reporters[reporter_class.name] = reporter_class
- if reporter_class.name == self.config.output_format.lower():
- self.load_reporter()
-
- 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 disable_noerror_messages(self):
@@ -791,7 +750,6 @@ class PyLinter(
"""main checking entry: check a list of files or modules from their
name.
"""
- assert self.reporter, "A reporter has not been loaded"
# initialize msgs_state now that all messages have been registered into
# the store
self._init_msg_states()
@@ -924,58 +882,6 @@ class PyLinter(
for msg_cat in utils.MSG_TYPES.values():
self.stats[msg_cat] = 0
- def generate_reports(self):
- """close the whole package /module, it's time to make reports !
-
- if persistent run, pickle results for later comparison
- """
- # Display whatever messages are left on the reporter.
- self.reporter.display_messages(report_nodes.Section())
-
- if self.file_state.base_name is not None:
- # load previous results if any
- previous_stats = config.load_results(self.file_state.base_name)
- # XXX code below needs refactoring to be more reporter agnostic
- self.reporter.on_close(self.stats, previous_stats)
- if self.config.reports:
- sect = self.make_reports(self.stats, previous_stats)
- else:
- sect = report_nodes.Section()
-
- if self.config.reports:
- self.reporter.display_reports(sect)
- self._report_evaluation()
- # save results if persistent run
- if self.config.persistent:
- config.save_results(self.stats, self.file_state.base_name)
- else:
- self.reporter.on_close(self.stats, {})
-
- def _report_evaluation(self):
- """make the global evaluation report"""
- # check with at least check 1 statements (usually 0 when there is a
- # syntax error preventing pylint from further processing)
- previous_stats = config.load_results(self.file_state.base_name)
- if self.stats["statement"] == 0:
- return
-
- # get a global note for the code
- evaluation = self.config.evaluation
- try:
- note = eval(evaluation, {}, self.stats) # pylint: disable=eval-used
- except Exception as ex:
- msg = "An exception occurred while rating: %s" % ex
- else:
- self.stats["global_note"] = note
- msg = "Your code has been rated at %.2f/10" % note
- pnote = previous_stats.get("global_note")
- if pnote is not None:
- msg += " (previous run: %.2f/10, %+.2f)" % (pnote, note - pnote)
-
- if self.config.score:
- sect = report_nodes.EvaluationSection(msg)
- self.reporter.display_reports(sect)
-
# utilities ###################################################################
@@ -1032,8 +938,18 @@ class PluginRegistry(object):
self._checkers = collections.defaultdict(list)
# TODO: Remove. This is needed for the MessagesHandlerMixIn for now.
linter._checkers = self._checkers
+ self._reporters = {}
+ linter._reporters = self._reporters
self._linter = linter
- self.register_checker(linter)
+
+ # TODO: Move elsewhere
+ for r_id, r_title, r_cb in linter.reports:
+ self._linter.register_post_report(r_id, r_title, r_cb)
+
+ self.register_options(linter.options)
+
+ # TODO: Move elsewhere
+ linter.msgs_store.register_messages(linter)
def for_all_checkers(self):
"""Loop through all registered checkers.
@@ -1081,6 +997,16 @@ class PluginRegistry(object):
if not getattr(checker, "enabled", True):
self._linter.disable(checker.name)
+ def register_reporter(self, reporter_class):
+ if reporter_class.name in self._reporters:
+ # TODO: Raise if classes are the same
+ duplicate = self._reporters[reporter_class.name]
+ msg = "A reporter called {} has already been registered ({})."
+ msg = msg.format(reporter.name, duplicate.__class__)
+ warnings.warn(msg)
+
+ self._reporters[reporter_class.name] = reporter_class
+
# For now simply defer missing attributs to the linter,
# until we know what API we want.
def __getattr__(self, attribute):
@@ -1231,10 +1157,12 @@ group are mutually exclusive.",
self._linter = PyLinter()
self._plugin_registry = PluginRegistry(self._linter)
self._loaded_plugins = set()
+ self._global_config = config.Configuration()
+ self._reporter = None
def run(self, args):
# Phase 1: Preprocessing
- option_definitions = self.option_definitions + self._linter.options
+ option_definitions = self.option_definitions + PyLinter.options
parser = config.CLIParser(self.description)
parser.add_option_definitions(option_definitions)
parser.add_help_section("Environment variables", config.ENV_HELP, level=1)
@@ -1270,9 +1198,8 @@ group are mutually exclusive.",
level=1,
)
- global_config = config.Configuration()
- global_config.add_options(option_definitions)
- self._linter.config = global_config
+ self._global_config.add_options(option_definitions)
+ self._linter.config = self._global_config
parsed = parser.preprocess(
args, "init_hook", "rcfile", "load_plugins", "ignore", "ignore_patterns"
@@ -1284,13 +1211,13 @@ group are mutually exclusive.",
# Load rcfile, else system rcfile
file_parser = config.IniFileParser()
- file_parser.add_option_definitions(self._linter.options)
+ file_parser.add_option_definitions(PyLinter.options)
rcfile = parsed.rcfile or config.PYLINTRC
if rcfile:
- file_parser.parse(rcfile, global_config)
+ file_parser.parse(rcfile, self._global_config)
def register_options(options):
- global_config.add_options(options)
+ self._global_config.add_options(options)
parser.add_option_definitions(options)
file_parser.add_option_definitions(options)
@@ -1312,37 +1239,37 @@ group are mutually exclusive.",
# Phase 3: Full load
# Fully load config files
if rcfile:
- file_parser.parse(rcfile, global_config)
+ file_parser.parse(rcfile, self._global_config)
# Fully load CLI into global config
- parser.parse(args, global_config)
+ parser.parse(args, self._global_config)
- if global_config.generate_rcfile:
+ if self._global_config.generate_rcfile:
file_parser.write()
sys.exit(0)
# TODO: if global_config.generate_man
- if global_config.errors_only:
+ if self._global_config.errors_only:
self._linter.errors_mode()
- if global_config.py3k:
+ if self._global_config.py3k:
self._linter.python3_porting_mode()
- if global_config.full_documentation:
+ if self._global_config.full_documentation:
self._linter.print_full_documentation()
sys.exit(0)
- if global_config.list_conf_levels:
+ if self._global_config.list_conf_levels:
for level in interfaces.CONFIDENCE_LEVELS:
print("%-18s: %s" % level)
sys.exit(0)
- if global_config.list_msgs:
+ if self._global_config.list_msgs:
self._linter.msgs_store.list_messages()
sys.exit(0)
- if global_config.help_msg:
- msg = utils._splitstrip(global_config.help_msg)
+ if self._global_config.help_msg:
+ msg = utils._splitstrip(self._global_config.help_msg)
self._linter.msgs_store.help_message(msg)
sys.exit(0)
@@ -1352,13 +1279,13 @@ group are mutually exclusive.",
self._linter.enable("c-extension-no-member")
for checker in self._plugin_registry.for_all_checkers():
- checker.config = global_config
+ checker.config = self._global_config
- with fix_import_path(global_config.module_or_package):
- assert self._linter.config.jobs == 1
- self._linter.check(global_config.module_or_package)
+ with fix_import_path(self._global_config.module_or_package):
+ assert self._global_config.jobs == 1
+ self._linter.check(self._global_config.module_or_package)
- self._linter.generate_reports()
+ self.generate_reports()
if linter.config.exit_zero:
sys.exit(0)
@@ -1384,11 +1311,89 @@ group are mutually exclusive.",
def load_default_plugins(self):
"""Load all of the default plugins."""
- reporters.initialize(self._linter)
+ reporters.initialize(self._plugin_registry)
# Make sure to load the default reporter, because
# the option has been set before the plugins had been loaded.
- if not self._linter.reporter:
- self._linter.load_reporter()
+ if not self._reporter:
+ self.load_reporter()
+
+ def load_reporter(self):
+ name = self._global_config.output_format.lower()
+ if name in self._plugin_registry._reporters:
+ self._reporter = self._plugin_registry._reporters[name]()
+ self._linter.reporter = self._reporter
+ # TODO: Remove the need to do this
+ self._reporter.linter = self._linter
+ else:
+ try:
+ reporter_class = self._load_reporter_class()
+ except (ImportError, AttributeError):
+ raise exceptions.InvalidReporterError(name)
+ else:
+ self._reporter = reporter_class()
+ self._linter.reporter = self._reporter
+ self._reporter.linter = self._linter
+
+ def _load_reporter_class(self):
+ qname = self._global_config.output_format
+ module = modutils.load_module_from_name(modutils.get_module_part(qname))
+ class_name = qname.split(".")[-1]
+ reporter_class = getattr(module, class_name)
+ return reporter_class
+
+ def generate_reports(self):
+ """close the whole package /module, it's time to make reports !
+
+ if persistent run, pickle results for later comparison
+ """
+ # Display whatever messages are left on the reporter.
+ self._reporter.display_messages(report_nodes.Section())
+
+ if self._linter.file_state.base_name is not None:
+ # load previous results if any
+ previous_stats = config.load_results(self._linter.file_state.base_name)
+ # XXX code below needs refactoring to be more reporter agnostic
+ self._reporter.on_close(self._linter.stats, previous_stats)
+ if self._global_config.reports:
+ sect = self._linter.make_reports(self._linter.stats, previous_stats)
+ else:
+ sect = report_nodes.Section()
+
+ if self._global_config.reports:
+ self._reporter.display_reports(sect)
+ self._report_evaluation()
+ # save results if persistent run
+ if self._global_config.persistent:
+ config.save_results(
+ self._linter.stats, self._linter.file_state.base_name
+ )
+ else:
+ self._reporter.on_close(self._linter.stats, {})
+
+ def _report_evaluation(self):
+ """make the global evaluation report"""
+ # check with at least check 1 statements (usually 0 when there is a
+ # syntax error preventing pylint from further processing)
+ previous_stats = config.load_results(self._linter.file_state.base_name)
+ if self._linter.stats["statement"] == 0:
+ return
+
+ # get a global note for the code
+ evaluation = self._global_config.evaluation
+ try:
+ note = eval(evaluation, {}, self._linter.stats) # pylint: disable=eval-used
+ except Exception as ex:
+ msg = "An exception occurred while rating: %s" % ex
+ else:
+ self._linter.stats["global_note"] = note
+ msg = "Your code has been rated at %.2f/10" % note
+ pnote = previous_stats.get("global_note")
+ if pnote is not None:
+ msg += " (previous run: %.2f/10, %+.2f)" % (pnote, note - pnote)
+
+ if self._global_config.score:
+ sect = report_nodes.EvaluationSection(msg)
+ self._reporter.display_reports(sect)
if __name__ == "__main__":
diff --git a/pylint/reporters/text.py b/pylint/reporters/text.py
index 4c682ae05..07a6a2c53 100644
--- a/pylint/reporters/text.py
+++ b/pylint/reporters/text.py
@@ -132,7 +132,7 @@ class TextReporter(BaseReporter):
def __init__(self, output=None):
BaseReporter.__init__(self, output)
self._modules = set()
- self._template = None
+ self._template = self.line_format
def on_set_current_module(self, module, filepath):
self._template = str(self.linter.config.msg_template or self.line_format)
diff --git a/pylint/utils.py b/pylint/utils.py
index aa6535425..f8baa96a7 100644
--- a/pylint/utils.py
+++ b/pylint/utils.py
@@ -1061,28 +1061,55 @@ class ReportsHandlerMixIn:
related methods for the main lint class
"""
+ _POST_CHECKER = object()
+
def __init__(self):
self._reports = collections.defaultdict(list)
self._reports_state = {}
super().__init__()
def report_order(self):
- """ Return a list of reports, sorted in the order
- in which they must be called.
+ """A list of reports, sorted in the order in which they must be called.
+
+ :returns: The list of reports.
+ :rtype: list(BaseChecker or object)
"""
- return list(self._reports)
+ reports = sorted(self._reports, key=lambda x: getattr(x, "name", ""))
+ try:
+ reports.remove(self._POST_CHECKER)
+ except ValueError:
+ pass
+ else:
+ reports.append(self._POST_CHECKER)
+ return reports
def register_report(self, reportid, r_title, r_cb, checker):
"""register a report
- reportid is the unique identifier for the report
- r_title the report's title
- r_cb the method to call to make the report
- checker is the checker defining the report
+ :param reportid: The unique identifier for the report.
+ :type reportid: str
+ :param r_title: The report's title.
+ :type r_title: str
+ :param r_cb: The method to call to make the report.
+ :type r_cb: callable
+ :param checker: The checker defining the report.
+ :type checker: BaseChecker
"""
reportid = reportid.upper()
self._reports[checker].append((reportid, r_title, r_cb))
+ def register_post_report(self, reportid, r_title, r_cb):
+ """Register a report to run last.
+
+ :param reportid: The unique identifier for the report.
+ :type reportid: str
+ :param r_title: The report's title.
+ :type r_title: str
+ :param r_cb: The method to call to make the report.
+ :type r_cb: callable
+ """
+ self.register_report(reportid, r_title, r_cb, self._POST_CHECKER)
+
def enable_report(self, reportid):
"""disable the report of the given id"""
reportid = reportid.upper()