diff options
author | Pierre Sassoulas <pierre.sassoulas@gmail.com> | 2018-12-09 14:35:39 +0100 |
---|---|---|
committer | Claudiu Popa <pcmanticore@gmail.com> | 2019-03-09 11:09:29 +0100 |
commit | 16e98598c6d8afc826e3cc8f5612618e24d3ec6a (patch) | |
tree | b14e53435a1c7a8831a3db9d114e3f7e7be6222d /pylint/utils/utils.py | |
parent | 20976c36f1e48061e72379979411bc695564a518 (diff) | |
download | pylint-git-16e98598c6d8afc826e3cc8f5612618e24d3ec6a.tar.gz |
Refactor - Create a file for each class in utils
Diffstat (limited to 'pylint/utils/utils.py')
-rw-r--r-- | pylint/utils/utils.py | 852 |
1 files changed, 12 insertions, 840 deletions
diff --git a/pylint/utils/utils.py b/pylint/utils/utils.py index 5c429652f..6c6cd269b 100644 --- a/pylint/utils/utils.py +++ b/pylint/utils/utils.py @@ -1,5 +1,8 @@ # -*- 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 + from __future__ import print_function import codecs @@ -7,91 +10,16 @@ import collections import os import re import sys -import textwrap import tokenize import warnings -from inspect import cleandoc from os.path import basename, dirname, exists, isdir, join, normpath, splitext -from astroid import Module, modutils, nodes -from pylint.exceptions import EmptyReportError, InvalidMessageError, UnknownMessageError -from pylint.interfaces import UNDEFINED, IRawChecker, ITokenChecker, implements -from pylint.reporters.ureports.nodes import Section - -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} - -_MSG_ORDER = "EWRCIF" -MSG_STATE_SCOPE_CONFIG = 0 -MSG_STATE_SCOPE_MODULE = 1 -MSG_STATE_CONFIDENCE = 2 - -# Allow stopping after the first semicolon/hash encountered, -# so that an option can be continued with the reasons -# why it is active or disabled. -OPTION_RGX = re.compile(r"\s*#.*\bpylint:\s*([^;#]+)[;#]{0,1}") - -# The line/node distinction does not apply to fatal errors and reports. -_SCOPE_EXEMPT = "FR" - - -class WarningScope: - LINE = "line-based-msg" - NODE = "node-based-msg" - - -_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))) +from astroid import Module, modutils +from pylint.interfaces import IRawChecker, ITokenChecker, implements +from pylint.utils.constants import MSG_TYPES, MSG_TYPES_LONG, PY_EXTS +from pylint.utils.message_definition import MessageDefinition +from pylint.utils.normalize_text import normalize_text +from pylint.utils.warning_scope import WarningScope def get_module_and_frameid(node): @@ -164,678 +92,6 @@ def build_message_def(checker, msgid, msg_tuple): return MessageDefinition(checker, msgid, msg, descr, symbol, **options) -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) - - -class MessagesHandlerMixIn: - """a mix-in class containing all the messages related methods for the main - lint class - """ - - __by_id_managed_msgs = [] # type: ignore - - def __init__(self): - self._msgs_state = {} - self.msg_status = 0 - - def _checker_messages(self, checker): - for known_checker in self._checkers[checker.lower()]: - for msgid in known_checker.msgs: - yield msgid - - @classmethod - def clear_by_id_managed_msgs(cls): - cls.__by_id_managed_msgs.clear() - - @classmethod - def get_by_id_managed_msgs(cls): - return cls.__by_id_managed_msgs - - def _register_by_id_managed_msg(self, msgid, line, is_disabled=True): - """If the msgid is a numeric one, then register it to inform the user - it could furnish instead a symbolic msgid.""" - try: - message_definitions = self.msgs_store.get_message_definitions(msgid) - for message_definition in message_definitions: - if msgid == message_definition.msgid: - MessagesHandlerMixIn.__by_id_managed_msgs.append( - ( - self.current_name, - message_definition.msgid, - message_definition.symbol, - line, - is_disabled, - ) - ) - except UnknownMessageError: - pass - - def disable(self, msgid, scope="package", line=None, ignore_unknown=False): - """don't output message of the given id""" - self._set_msg_status( - msgid, enable=False, scope=scope, line=line, ignore_unknown=ignore_unknown - ) - self._register_by_id_managed_msg(msgid, line) - - def enable(self, msgid, scope="package", line=None, ignore_unknown=False): - """reenable message of the given id""" - self._set_msg_status( - msgid, enable=True, scope=scope, line=line, ignore_unknown=ignore_unknown - ) - self._register_by_id_managed_msg(msgid, line, is_disabled=False) - - def _set_msg_status( - self, msgid, enable, scope="package", line=None, ignore_unknown=False - ): - assert scope in ("package", "module") - - if msgid == "all": - for _msgid in MSG_TYPES: - self._set_msg_status(_msgid, enable, scope, line, ignore_unknown) - if enable and not self._python3_porting_mode: - # Don't activate the python 3 porting checker if it wasn't activated explicitly. - self.disable("python3") - return - - # msgid is a category? - catid = category_id(msgid) - if catid is not None: - for _msgid in self.msgs_store._msgs_by_category.get(catid): - self._set_msg_status(_msgid, enable, scope, line) - return - - # msgid is a checker name? - if msgid.lower() in self._checkers: - msgs_store = self.msgs_store - for checker in self._checkers[msgid.lower()]: - for _msgid in checker.msgs: - if _msgid in msgs_store._alternative_names: - self._set_msg_status(_msgid, enable, scope, line) - return - - # msgid is report id? - if msgid.lower().startswith("rp"): - if enable: - self.enable_report(msgid) - else: - self.disable_report(msgid) - return - - try: - # msgid is a symbolic or numeric msgid. - message_definitions = self.msgs_store.get_message_definitions(msgid) - except UnknownMessageError: - if ignore_unknown: - return - raise - for message_definition in message_definitions: - self._set_one_msg_status(scope, message_definition, line, enable) - - def _set_one_msg_status(self, scope, msg, line, enable): - if scope == "module": - self.file_state.set_msg_status(msg, line, enable) - if not enable and msg.symbol != "locally-disabled": - self.add_message( - "locally-disabled", line=line, args=(msg.symbol, msg.msgid) - ) - else: - msgs = self._msgs_state - msgs[msg.msgid] = enable - # sync configuration object - self.config.enable = [ - self._message_symbol(mid) for mid, val in sorted(msgs.items()) if val - ] - self.config.disable = [ - self._message_symbol(mid) - for mid, val in sorted(msgs.items()) - if not val - ] - - def _message_symbol(self, msgid): - """Get the message symbol of the given message id - - Return the original message id if the message does not - exist. - """ - try: - return [md.symbol for md in self.msgs_store.get_message_definitions(msgid)] - except UnknownMessageError: - return msgid - - def get_message_state_scope(self, msgid, line=None, confidence=UNDEFINED): - """Returns the scope at which a message was enabled/disabled.""" - if self.config.confidence and confidence.name not in self.config.confidence: - return MSG_STATE_CONFIDENCE - try: - if line in self.file_state._module_msgs_state[msgid]: - return MSG_STATE_SCOPE_MODULE - except (KeyError, TypeError): - return MSG_STATE_SCOPE_CONFIG - return None - - def is_message_enabled(self, msg_descr, line=None, confidence=None): - """return true if the message associated to the given message id is - enabled - - msgid may be either a numeric or symbolic message id. - """ - if self.config.confidence and confidence: - if confidence.name not in self.config.confidence: - return False - try: - message_definitions = self.msgs_store.get_message_definitions(msg_descr) - msgids = [md.msgid for md in message_definitions] - except UnknownMessageError: - # The linter checks for messages that are not registered - # due to version mismatch, just treat them as message IDs - # for now. - msgids = [msg_descr] - for msgid in msgids: - if self.is_one_message_enabled(msgid, line): - return True - return False - - def is_one_message_enabled(self, msgid, line): - if line is None: - return self._msgs_state.get(msgid, True) - try: - return self.file_state._module_msgs_state[msgid][line] - except KeyError: - # Check if the message's line is after the maximum line existing in ast tree. - # This line won't appear in the ast tree and won't be referred in - # self.file_state._module_msgs_state - # This happens for example with a commented line at the end of a module. - max_line_number = self.file_state.get_effective_max_line_number() - if max_line_number and line > max_line_number: - fallback = True - lines = self.file_state._raw_module_msgs_state.get(msgid, {}) - - # Doesn't consider scopes, as a disable can be in a different scope - # than that of the current line. - closest_lines = reversed( - [ - (message_line, enable) - for message_line, enable in lines.items() - if message_line <= line - ] - ) - last_line, is_enabled = next(closest_lines, (None, None)) - if last_line is not None: - fallback = is_enabled - - return self._msgs_state.get(msgid, fallback) - return self._msgs_state.get(msgid, True) - - def add_message( - self, - msg_descr, - line=None, - node=None, - args=None, - confidence=UNDEFINED, - col_offset=None, - ): - """Adds a message given by ID or name. - - If provided, the message string is expanded using args. - - AST checkers must provide the node argument (but may optionally - provide line if the line number is different), raw and token checkers - must provide the line argument. - """ - message_definitions = self.msgs_store.get_message_definitions(msg_descr) - for message_definition in message_definitions: - self.add_one_message( - message_definition, line, node, args, confidence, col_offset - ) - - def add_one_message( - self, message_definition, line, node, args, confidence, col_offset - ): - msgid = message_definition.msgid - # backward compatibility, message may not have a symbol - symbol = message_definition.symbol or msgid - # Fatal messages and reports are special, the node/scope distinction - # does not apply to them. - if msgid[0] not in _SCOPE_EXEMPT: - if message_definition.scope == WarningScope.LINE: - if line is None: - raise InvalidMessageError( - "Message %s must provide line, got None" % msgid - ) - if node is not None: - raise InvalidMessageError( - "Message %s must only provide line, " - "got line=%s, node=%s" % (msgid, line, node) - ) - elif message_definition.scope == WarningScope.NODE: - # Node-based warnings may provide an override line. - if node is None: - raise InvalidMessageError( - "Message %s must provide Node, got None" % msgid - ) - - if line is None and node is not None: - line = node.fromlineno - if col_offset is None and hasattr(node, "col_offset"): - col_offset = ( - node.col_offset - ) # XXX measured in bytes for utf-8, divide by two for chars? - - # should this message be displayed - if not self.is_message_enabled(msgid, line, confidence): - self.file_state.handle_ignored_message( - self.get_message_state_scope(msgid, line, confidence), - msgid, - line, - node, - args, - confidence, - ) - return - # update stats - msg_cat = MSG_TYPES[msgid[0]] - self.msg_status |= MSG_TYPES_STATUS[msgid[0]] - self.stats[msg_cat] += 1 - self.stats["by_module"][self.current_name][msg_cat] += 1 - try: - self.stats["by_msg"][symbol] += 1 - except KeyError: - self.stats["by_msg"][symbol] = 1 - # expand message ? - msg = message_definition.msg - if args: - msg %= args - # get module and object - if node is None: - module, obj = self.current_name, "" - abspath = self.current_file - else: - module, obj = get_module_and_frameid(node) - abspath = node.root().file - path = abspath.replace(self.reporter.path_strip_prefix, "", 1) - # add the message - self.reporter.handle_message( - Message( - msgid, - symbol, - (abspath, path, module, obj, line or 1, col_offset or 0), - msg, - confidence, - ) - ) - - def print_full_documentation(self, stream=None): - """output a full documentation in ReST format""" - if not stream: - stream = sys.stdout - - print("Pylint global options and switches", file=stream) - print("----------------------------------", file=stream) - print("", file=stream) - print("Pylint provides global options and switches.", file=stream) - print("", file=stream) - - by_checker = {} - for checker in self.get_checkers(): - if checker.name == "master": - if checker.options: - for section, options in checker.options_by_section(): - if section is None: - title = "General options" - else: - title = "%s options" % section.capitalize() - print(title, file=stream) - print("~" * len(title), file=stream) - _rest_format_section(stream, None, options) - print("", file=stream) - else: - name = checker.name - try: - by_checker[name]["options"] += checker.options_and_values() - by_checker[name]["msgs"].update(checker.msgs) - by_checker[name]["reports"] += checker.reports - except KeyError: - by_checker[name] = { - "options": list(checker.options_and_values()), - "msgs": dict(checker.msgs), - "reports": list(checker.reports), - } - - print("Pylint checkers' options and switches", file=stream) - print("-------------------------------------", file=stream) - print("", file=stream) - print("Pylint checkers can provide three set of features:", file=stream) - print("", file=stream) - print("* options that control their execution,", file=stream) - print("* messages that they can raise,", file=stream) - print("* reports that they can generate.", file=stream) - print("", file=stream) - print("Below is a list of all checkers and their features.", file=stream) - print("", file=stream) - - for checker, info in sorted(by_checker.items()): - self._print_checker_doc(checker, info, stream=stream) - - @staticmethod - def _print_checker_doc(checker_name, info, stream=None): - """Helper method for print_full_documentation. - - Also used by doc/exts/pylint_extensions.py. - """ - if not stream: - stream = sys.stdout - - doc = info.get("doc") - module = info.get("module") - msgs = info.get("msgs") - options = info.get("options") - reports = info.get("reports") - - checker_title = "%s checker" % (checker_name.replace("_", " ").title()) - - if module: - # Provide anchor to link against - print(".. _%s:\n" % module, file=stream) - print(checker_title, file=stream) - print("~" * len(checker_title), file=stream) - print("", file=stream) - if module: - print("This checker is provided by ``%s``." % module, file=stream) - print("Verbatim name of the checker is ``%s``." % checker_name, file=stream) - print("", file=stream) - if doc: - # Provide anchor to link against - title = "{} Documentation".format(checker_title) - print(title, file=stream) - print("^" * len(title), file=stream) - print(cleandoc(doc), file=stream) - print("", file=stream) - if options: - title = "{} Options".format(checker_title) - print(title, file=stream) - print("^" * len(title), file=stream) - _rest_format_section(stream, None, options) - print("", file=stream) - if msgs: - title = "{} Messages".format(checker_title) - print(title, file=stream) - print("^" * len(title), file=stream) - for msgid, msg in sorted( - msgs.items(), key=lambda kv: (_MSG_ORDER.index(kv[0][0]), kv[1]) - ): - msg = build_message_def(checker_name, msgid, msg) - print(msg.format_help(checkerref=False), file=stream) - print("", file=stream) - if reports: - title = "{} Reports".format(checker_title) - print(title, file=stream) - print("^" * len(title), file=stream) - for report in reports: - print(":%s: %s" % report[:2], file=stream) - print("", file=stream) - print("", file=stream) - - -class FileState: - """Hold internal state specific to the currently analyzed file""" - - def __init__(self, modname=None): - self.base_name = modname - self._module_msgs_state = {} - self._raw_module_msgs_state = {} - self._ignored_msgs = collections.defaultdict(set) - self._suppression_mapping = {} - self._effective_max_line_number = None - - def collect_block_lines(self, msgs_store, module_node): - """Walk the AST to collect block level options line numbers.""" - for msg, lines in self._module_msgs_state.items(): - self._raw_module_msgs_state[msg] = lines.copy() - orig_state = self._module_msgs_state.copy() - self._module_msgs_state = {} - self._suppression_mapping = {} - self._effective_max_line_number = module_node.tolineno - self._collect_block_lines(msgs_store, module_node, orig_state) - - def _collect_block_lines(self, msgs_store, node, msg_state): - """Recursively walk (depth first) AST to collect block level options - line numbers. - """ - for child in node.get_children(): - self._collect_block_lines(msgs_store, child, msg_state) - first = node.fromlineno - last = node.tolineno - # first child line number used to distinguish between disable - # which are the first child of scoped node with those defined later. - # For instance in the code below: - # - # 1. def meth8(self): - # 2. """test late disabling""" - # 3. # pylint: disable=E1102 - # 4. print self.blip - # 5. # pylint: disable=E1101 - # 6. print self.bla - # - # E1102 should be disabled from line 1 to 6 while E1101 from line 5 to 6 - # - # this is necessary to disable locally messages applying to class / - # function using their fromlineno - if ( - isinstance(node, (nodes.Module, nodes.ClassDef, nodes.FunctionDef)) - and node.body - ): - firstchildlineno = node.body[0].fromlineno - else: - firstchildlineno = last - for msgid, lines in msg_state.items(): - for lineno, state in list(lines.items()): - original_lineno = lineno - if first > lineno or last < lineno: - continue - # Set state for all lines for this block, if the - # warning is applied to nodes. - message_definitions = msgs_store.get_message_definitions(msgid) - for message_definition in message_definitions: - if message_definition.scope == WarningScope.NODE: - if lineno > firstchildlineno: - state = True - first_, last_ = node.block_range(lineno) - else: - first_ = lineno - last_ = last - for line in range(first_, last_ + 1): - # do not override existing entries - if line in self._module_msgs_state.get(msgid, ()): - continue - if line in lines: # state change in the same block - state = lines[line] - original_lineno = line - if not state: - self._suppression_mapping[(msgid, line)] = original_lineno - try: - self._module_msgs_state[msgid][line] = state - except KeyError: - self._module_msgs_state[msgid] = {line: state} - del lines[lineno] - - def set_msg_status(self, msg, line, status): - """Set status (enabled/disable) for a given message at a given line""" - assert line > 0 - try: - self._module_msgs_state[msg.msgid][line] = status - except KeyError: - self._module_msgs_state[msg.msgid] = {line: status} - - def handle_ignored_message( - self, state_scope, msgid, line, node, args, confidence - ): # pylint: disable=unused-argument - """Report an ignored message. - - state_scope is either MSG_STATE_SCOPE_MODULE or MSG_STATE_SCOPE_CONFIG, - depending on whether the message was disabled locally in the module, - or globally. The other arguments are the same as for add_message. - """ - if state_scope == MSG_STATE_SCOPE_MODULE: - try: - orig_line = self._suppression_mapping[(msgid, line)] - self._ignored_msgs[(msgid, orig_line)].add(line) - except KeyError: - pass - - def iter_spurious_suppression_messages(self, msgs_store): - for warning, lines in self._raw_module_msgs_state.items(): - for line, enable in lines.items(): - if not enable and (warning, line) not in self._ignored_msgs: - yield "useless-suppression", line, ( - msgs_store.get_msg_display_string(warning), - ) - # don't use iteritems here, _ignored_msgs may be modified by add_message - for (warning, from_), lines in list(self._ignored_msgs.items()): - for line in lines: - yield "suppressed-message", line, ( - msgs_store.get_msg_display_string(warning), - from_, - ) - - def get_effective_max_line_number(self): - return self._effective_max_line_number - - -class ReportsHandlerMixIn: - """a mix-in class containing all the reports and stats manipulation - related methods for the main lint class - """ - - def __init__(self): - self._reports = collections.defaultdict(list) - self._reports_state = {} - - def report_order(self): - """ Return a list of reports, sorted in the order - in which they must be called. - """ - return list(self._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 - """ - reportid = reportid.upper() - self._reports[checker].append((reportid, r_title, r_cb)) - - def enable_report(self, reportid): - """disable the report of the given id""" - reportid = reportid.upper() - self._reports_state[reportid] = True - - def disable_report(self, reportid): - """disable the report of the given id""" - reportid = reportid.upper() - self._reports_state[reportid] = False - - def report_is_enabled(self, reportid): - """return true if the report associated to the given identifier is - enabled - """ - return self._reports_state.get(reportid, True) - - def make_reports(self, stats, old_stats): - """render registered reports""" - sect = Section("Report", "%s statements analysed." % (self.stats["statement"])) - for checker in self.report_order(): - for reportid, r_title, r_cb in self._reports[checker]: - if not self.report_is_enabled(reportid): - continue - report_sect = Section(r_title) - try: - r_cb(report_sect, stats, old_stats) - except EmptyReportError: - continue - report_sect.report_id = reportid - sect.append(report_sect) - return sect - - def add_stats(self, **kwargs): - """add some stats entries to the statistic dictionary - raise an AssertionError if there is a key conflict - """ - for key, value in kwargs.items(): - if key[-1] == "_": - key = key[:-1] - assert key not in self.stats - self.stats[key] = value - return self.stats - - def _basename_in_blacklist_re(base_name, black_list_re): """Determines if the basename is matched in a regex blacklist @@ -947,81 +203,6 @@ def expand_modules(files_or_modules, black_list, black_list_re): return result, errors -class PyLintASTWalker: - def __init__(self, linter): - # callbacks per node types - self.nbstatements = 0 - self.visit_events = collections.defaultdict(list) - self.leave_events = collections.defaultdict(list) - self.linter = linter - - def _is_method_enabled(self, method): - if not hasattr(method, "checks_msgs"): - return True - for msg_desc in method.checks_msgs: - if self.linter.is_message_enabled(msg_desc): - return True - return False - - def add_checker(self, checker): - """walk to the checker's dir and collect visit and leave methods""" - # XXX : should be possible to merge needed_checkers and add_checker - vcids = set() - lcids = set() - visits = self.visit_events - leaves = self.leave_events - for member in dir(checker): - cid = member[6:] - if cid == "default": - continue - if member.startswith("visit_"): - v_meth = getattr(checker, member) - # don't use visit_methods with no activated message: - if self._is_method_enabled(v_meth): - visits[cid].append(v_meth) - vcids.add(cid) - elif member.startswith("leave_"): - l_meth = getattr(checker, member) - # don't use leave_methods with no activated message: - if self._is_method_enabled(l_meth): - leaves[cid].append(l_meth) - lcids.add(cid) - visit_default = getattr(checker, "visit_default", None) - if visit_default: - for cls in nodes.ALL_NODE_CLASSES: - cid = cls.__name__.lower() - if cid not in vcids: - visits[cid].append(visit_default) - # for now we have no "leave_default" method in Pylint - - def walk(self, astroid): - """call visit events of astroid checkers for the given node, recurse on - its children, then leave events. - """ - cid = astroid.__class__.__name__.lower() - - # Detect if the node is a new name for a deprecated alias. - # In this case, favour the methods for the deprecated - # alias if any, in order to maintain backwards - # compatibility. - visit_events = self.visit_events.get(cid, ()) - leave_events = self.leave_events.get(cid, ()) - - if astroid.is_statement: - self.nbstatements += 1 - # generate events for this node on each checker - for cb in visit_events or (): - cb(astroid) - # recurse on children - for child in astroid.get_children(): - self.walk(child) - for cb in leave_events or (): - cb(astroid) - - -PY_EXTS = (".py", ".pyc", ".pyo", ".pyw", ".so", ".dll") - - def register_plugins(linter, directory): """load all module and package in the given directory, looking for a 'register' function in each one, used to register pylint checkers @@ -1134,15 +315,6 @@ def _unquote(string): return string -def _normalize_text(text, line_len=80, indent=""): - """Wrap the text on the given line length.""" - return "\n".join( - textwrap.wrap( - text, width=line_len, initial_indent=indent, subsequent_indent=indent - ) - ) - - def _check_csv(value): if isinstance(value, (list, tuple)): return value @@ -1185,7 +357,7 @@ def _ini_format(stream, options): value = _format_option_value(optdict, value) help_opt = optdict.get("help") if help_opt: - help_opt = _normalize_text(help_opt, line_len=79, indent="# ") + help_opt = normalize_text(help_opt, line_len=79, indent="# ") print(file=stream) print(help_opt, file=stream) else: @@ -1210,13 +382,13 @@ def _rest_format_section(stream, section, options, doc=None): if section: print("%s\n%s" % (section, "'" * len(section)), file=stream) if doc: - print(_normalize_text(doc, line_len=79, indent=""), file=stream) + print(normalize_text(doc, line_len=79, indent=""), file=stream) print(file=stream) for optname, optdict, value in options: help_opt = optdict.get("help") print(":%s:" % optname, file=stream) if help_opt: - help_opt = _normalize_text(help_opt, line_len=79, indent=" ") + help_opt = normalize_text(help_opt, line_len=79, indent=" ") print(help_opt, file=stream) if value: value = str(_format_option_value(optdict, value)) |