Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor - Burst utils.py into a "utils" and "message" package #2654

Merged
merged 13 commits into from
Mar 9, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion pylint/checkers/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@

from pylint.interfaces import IRawChecker, ITokenChecker
from pylint.checkers import BaseChecker
from pylint.utils import OPTION_RGX, MessagesHandlerMixIn
from pylint.utils import OPTION_RGX
from pylint.message import MessagesHandlerMixIn


class ByIdManagedMessagesChecker(BaseChecker):
Expand Down
29 changes: 15 additions & 14 deletions pylint/lint.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,9 @@
from pylint import checkers
from pylint import interfaces
from pylint import reporters
from pylint.message import MessagesStore, Message, MSG_TYPES, MessagesHandlerMixIn
from pylint.utils import FileState, ASTWalker, ReportsHandlerMixIn, OPTION_RGX, utils
from pylint import exceptions
from pylint import utils
from pylint import config
from pylint.__pkginfo__ import version
from pylint.reporters.ureports import nodes as report_nodes
Expand Down Expand Up @@ -308,8 +309,8 @@ def _run_linter(self, file_or_module):
# pylint: disable=too-many-instance-attributes
class PyLinter(
config.OptionsManagerMixIn,
utils.MessagesHandlerMixIn,
utils.ReportsHandlerMixIn,
MessagesHandlerMixIn,
ReportsHandlerMixIn,
checkers.BaseTokenChecker,
):
"""lint Python modules using external checkers.
Expand Down Expand Up @@ -594,15 +595,15 @@ def __init__(self, options=(), reporter=None, option_groups=(), pylintrc=None):
# some stuff has to be done before ancestors initialization...
#
# messages store / checkers / reporter / astroid manager
self.msgs_store = utils.MessagesStore()
self.msgs_store = MessagesStore()
self.reporter = None
self._reporter_name = None
self._reporters = {}
self._checkers = collections.defaultdict(list)
self._pragma_lineno = {}
self._ignore_file = False
# visit variables
self.file_state = utils.FileState()
self.file_state = FileState()
self.current_name = None
self.current_file = None
self.stats = None
Expand All @@ -620,8 +621,8 @@ def __init__(self, options=(), reporter=None, option_groups=(), pylintrc=None):
astroid_version,
sys.version,
)
utils.MessagesHandlerMixIn.__init__(self)
utils.ReportsHandlerMixIn.__init__(self)
MessagesHandlerMixIn.__init__(self)
ReportsHandlerMixIn.__init__(self)
super(PyLinter, self).__init__(
usage=__doc__, version=full_version, config_file=pylintrc or config.PYLINTRC
)
Expand Down Expand Up @@ -836,7 +837,7 @@ def process_tokens(self, tokens):
for (tok_type, content, start, _, _) in tokens:
if tok_type != tokenize.COMMENT:
continue
match = utils.OPTION_RGX.search(content)
match = OPTION_RGX.search(content)
if match is None:
continue

Expand Down Expand Up @@ -1049,7 +1050,7 @@ def _parallel_check(self, files_or_modules):
(_, self.file_state.base_name, module, messages, stats, msg_status) = result

for msg in messages:
msg = utils.Message(*msg)
msg = Message(*msg)
self.set_current_module(module)
self.reporter.handle_message(msg)

Expand All @@ -1065,7 +1066,7 @@ def _parallel_check(self, files_or_modules):
checker.stats = self.stats

def _do_check(self, files_or_modules):
walker = utils.PyLintASTWalker(self)
walker = ASTWalker(self)
_checkers = self.prepare_checkers()
tokencheckers = [
c
Expand Down Expand Up @@ -1102,7 +1103,7 @@ def _do_check(self, files_or_modules):
ast_node = _ast_from_string(_read_stdin(), filepath, modname)

if ast_node is not None:
self.file_state = utils.FileState(filepath)
self.file_state = FileState(filepath)
self.check_astroid_module(ast_node, walker, rawcheckers, tokencheckers)
# warn about spurious inline messages handling
spurious_messages = self.file_state.iter_spurious_suppression_messages(
Expand All @@ -1124,7 +1125,7 @@ def _do_check(self, files_or_modules):
# XXX to be correct we need to keep module_msgs_state for every
# analyzed module (the problem stands with localized messages which
# are only detected in the .close step)
self.file_state = utils.FileState(descr["basename"])
self.file_state = FileState(descr["basename"])
self._ignore_file = False
# fix the current file (if the source file was not available or
# if it's actually a c extension)
Expand Down Expand Up @@ -1167,7 +1168,7 @@ def set_current_module(self, modname, filepath=None):
self.current_file = filepath or modname
self.stats["by_module"][modname] = {}
self.stats["by_module"][modname]["statement"] = 0
for msg_cat in utils.MSG_TYPES.values():
for msg_cat in MSG_TYPES.values():
self.stats["by_module"][modname][msg_cat] = 0

def get_ast(self, filepath, modname):
Expand Down Expand Up @@ -1223,7 +1224,7 @@ def open(self):
MANAGER.always_load_extensions = self.config.unsafe_load_any_extension
MANAGER.max_inferable_values = self.config.limit_inference_results
MANAGER.extension_package_whitelist.update(self.config.extension_pkg_whitelist)
for msg_cat in utils.MSG_TYPES.values():
for msg_cat in MSG_TYPES.values():
self.stats[msg_cat] = 0

def generate_reports(self):
Expand Down
55 changes: 55 additions & 0 deletions pylint/message/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2006-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
# Copyright (c) 2009 Vincent
# Copyright (c) 2009 Mads Kiilerich <mads@kiilerich.com>
# Copyright (c) 2012-2014 Google, Inc.
# Copyright (c) 2014-2018 Claudiu Popa <pcmanticore@gmail.com>
# Copyright (c) 2014-2015 Michal Nowikowski <godfryd@gmail.com>
# Copyright (c) 2014 LCD 47 <lcd047@gmail.com>
# Copyright (c) 2014 Brett Cannon <brett@python.org>
# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
# Copyright (c) 2014 Damien Nozay <damien.nozay@gmail.com>
# Copyright (c) 2015 Aru Sahni <arusahni@gmail.com>
# Copyright (c) 2015 Florian Bruhin <me@the-compiler.org>
# Copyright (c) 2015 Simu Toni <simutoni@gmail.com>
# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
# Copyright (c) 2016 Łukasz Rogalski <rogalski.91@gmail.com>
# Copyright (c) 2016 Moises Lopez <moylop260@vauxoo.com>
# Copyright (c) 2016 Glenn Matthews <glenn@e-dad.net>
# Copyright (c) 2016 Glenn Matthews <glmatthe@cisco.com>
# Copyright (c) 2016 Ashley Whetter <ashley@awhetter.co.uk>
# Copyright (c) 2016 xmo-odoo <xmo-odoo@users.noreply.github.com>
# Copyright (c) 2017-2018 hippo91 <guillaume.peillex@gmail.com>
# Copyright (c) 2017 Pierre Sassoulas <pierre.sassoulas@cea.fr>
# Copyright (c) 2017 Bryce Guinta <bryce.paul.guinta@gmail.com>
# Copyright (c) 2017 Chris Lamb <chris@chris-lamb.co.uk>
# Copyright (c) 2017 Anthony Sottile <asottile@umich.edu>
# Copyright (c) 2017 Thomas Hisch <t.hisch@gmail.com>
# Copyright (c) 2017 Mikhail Fesenko <proggga@gmail.com>
# Copyright (c) 2017 Craig Citro <craigcitro@gmail.com>
# Copyright (c) 2017 Ville Skyttä <ville.skytta@iki.fi>
# Copyright (c) 2018 ssolanki <sushobhitsolanki@gmail.com>
# Copyright (c) 2018 Sushobhit <31987769+sushobhit27@users.noreply.github.com>
# Copyright (c) 2018 Pierre Sassoulas <pierre.sassoulas@wisebim.fr>
# Copyright (c) 2018 Reverb C <reverbc@users.noreply.github.com>
# Copyright (c) 2018 Nick Drozd <nicholasdrozd@gmail.com>

# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
# For details: https://github.com/PyCQA/pylint/blob/master/COPYING

"""All the classes related to Message handling."""

from pylint.message.constants import (
MSG_STATE_CONFIDENCE,
_SCOPE_EXEMPT,
MSG_STATE_SCOPE_CONFIG,
MSG_STATE_SCOPE_MODULE,
MSG_TYPES,
MSG_TYPES_LONG,
MSG_TYPES_STATUS,
)
from pylint.message.build_message_definition import build_message_def
from pylint.message.message import Message
from pylint.message.message_definition import MessageDefinition
from pylint.message.message_handler_mix_in import MessagesHandlerMixIn
from pylint.message.message_store import MessagesStore
34 changes: 34 additions & 0 deletions pylint/message/build_message_definition.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# -*- coding: utf-8 -*-

# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
# For details: https://github.com/PyCQA/pylint/blob/master/COPYING

import warnings

from pylint.interfaces import IRawChecker, ITokenChecker, implements
from pylint.message.message_definition import MessageDefinition
from pylint.utils.warning_scope import WarningScope


def build_message_def(checker, msgid, msg_tuple):
if implements(checker, (IRawChecker, ITokenChecker)):
default_scope = WarningScope.LINE
else:
default_scope = WarningScope.NODE
options = {}
if len(msg_tuple) > 3:
(msg, symbol, descr, options) = msg_tuple
elif len(msg_tuple) > 2:
(msg, symbol, descr) = msg_tuple
else:
# messages should have a symbol, but for backward compatibility
# they may not.
(msg, descr) = msg_tuple
warnings.warn(
"[pylint 0.26] description of message %s doesn't include "
"a symbolic name" % msgid,
DeprecationWarning,
)
symbol = None
options.setdefault("scope", default_scope)
return MessageDefinition(checker, msgid, msg, descr, symbol, **options)
24 changes: 24 additions & 0 deletions pylint/message/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-

# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
# For details: https://github.com/PyCQA/pylint/blob/master/COPYING

MSG_STATE_CONFIDENCE = 2
_MSG_ORDER = "EWRCIF"
MSG_STATE_SCOPE_CONFIG = 0
MSG_STATE_SCOPE_MODULE = 1

# The line/node distinction does not apply to fatal errors and reports.
_SCOPE_EXEMPT = "FR"

MSG_TYPES = {
"I": "info",
"C": "convention",
"R": "refactor",
"W": "warning",
"E": "error",
"F": "fatal",
}
MSG_TYPES_LONG = {v: k for k, v in MSG_TYPES.items()}

MSG_TYPES_STATUS = {"I": 0, "C": 16, "R": 8, "W": 4, "E": 2, "F": 1}
53 changes: 53 additions & 0 deletions pylint/message/message.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# -*- coding: utf-8 -*-

# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
# For details: https://github.com/PyCQA/pylint/blob/master/COPYING


import collections

from pylint.message.constants import MSG_TYPES

_MsgBase = collections.namedtuple(
"_MsgBase",
[
"msg_id",
"symbol",
"msg",
"C",
"category",
"confidence",
"abspath",
"path",
"module",
"obj",
"line",
"column",
],
)


class Message(_MsgBase):
"""This class represent a message to be issued by the reporters"""

def __new__(cls, msg_id, symbol, location, msg, confidence):
return _MsgBase.__new__(
cls,
msg_id,
symbol,
msg,
msg_id[0],
MSG_TYPES[msg_id[0]],
confidence,
*location
)

def format(self, template):
"""Format the message according to the given template.

The template format is the one of the format method :
cf. http://docs.python.org/2/library/string.html#formatstrings
"""
# For some reason, _asdict on derived namedtuples does not work with
# Python 3.4. Needs some investigation.
return template.format(**dict(zip(self._fields, self)))
77 changes: 77 additions & 0 deletions pylint/message/message_definition.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# -*- coding: utf-8 -*-

# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
# For details: https://github.com/PyCQA/pylint/blob/master/COPYING

import sys

from pylint.exceptions import InvalidMessageError
from pylint.message.constants import MSG_TYPES
from pylint.utils.normalize_text import normalize_text


class MessageDefinition:
def __init__(
self,
checker,
msgid,
msg,
descr,
symbol,
scope,
minversion=None,
maxversion=None,
old_names=None,
):
self.checker = checker
if len(msgid) != 5:
raise InvalidMessageError("Invalid message id %r" % msgid)
if not msgid[0] in MSG_TYPES:
raise InvalidMessageError("Bad message type %s in %r" % (msgid[0], msgid))
self.msgid = msgid
self.msg = msg
self.descr = descr
self.symbol = symbol
self.scope = scope
self.minversion = minversion
self.maxversion = maxversion
self.old_names = old_names or []

def __repr__(self):
return "MessageDefinition:{}".format(self.__dict__)

def may_be_emitted(self):
"""return True if message may be emitted using the current interpreter"""
if self.minversion is not None and self.minversion > sys.version_info:
return False
if self.maxversion is not None and self.maxversion <= sys.version_info:
return False
return True

def format_help(self, checkerref=False):
"""return the help string for the given message id"""
desc = self.descr
if checkerref:
desc += " This message belongs to the %s checker." % self.checker.name
title = self.msg
if self.symbol:
msgid = "%s (%s)" % (self.symbol, self.msgid)
else:
msgid = self.msgid
if self.minversion or self.maxversion:
restr = []
if self.minversion:
restr.append("< %s" % ".".join([str(n) for n in self.minversion]))
if self.maxversion:
restr.append(">= %s" % ".".join([str(n) for n in self.maxversion]))
restr = " or ".join(restr)
if checkerref:
desc += " It can't be emitted when using Python %s." % restr
else:
desc += " This message can't be emitted when using Python %s." % restr
desc = normalize_text(" ".join(desc.split()), indent=" ")
if title != "%s":
title = title.splitlines()[0]

return ":%s: *%s*\n%s" % (msgid, title.rstrip(" "), desc)
return ":%s:\n%s" % (msgid, desc)