diff options
Diffstat (limited to 'venv/Lib/site-packages/pylint/message')
12 files changed, 802 insertions, 0 deletions
diff --git a/venv/Lib/site-packages/pylint/message/__init__.py b/venv/Lib/site-packages/pylint/message/__init__.py new file mode 100644 index 0000000..5ac8411 --- /dev/null +++ b/venv/Lib/site-packages/pylint/message/__init__.py @@ -0,0 +1,54 @@ +# -*- 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.message import Message +from pylint.message.message_definition import MessageDefinition +from pylint.message.message_definition_store import MessageDefinitionStore +from pylint.message.message_handler_mix_in import MessagesHandlerMixIn +from pylint.message.message_id_store import MessageIdStore + +__all__ = [ + "Message", + "MessageDefinition", + "MessageDefinitionStore", + "MessagesHandlerMixIn", + "MessageIdStore", +] diff --git a/venv/Lib/site-packages/pylint/message/__pycache__/__init__.cpython-37.pyc b/venv/Lib/site-packages/pylint/message/__pycache__/__init__.cpython-37.pyc Binary files differnew file mode 100644 index 0000000..f3462f1 --- /dev/null +++ b/venv/Lib/site-packages/pylint/message/__pycache__/__init__.cpython-37.pyc diff --git a/venv/Lib/site-packages/pylint/message/__pycache__/message.cpython-37.pyc b/venv/Lib/site-packages/pylint/message/__pycache__/message.cpython-37.pyc Binary files differnew file mode 100644 index 0000000..6c89577 --- /dev/null +++ b/venv/Lib/site-packages/pylint/message/__pycache__/message.cpython-37.pyc diff --git a/venv/Lib/site-packages/pylint/message/__pycache__/message_definition.cpython-37.pyc b/venv/Lib/site-packages/pylint/message/__pycache__/message_definition.cpython-37.pyc Binary files differnew file mode 100644 index 0000000..952803b --- /dev/null +++ b/venv/Lib/site-packages/pylint/message/__pycache__/message_definition.cpython-37.pyc diff --git a/venv/Lib/site-packages/pylint/message/__pycache__/message_definition_store.cpython-37.pyc b/venv/Lib/site-packages/pylint/message/__pycache__/message_definition_store.cpython-37.pyc Binary files differnew file mode 100644 index 0000000..ce6f867 --- /dev/null +++ b/venv/Lib/site-packages/pylint/message/__pycache__/message_definition_store.cpython-37.pyc diff --git a/venv/Lib/site-packages/pylint/message/__pycache__/message_handler_mix_in.cpython-37.pyc b/venv/Lib/site-packages/pylint/message/__pycache__/message_handler_mix_in.cpython-37.pyc Binary files differnew file mode 100644 index 0000000..23cc65a --- /dev/null +++ b/venv/Lib/site-packages/pylint/message/__pycache__/message_handler_mix_in.cpython-37.pyc diff --git a/venv/Lib/site-packages/pylint/message/__pycache__/message_id_store.cpython-37.pyc b/venv/Lib/site-packages/pylint/message/__pycache__/message_id_store.cpython-37.pyc Binary files differnew file mode 100644 index 0000000..f132b88 --- /dev/null +++ b/venv/Lib/site-packages/pylint/message/__pycache__/message_id_store.cpython-37.pyc diff --git a/venv/Lib/site-packages/pylint/message/message.py b/venv/Lib/site-packages/pylint/message/message.py new file mode 100644 index 0000000..e2b0320 --- /dev/null +++ b/venv/Lib/site-packages/pylint/message/message.py @@ -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.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))) diff --git a/venv/Lib/site-packages/pylint/message/message_definition.py b/venv/Lib/site-packages/pylint/message/message_definition.py new file mode 100644 index 0000000..e54c15a --- /dev/null +++ b/venv/Lib/site-packages/pylint/message/message_definition.py @@ -0,0 +1,84 @@ +# -*- 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.constants import MSG_TYPES +from pylint.exceptions import InvalidMessageError +from pylint.utils import normalize_text + + +class MessageDefinition: + def __init__( + self, + checker, + msgid, + msg, + description, + symbol, + scope, + minversion=None, + maxversion=None, + old_names=None, + ): + self.checker = checker + self.check_msgid(msgid) + self.msgid = msgid + self.symbol = symbol + self.msg = msg + self.description = description + self.scope = scope + self.minversion = minversion + self.maxversion = maxversion + self.old_names = [] + if old_names: + for old_msgid, old_symbol in old_names: + self.check_msgid(old_msgid) + self.old_names.append([old_msgid, old_symbol]) + + @staticmethod + def check_msgid(msgid: str) -> None: + if len(msgid) != 5: + raise InvalidMessageError("Invalid message id %r" % msgid) + if msgid[0] not in MSG_TYPES: + raise InvalidMessageError("Bad message type %s in %r" % (msgid[0], msgid)) + + def __repr__(self): + return "MessageDefinition:%s (%s)" % (self.symbol, self.msgid) + + def __str__(self): + return "%s:\n%s %s" % (repr(self), self.msg, self.description) + + 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.description + if checkerref: + desc += " This message belongs to the %s checker." % self.checker.name + title = self.msg + 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 + msg_help = normalize_text(" ".join(desc.split()), indent=" ") + message_id = "%s (%s)" % (self.symbol, self.msgid) + if title != "%s": + title = title.splitlines()[0] + return ":%s: *%s*\n%s" % (message_id, title.rstrip(" "), msg_help) + return ":%s:\n%s" % (message_id, msg_help) diff --git a/venv/Lib/site-packages/pylint/message/message_definition_store.py b/venv/Lib/site-packages/pylint/message/message_definition_store.py new file mode 100644 index 0000000..f7d87b6 --- /dev/null +++ b/venv/Lib/site-packages/pylint/message/message_definition_store.py @@ -0,0 +1,90 @@ +# -*- 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.exceptions import UnknownMessageError +from pylint.message.message_id_store import MessageIdStore + + +class MessageDefinitionStore: + + """The messages store knows information about every possible message definition but has + no particular state during analysis. + """ + + def __init__(self): + self.message_id_store = MessageIdStore() + # Primary registry for all active messages definitions. + # It contains the 1:1 mapping from msgid to MessageDefinition. + # Keys are msgid, values are MessageDefinition + self._messages_definitions = {} + # MessageDefinition kept by category + self._msgs_by_category = collections.defaultdict(list) + + @property + def messages(self) -> list: + """The list of all active messages.""" + return self._messages_definitions.values() + + def register_messages_from_checker(self, checker): + """Register all messages definitions from a checker. + + :param BaseChecker checker: + """ + checker.check_consistency() + for message in checker.messages: + self.register_message(message) + + def register_message(self, message): + """Register a MessageDefinition with consistency in mind. + + :param MessageDefinition message: The message definition being added. + """ + self.message_id_store.register_message_definition(message) + self._messages_definitions[message.msgid] = message + self._msgs_by_category[message.msgid[0]].append(message.msgid) + + def get_message_definitions(self, msgid_or_symbol: str) -> list: + """Returns the Message object for this message. + :param str msgid_or_symbol: msgid_or_symbol may be either a numeric or symbolic id. + :raises UnknownMessageError: if the message id is not defined. + :rtype: List of MessageDefinition + :return: A message definition corresponding to msgid_or_symbol + """ + return [ + self._messages_definitions[m] + for m in self.message_id_store.get_active_msgids(msgid_or_symbol) + ] + + def get_msg_display_string(self, msgid_or_symbol: str): + """Generates a user-consumable representation of a message. """ + message_definitions = self.get_message_definitions(msgid_or_symbol) + if len(message_definitions) == 1: + return repr(message_definitions[0].symbol) + return repr([md.symbol for md in message_definitions]) + + def help_message(self, msgids_or_symbols: list): + """Display help messages for the given message identifiers""" + for msgids_or_symbol in msgids_or_symbols: + try: + for message_definition in self.get_message_definitions( + msgids_or_symbol + ): + print(message_definition.format_help(checkerref=True)) + print("") + except UnknownMessageError as ex: + print(ex) + print("") + continue + + def list_messages(self): + """Output full messages list documentation in ReST format. """ + messages = sorted(self._messages_definitions.values(), key=lambda m: m.msgid) + for message in messages: + if not message.may_be_emitted(): + continue + print(message.format_help(checkerref=False)) + print("") diff --git a/venv/Lib/site-packages/pylint/message/message_handler_mix_in.py b/venv/Lib/site-packages/pylint/message/message_handler_mix_in.py new file mode 100644 index 0000000..813cdd7 --- /dev/null +++ b/venv/Lib/site-packages/pylint/message/message_handler_mix_in.py @@ -0,0 +1,393 @@ +# -*- 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.constants import ( + _SCOPE_EXEMPT, + MAIN_CHECKER_NAME, + MSG_STATE_CONFIDENCE, + MSG_STATE_SCOPE_CONFIG, + MSG_STATE_SCOPE_MODULE, + MSG_TYPES, + MSG_TYPES_LONG, + MSG_TYPES_STATUS, + WarningScope, +) +from pylint.exceptions import InvalidMessageError, UnknownMessageError +from pylint.interfaces import UNDEFINED +from pylint.message.message import Message +from pylint.utils import get_module_and_frameid, get_rst_section, get_rst_title + + +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? + category_id = msgid.upper() + if category_id not in MSG_TYPES: + category_id = MSG_TYPES_LONG.get(category_id) + if category_id is not None: + for _msgid in self.msgs_store._msgs_by_category.get(category_id): + self._set_msg_status(_msgid, enable, scope, line) + return + + # msgid is a checker name? + if msgid.lower() in self._checkers: + for checker in self._checkers[msgid.lower()]: + for _msgid in checker.msgs: + 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, msgid, line=None, node=None, args=None, confidence=None, 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. + """ + if confidence is None: + confidence = UNDEFINED + message_definitions = self.msgs_store.get_message_definitions(msgid) + for message_definition in message_definitions: + self.add_one_message( + message_definition, line, node, args, confidence, col_offset + ) + + @staticmethod + def check_message_definition(message_definition, line, node): + if message_definition.msgid[0] not in _SCOPE_EXEMPT: + # Fatal messages and reports are special, the node/scope distinction + # does not apply to them. + if message_definition.scope == WarningScope.LINE: + if line is None: + raise InvalidMessageError( + "Message %s must provide line, got None" + % message_definition.msgid + ) + if node is not None: + raise InvalidMessageError( + "Message %s must only provide line, " + "got line=%s, node=%s" % (message_definition.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" + % message_definition.msgid + ) + + def add_one_message( + self, message_definition, line, node, args, confidence, col_offset + ): + self.check_message_definition(message_definition, line, node) + 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 + + # should this message be displayed + if not self.is_message_enabled(message_definition.msgid, line, confidence): + self.file_state.handle_ignored_message( + self.get_message_state_scope( + message_definition.msgid, line, confidence + ), + message_definition.msgid, + line, + node, + args, + confidence, + ) + return + # update stats + msg_cat = MSG_TYPES[message_definition.msgid[0]] + self.msg_status |= MSG_TYPES_STATUS[message_definition.msgid[0]] + self.stats[msg_cat] += 1 + self.stats["by_module"][self.current_name][msg_cat] += 1 + try: + self.stats["by_msg"][message_definition.symbol] += 1 + except KeyError: + self.stats["by_msg"][message_definition.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( + message_definition.msgid, + message_definition.symbol, + (abspath, path, module, obj, line or 1, col_offset or 0), + msg, + confidence, + ) + ) + + def _get_checkers_infos(self): + by_checker = {} + for checker in self.get_checkers(): + name = checker.name + if name != "master": + try: + by_checker[name]["checker"] = checker + 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] = { + "checker": checker, + "options": list(checker.options_and_values()), + "msgs": dict(checker.msgs), + "reports": list(checker.reports), + } + return by_checker + + def get_checkers_documentation(self): + result = get_rst_title("Pylint global options and switches", "-") + result += """ +Pylint provides global options and switches. + +""" + for checker in self.get_checkers(): + name = checker.name + if name == MAIN_CHECKER_NAME: + if checker.options: + for section, options in checker.options_by_section(): + if section is None: + title = "General options" + else: + title = "%s options" % section.capitalize() + result += get_rst_title(title, "~") + result += "%s\n" % get_rst_section(None, options) + result += get_rst_title("Pylint checkers' options and switches", "-") + result += """\ + +Pylint checkers can provide three set of features: + +* options that control their execution, +* messages that they can raise, +* reports that they can generate. + +Below is a list of all checkers and their features. + +""" + by_checker = self._get_checkers_infos() + for checker in sorted(by_checker): + information = by_checker[checker] + checker = information["checker"] + del information["checker"] + result += checker.get_full_documentation(**information) + return result + + def print_full_documentation(self, stream=None): + """output a full documentation in ReST format""" + if not stream: + stream = sys.stdout + print(self.get_checkers_documentation()[:-1], file=stream) + + @staticmethod + def _print_checker_doc(information, stream=None): + """Helper method for print_full_documentation. + + Also used by doc/exts/pylint_extensions.py. + """ + if not stream: + stream = sys.stdout + checker = information["checker"] + del information["checker"] + print(checker.get_full_documentation(**information)[:-1], file=stream) diff --git a/venv/Lib/site-packages/pylint/message/message_id_store.py b/venv/Lib/site-packages/pylint/message/message_id_store.py new file mode 100644 index 0000000..756888a --- /dev/null +++ b/venv/Lib/site-packages/pylint/message/message_id_store.py @@ -0,0 +1,128 @@ +# -*- 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 typing import List + +from pylint.exceptions import InvalidMessageError, UnknownMessageError + + +class MessageIdStore: + + """The MessageIdStore store MessageId and make sure that there is a 1-1 relation between msgid and symbol.""" + + def __init__(self): + self.__msgid_to_symbol = {} + self.__symbol_to_msgid = {} + self.__old_names = {} + + def __len__(self): + return len(self.__msgid_to_symbol) + + def __repr__(self): + result = "MessageIdStore: [\n" + for msgid, symbol in self.__msgid_to_symbol.items(): + result += " - {msgid} ({symbol})\n".format(msgid=msgid, symbol=symbol) + result += "]" + return result + + def get_symbol(self, msgid: str) -> str: + return self.__msgid_to_symbol[msgid] + + def get_msgid(self, symbol: str) -> str: + return self.__symbol_to_msgid[symbol] + + def register_message_definition(self, message_definition): + self.check_msgid_and_symbol(message_definition.msgid, message_definition.symbol) + self.add_msgid_and_symbol(message_definition.msgid, message_definition.symbol) + for old_msgid, old_symbol in message_definition.old_names: + self.check_msgid_and_symbol(old_msgid, old_symbol) + self.add_legacy_msgid_and_symbol( + old_msgid, old_symbol, message_definition.msgid + ) + + def add_msgid_and_symbol(self, msgid: str, symbol: str) -> None: + """Add valid message id. + + There is a little duplication with add_legacy_msgid_and_symbol to avoid a function call, + this is called a lot at initialization.""" + self.__msgid_to_symbol[msgid] = symbol + self.__symbol_to_msgid[symbol] = msgid + + def add_legacy_msgid_and_symbol(self, msgid: str, symbol: str, new_msgid: str): + """Add valid legacy message id. + + There is a little duplication with add_msgid_and_symbol to avoid a function call, + this is called a lot at initialization.""" + self.__msgid_to_symbol[msgid] = symbol + self.__symbol_to_msgid[symbol] = msgid + existing_old_names = self.__old_names.get(msgid, []) + existing_old_names.append(new_msgid) + self.__old_names[msgid] = existing_old_names + + def check_msgid_and_symbol(self, msgid: str, symbol: str) -> None: + existing_msgid = self.__symbol_to_msgid.get(symbol) + existing_symbol = self.__msgid_to_symbol.get(msgid) + if existing_symbol is None and existing_msgid is None: + return + if existing_msgid is not None: + if existing_msgid != msgid: + self._raise_duplicate_msgid(symbol, msgid, existing_msgid) + if existing_symbol != symbol: + self._raise_duplicate_symbol(msgid, symbol, existing_symbol) + + @staticmethod + def _raise_duplicate_symbol(msgid, symbol, other_symbol): + """Raise an error when a symbol is duplicated. + + :param str msgid: The msgid corresponding to the symbols + :param str symbol: Offending symbol + :param str other_symbol: Other offending symbol + :raises InvalidMessageError:""" + symbols = [symbol, other_symbol] + symbols.sort() + error_message = "Message id '{msgid}' cannot have both ".format(msgid=msgid) + error_message += "'{other_symbol}' and '{symbol}' as symbolic name.".format( + other_symbol=symbols[0], symbol=symbols[1] + ) + raise InvalidMessageError(error_message) + + @staticmethod + def _raise_duplicate_msgid(symbol, msgid, other_msgid): + """Raise an error when a msgid is duplicated. + + :param str symbol: The symbol corresponding to the msgids + :param str msgid: Offending msgid + :param str other_msgid: Other offending msgid + :raises InvalidMessageError:""" + msgids = [msgid, other_msgid] + msgids.sort() + error_message = ( + "Message symbol '{symbol}' cannot be used for " + "'{other_msgid}' and '{msgid}' at the same time." + " If you're creating an 'old_names' use 'old-{symbol}' as the old symbol." + ).format(symbol=symbol, other_msgid=msgids[0], msgid=msgids[1]) + raise InvalidMessageError(error_message) + + def get_active_msgids(self, msgid_or_symbol: str) -> List[str]: + """Return msgids but the input can be a symbol.""" + # Only msgid can have a digit as second letter + is_msgid = msgid_or_symbol[1:].isdigit() + if is_msgid: + msgid = msgid_or_symbol.upper() + symbol = self.__msgid_to_symbol.get(msgid) + else: + msgid = self.__symbol_to_msgid.get(msgid_or_symbol) + symbol = msgid_or_symbol + if not msgid or not symbol: + error_msg = "No such message id or symbol '{msgid_or_symbol}'.".format( + msgid_or_symbol=msgid_or_symbol + ) + raise UnknownMessageError(error_msg) + # logging.debug( + # "Return for {} and msgid {} is {}".format( + # msgid_or_symbol, msgid, self.__old_names.get(msgid, [msgid]) + # ) + # ) + return self.__old_names.get(msgid, [msgid]) |